apt-dnf-bridge-workspace/README.md
robojerk 88d57cd3a1 Add enhanced rollback functionality and comprehensive documentation
- 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
2025-09-13 21:02:29 -07:00

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 implementation
  • apt-dnf-bridge - Main crate that re-exports core + optional advanced features
  • apt-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

  1. Core users: No changes needed - same API
  2. Advanced users: Add features = ["advanced"] to Cargo.toml
  3. 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

  1. Package Tracking: Tracks previously_installed, newly_installed, and upgraded packages
  2. Two-Phase Rollback:
    • Phase 1: Remove newly installed packages using apt remove -y
    • Phase 2: Downgrade upgraded packages using apt install -y package=oldversion

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

  1. Single Crate - No confusion about which to use
  2. Feature Flags - Users choose complexity level
  3. Workspace - Easy version coordination
  4. Re-exports - Clean API surface
  5. Gradual Adoption - Start simple, add complexity when needed
  6. Clear Documentation - One README with feature explanations
  7. 🔄 Advanced Rollback - Production-ready rollback functionality
  8. 🔧 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.