- Implement two-phase rollback system inspired by apt-tx project - Add package state tracking (newly_installed, upgraded, previously_installed) - Enhance both core and advanced transaction APIs with rollback methods - Add comprehensive rollback documentation in docs/rollback.md - Create rollback_demo.rs example demonstrating functionality - Update README with detailed crate usage instructions - Add rollback features to feature flags documentation - Fix import issues in advanced crate modules - Add get_installed_packages method to AptCommands - Include both crates.io and git installation options in README
13 KiB
APT-DNF Bridge
A DNF-like bridge around APT for apt-ostree integration. This workspace provides a transaction-based API that makes APT work like DNF, complete with sophisticated rollback functionality.
✨ Key Features
- 🔄 Advanced Rollback: Two-phase rollback system that tracks and undoes package changes
- 📦 Transaction Model: DNF-like imperative transactions with resolve and commit phases
- 🔧 Pluggable Backends: Shell, mock, and libapt backends for different use cases
- ⚡ Feature Flags: Choose between minimal core or full advanced functionality
- 🛡️ Error Handling: Comprehensive error handling with clear messages
- 📚 Complete Documentation: Detailed guides and working examples
🎯 Two-Crate Approach
This workspace implements the refined two-crate approach with feature flags:
apt-dnf-bridge-core- Minimal shell-out implementationapt-dnf-bridge- Main crate that re-exports core + optional advanced featuresapt-dnf-bridge-advanced- Pluggable backends, caching, and enhanced features
🚀 Quick Start
Core (Minimal)
[dependencies]
apt-dnf-bridge = "0.1"
Advanced Features
[dependencies]
apt-dnf-bridge = { version = "0.1", features = ["advanced"] }
📁 Workspace Structure
apt-dnf-bridge-workspace/
├── Cargo.toml # Workspace root
├── apt-dnf-bridge-core/ # Minimal implementation
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── command.rs
│ ├── error.rs
│ ├── package.rs
│ ├── repository.rs
│ └── transaction.rs
├── apt-dnf-bridge/ # Main public crate
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── apt-dnf-bridge-advanced/ # Advanced features
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── backend.rs
│ ├── package_v2.rs
│ ├── transaction_v2.rs
│ └── backend/
│ ├── shell_backend.rs
│ ├── mock_backend.rs
│ └── libapt_backend.rs
└── examples/ # Shared examples
├── basic_usage.rs
├── package_query.rs
├── atomicity_notes.rs
├── backend_selection.rs
└── rollback_demo.rs
🔧 Usage Examples
Basic Usage (Core Only)
use apt_dnf_bridge::{Transaction, Package, Repository};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a transaction
let mut tx = Transaction::new();
// Add packages to install
let vim = Package::new("vim", "2:8.1.2269-1ubuntu5.14", "amd64");
tx.add_install(vim).await?;
// Resolve dependencies (APT handles automatically)
tx.resolve().await?;
// Commit the transaction
tx.commit().await?;
Ok(())
}
Advanced Usage (With Backends)
use apt_dnf_bridge::{TransactionV2, PackageDatabaseV2, BackendFactory};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create transaction with auto-detected backend
let mut tx = TransactionV2::new().await?;
// Add packages
let vim = Package::new("vim", "2:8.1.2269-1ubuntu5.14", "amd64");
tx.add_install(vim).await?;
// Resolve and commit
tx.resolve().await?;
tx.commit().await?;
Ok(())
}
Rollback Functionality
use apt_dnf_bridge::{Transaction, Package};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut tx = Transaction::new();
// Add packages
tx.add_install(Package::new("vim", "", "")).await?;
tx.add_install(Package::new("curl", "", "")).await?;
// Commit transaction
tx.resolve().await?;
tx.commit().await?;
// Later, rollback if needed
if tx.can_rollback() {
println!("Rolling back {} newly installed packages", tx.newly_installed().len());
tx.rollback().await?;
}
Ok(())
}
🏗️ Building and Testing
Build All Crates
cargo build
Test Core Features
cargo test -p apt-dnf-bridge-core
Test Advanced Features
cargo test -p apt-dnf-bridge-advanced
Run Examples
# Core examples
cargo run --example basic_usage
cargo run --example package_query
# Advanced examples (requires advanced feature)
cargo run --example backend_selection --features advanced
cargo run --example rollback_demo --features advanced
🎯 Feature Flags
Core Features (Default)
- Shell-out APT commands
- Basic transaction model
- Package querying
- Repository management
- 🔄 Rollback functionality (two-phase rollback)
- Error handling
Advanced Features (advanced feature)
- Pluggable backends (shell, mock, libapt)
- Caching system
- Enhanced error handling
- Backend statistics
- Mock backend for testing
- 🔄 Advanced rollback (backend-integrated)
📦 Using as a Crate
Installation
Add to your Cargo.toml:
[dependencies]
apt-dnf-bridge = "0.1"
For advanced features:
[dependencies]
apt-dnf-bridge = { version = "0.1", features = ["advanced"] }
Or using git directly:
[dependencies]
apt-dnf-bridge = { git = "https://git.raines.xyz/particle-os/apt-dnf-bridge-workspace.git", features = ["advanced"] }
Basic Usage
1. Core API (Minimal)
use apt_dnf_bridge::{Transaction, Package, Repository};
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Create a transaction
let mut tx = Transaction::new();
// Add packages to install
let vim = Package::new("vim", "2:8.1.2269-1ubuntu5.14", "amd64");
tx.add_install(vim).await?;
// Resolve dependencies
tx.resolve().await?;
// Commit the transaction
tx.commit().await?;
// Check what was installed
println!("Newly installed: {:?}", tx.newly_installed());
// Rollback if needed
if tx.can_rollback() {
tx.rollback().await?;
}
Ok(())
}
2. Advanced API (With Backends)
use apt_dnf_bridge::{TransactionV2, PackageDatabaseV2, BackendConfig};
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Create transaction with specific backend
let config = BackendConfig::default();
let mut tx = TransactionV2::with_shell_backend(config).await?;
// Add packages
let git = Package::new("git", "1:2.25.1-1ubuntu3.11", "amd64");
tx.add_install(git).await?;
// Resolve and commit
tx.resolve().await?;
tx.commit().await?;
// Advanced rollback with backend
if tx.can_rollback() {
println!("Changed packages: {:?}", tx.changed_packages());
tx.rollback().await?;
}
Ok(())
}
3. Package Querying
use apt_dnf_bridge::{PackageDatabase, Package};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut db = PackageDatabase::new();
// Search for packages
let packages = db.find_packages("editor").await?;
for package in packages {
println!("Found: {} - {}", package.name, package.version);
}
// Get specific package info
if let Some(package) = db.get_package_info("vim").await? {
println!("Package: {} v{}", package.name, package.version);
}
Ok(())
}
4. Repository Management
use apt_dnf_bridge::{Repository, PackageDatabase};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Add a repository
let mut repo = Repository::new("myrepo", "https://example.com/debian");
repo.add_component("main");
repo.add_component("contrib");
repo.save_to_sources_list_d("myrepo.list")?;
// Update package cache
let mut db = PackageDatabase::new();
db.update_cache().await?;
Ok(())
}
Error Handling
The crate uses anyhow::Result for error handling:
use anyhow::Result;
async fn example() -> Result<()> {
let mut tx = Transaction::new();
// All operations return Result<T, anyhow::Error>
tx.add_install(Package::new("vim", "", "")).await?;
tx.resolve().await?;
tx.commit().await?;
Ok(())
}
Rollback System
The rollback system tracks package changes and provides two-phase rollback:
use apt_dnf_bridge::{Transaction, Package};
async fn rollback_example() -> Result<(), Box<dyn std::error::Error>> {
let mut tx = Transaction::new();
// Add packages
tx.add_install(Package::new("vim", "", "")).await?;
tx.add_install(Package::new("curl", "", "")).await?;
// Commit
tx.resolve().await?;
tx.commit().await?;
// Check rollback information
println!("Previously installed: {} packages", tx.previously_installed().len());
println!("Newly installed: {} packages", tx.newly_installed().len());
println!("Upgraded: {} packages", tx.upgraded().len());
// Rollback if needed
if tx.can_rollback() {
println!("Rolling back changes...");
tx.rollback().await?;
println!("Rollback completed");
}
Ok(())
}
Feature Flags
Core Only (Default)
[dependencies]
apt-dnf-bridge = "0.1"
With Advanced Features
[dependencies]
apt-dnf-bridge = { version = "0.1", features = ["advanced"] }
Available Examples
# Run examples
cargo run --example basic_usage
cargo run --example package_query
cargo run --example rollback_demo --features advanced
cargo run --example backend_selection --features advanced
🔄 Migration Guide
From Single Crate to Workspace
- Core users: No changes needed - same API
- Advanced users: Add
features = ["advanced"]to Cargo.toml - New users: Start with core, add advanced when needed
API Compatibility
- Core API remains unchanged
- Advanced API available via feature flag
- Gradual adoption path supported
🔄 Rollback System
The APT-DNF Bridge includes a sophisticated two-phase rollback system inspired by the apt-tx project:
How It Works
- Package Tracking: Tracks
previously_installed,newly_installed, andupgradedpackages - Two-Phase Rollback:
- Phase 1: Remove newly installed packages using
apt remove -y - Phase 2: Downgrade upgraded packages using
apt install -y package=oldversion
- Phase 1: Remove newly installed packages using
Rollback API
// Check if rollback is possible
if tx.can_rollback() {
// Get rollback information
println!("Newly installed: {:?}", tx.newly_installed());
println!("Upgraded: {:?}", tx.upgraded());
// Perform rollback
tx.rollback().await?;
}
Limitations
- ✅ New package installations
- ✅ Package upgrades with available previous versions
- ❌ Complex dependency changes
- ❌ Configuration file modifications
- ❌ Concurrent package operations
For critical systems, consider using OSTree's native checkpoint/rollback functionality.
📚 Documentation
- Core API: Focus on simplicity and reliability
- Advanced API: Focus on power and flexibility
- Rollback Guide: Detailed rollback implementation (
docs/rollback.md) - Examples: Demonstrate both core and advanced usage
- Migration: Guide for moving between feature levels
🚀 Benefits of This Approach
- Single Crate - No confusion about which to use
- Feature Flags - Users choose complexity level
- Workspace - Easy version coordination
- Re-exports - Clean API surface
- Gradual Adoption - Start simple, add complexity when needed
- Clear Documentation - One README with feature explanations
- 🔄 Advanced Rollback - Production-ready rollback functionality
- 🔧 Pluggable Backends - Flexible backend architecture
This approach gives us all the benefits of the two-crate strategy with much better UX and maintenance.
📊 Project Status
- ✅ Core Functionality: Complete and tested
- ✅ Rollback System: Implemented with two-phase approach
- ✅ Advanced Features: Pluggable backends and caching
- ✅ Documentation: Comprehensive guides and examples
- ✅ Examples: Working demonstrations of all features
- 🔄 Testing: Unit tests and integration tests
- 📦 Publishing: Ready for crates.io publication
🤝 Contributing
This project is designed for apt-ostree integration. Contributions should maintain simplicity and focus on the core use case while following the established patterns.
📄 License
MIT License - see LICENSE file for details.