No description
Find a file
2025-09-13 10:12:35 -07:00
examples Initial commit: apt-wrapper - Simple APT transaction wrapper 2025-09-13 10:02:01 -07:00
src Initial commit: apt-wrapper - Simple APT transaction wrapper 2025-09-13 10:02:01 -07:00
tests Initial commit: apt-wrapper - Simple APT transaction wrapper 2025-09-13 10:02:01 -07:00
Cargo.toml Initial commit: apt-wrapper - Simple APT transaction wrapper 2025-09-13 10:02:01 -07:00
README.md updated readme with instructions on how to use as a crate 2025-09-13 10:12:35 -07:00

APT Wrapper

A simple DNF-like API wrapper around APT for porting rpm-ostree to apt-ostree.

Purpose

This library provides a simple transaction interface that mimics DNF's imperative model, making it easier to adapt rpm-ostree code for Debian/Ubuntu systems.

Features

  • Simple transaction interface: add_package(), resolve(), commit(), rollback()
  • DNF-like API: Easy to port from rpm-ostree
  • Version-based rollback: Track versions and restore previous states
  • Minimal dependencies: Only anyhow and thiserror
  • ~250 lines total: Focused and maintainable

Quick Start

use apt_wrapper::{AptTransaction, init};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize
    init()?;
    
    // Create transaction
    let mut tx = AptTransaction::new()?;
    
    // Add packages
    tx.add_package("vim")?;
    tx.add_package("git")?;
    
    // Resolve dependencies
    tx.resolve()?;
    
    // Commit transaction
    tx.commit()?;
    
    // If something goes wrong, rollback
    // tx.rollback()?;
    
    Ok(())
}

API

AptTransaction

pub struct AptTransaction {
    packages: Vec<String>,
}

impl AptTransaction {
    pub fn new() -> Result<Self>;           // Create new transaction
    pub fn add_package(&mut self, name: &str) -> Result<()>;  // Add package
    pub fn resolve(&self) -> Result<()>;    // Resolve dependencies
    pub fn commit(&mut self) -> Result<()>; // Commit transaction
    pub fn rollback(&self) -> Result<()>;   // Rollback transaction
    pub fn packages(&self) -> &[String];    // Get package list
    pub fn changed_packages(&self) -> Vec<String>; // Get changed packages
    pub fn is_empty(&self) -> bool;         // Check if empty
}

Utility Functions

pub fn init() -> Result<()>;                                    // Initialize
pub fn search_packages(query: &str) -> Result<Vec<String>>;     // Search packages
pub fn is_package_installed(name: &str) -> Result<bool>;        // Check installed
pub fn get_package_info(name: &str) -> Result<AptPackage>;      // Get package info

Installation

Add to your Cargo.toml:

[dependencies]
apt-wrapper = "0.1.0"

Using as a Crate

Adding to Your Project

  1. Add the dependency to your Cargo.toml:
[dependencies]
apt-wrapper = "0.1.0"
  1. Import the crate in your Rust code:
use apt_wrapper::{AptTransaction, init, search_packages, is_package_installed};
  1. Initialize the library before use:
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Always call init() first
    init()?;
    
    // Now you can use the library
    let mut tx = AptTransaction::new()?;
    // ... rest of your code
}

Crate Features

The crate provides these main components:

  • AptTransaction: Main transaction interface for package operations
  • init(): Initialize the library (required before use)
  • search_packages(): Search for available packages
  • is_package_installed(): Check if a package is installed
  • get_package_info(): Get detailed package information

Error Handling

The crate uses anyhow::Result for error handling. All functions return Result<T, anyhow::Error>:

use anyhow::Result;

fn example() -> Result<()> {
    let mut tx = AptTransaction::new()?;  // Returns Result<AptTransaction, anyhow::Error>
    tx.add_package("vim")?;               // Returns Result<(), anyhow::Error>
    tx.commit()?;                         // Returns Result<(), anyhow::Error>
    Ok(())
}

Complete Example

Here's a complete example of using the crate:

use apt_wrapper::{AptTransaction, init, search_packages, is_package_installed};
use anyhow::Result;

fn main() -> Result<()> {
    // Initialize the library
    init()?;
    
    // Search for packages
    let editors = search_packages("editor")?;
    println!("Available editors: {:?}", editors);
    
    // Check if vim is installed
    if !is_package_installed("vim")? {
        println!("vim is not installed, installing...");
        
        // Create transaction
        let mut tx = AptTransaction::new()?;
        tx.add_package("vim")?;
        tx.add_package("git")?;
        
        // Resolve and commit
        tx.resolve()?;
        tx.commit()?;
        
        println!("Packages installed successfully!");
    } else {
        println!("vim is already installed");
    }
    
    Ok(())
}

Building Your Project

Once you've added the dependency, build your project normally:

cargo build
cargo run

The crate will automatically handle APT integration and provide the DNF-like interface for your application.

Usage

Basic Transaction

use apt_wrapper::AptTransaction;

let mut tx = AptTransaction::new()?;
tx.add_package("vim")?;
tx.add_package("git")?;
tx.resolve()?;
tx.commit()?;

Search Packages

use apt_wrapper::search_packages;

let packages = search_packages("editor")?;
for package in packages {
    println!("Found: {}", package);
}

Check Installation

use apt_wrapper::is_package_installed;

if is_package_installed("vim")? {
    println!("vim is installed");
}

Rollback Support

use apt_wrapper::AptTransaction;

let mut tx = AptTransaction::new()?;
tx.add_package("vim")?;
tx.add_package("git")?;
tx.resolve()?;

// Commit the transaction
tx.commit()?;

// If something goes wrong later, rollback
tx.rollback()?;

// Check what was changed
println!("Changed packages: {:?}", tx.changed_packages());

Testing

cargo test

Examples

cargo run --example simple_usage

Design Philosophy

This wrapper is designed to be:

  1. Simple: Minimal API surface, easy to understand
  2. Focused: Only what's needed for apt-ostree porting
  3. DNF-like: Familiar interface for rpm-ostree developers
  4. Minimal: ~200 lines total, no complex abstractions

Differences from DNF

  • APT is declarative: Dependencies are resolved automatically
  • No complex repo management: APT uses simple text files
  • Simpler error handling: APT provides clear error messages
  • No transaction rollback: APT doesn't have built-in rollback

OSTree Integration

For atomic operations, use OSTree's native checkpoint/rollback:

// 1. Create OSTree checkpoint
let checkpoint = ostree_create_checkpoint()?;

// 2. Run APT transaction
let mut tx = AptTransaction::new()?;
tx.add_package("vim")?;
tx.commit()?;

// 3. Commit or rollback based on result
if success {
    ostree_commit_changes()?;
} else {
    ostree_rollback_to_checkpoint(checkpoint)?;
}

License

MIT License - see LICENSE file for details.

Contributing

This is a focused tool for apt-ostree. Contributions should maintain simplicity and focus on the core use case.