apt-ostree/docs/developer-guide.md
robojerk 3dec23f8f7 Fix YAML linting issues and update system requirements to Debian 13+
- Fix trailing spaces and blank lines in Forgejo workflows
- Update system requirements from Ubuntu Jammy/Bookworm to Debian 13+ (Trixie)
- Update test treefile to use Debian Trixie instead of Ubuntu Jammy
- Update documentation to reflect modern system requirements
- Fix yamllint errors for CI/CD functionality
- Ensure compatibility with modern OSTree and libapt versions
2025-08-18 11:39:58 -07:00

15 KiB

apt-ostree Developer Guide

Table of Contents

  1. Architecture Overview
  2. Development Setup
  3. Code Organization
  4. API Documentation
  5. Development Workflow
  6. Testing and Debugging
  7. Contributing Guidelines

Architecture Overview

System Components

apt-ostree consists of several key components:

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   CLI Client    │    │   System Daemon  │    │   OSTree Repo   │
│  (apt-ostree)   │◄──►│  (apt-ostreed)   │◄──►│   (/ostree/)    │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                       │                       │
         │                       │                       │
         ▼                       ▼                       ▼
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   APT System   │    │   D-Bus Layer    │    │  File System    │
│  (Package Mgmt)│    │  (IPC Interface) │    │   (Deployments) │
└─────────────────┘    └──────────────────┘    └─────────────────┘

Component Responsibilities

CLI Client (apt-ostree)

  • Command parsing: Uses clap for argument parsing
  • User interface: Provides user-friendly command interface
  • Command dispatch: Routes commands to appropriate handlers
  • Output formatting: Formats results for user consumption

System Daemon (apt-ostreed)

  • Background processing: Handles long-running operations
  • D-Bus interface: Provides IPC for system operations
  • Transaction management: Manages atomic system changes
  • Security: Implements Polkit authentication

OSTree Integration

  • Repository management: Manages OSTree repositories
  • Deployment handling: Handles system deployments
  • Atomic operations: Ensures system consistency
  • Rollback support: Provides system recovery

APT Integration

  • Package resolution: Resolves package dependencies
  • Repository management: Manages APT repositories
  • Transaction handling: Handles package transactions
  • Conflict resolution: Resolves package conflicts

Development Setup

Prerequisites

  • Rust toolchain: Rust 1.75+ with Cargo
  • System dependencies: See installation guide
  • Development tools: Git, make, pkg-config
  • Documentation tools: rustdoc, cargo-doc

Environment Setup

# Clone repository
git clone https://github.com/robojerk/apt-ostree.git
cd apt-ostree

# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Install system dependencies
sudo apt-get install build-essential pkg-config \
    libostree-dev libapt-pkg-dev libpolkit-gobject-1-dev \
    libdbus-1-dev libsystemd-dev

# Install development tools
cargo install cargo-outdated cargo-audit cargo-tarpaulin

Build Configuration

# Development build with all features
cargo build --features development,dev-full

# Release build
cargo build --release

# Documentation
cargo doc --open --features development

# Run tests
cargo test --features development

Code Organization

Directory Structure

src/
├── main.rs              # CLI entry point
├── cli.rs               # Command-line interface definitions
├── commands/            # Command implementations
│   ├── mod.rs          # Command registry
│   ├── package.rs      # Package management commands
│   ├── system.rs       # System management commands
│   ├── testutils.rs    # Development utilities
│   ├── shlib_backend.rs # Shared library backend
│   └── internals.rs    # Internal diagnostics
├── lib/                 # Core library code
│   ├── mod.rs          # Library entry point
│   ├── apt.rs          # APT integration
│   ├── ostree.rs       # OSTree integration
│   ├── security.rs     # Security and authentication
│   ├── system.rs       # System operations
│   ├── transaction.rs  # Transaction management
│   └── logging.rs      # Logging and metrics
├── daemon/              # Daemon implementation
│   ├── main.rs         # Daemon entry point
│   ├── dbus.rs         # D-Bus interface
│   ├── polkit.rs       # Polkit integration
│   └── systemd.rs      # systemd integration
└── tests/               # Test suite
    ├── integration_tests.rs
    └── common/

Key Modules

Command System

The command system uses a trait-based approach for extensibility:

pub trait Command {
    fn execute(&self, args: &[String]) -> Result<(), Box<dyn std::error::Error>>;
    fn help(&self) -> String;
    fn usage(&self) -> String;
}

pub struct CommandRegistry {
    commands: HashMap<String, Box<dyn Command>>,
}

Library Interface

The library provides a clean API for external consumers:

pub struct AptOstree {
    apt_manager: AptManager,
    ostree_manager: OstreeManager,
    security_manager: SecurityManager,
}

impl AptOstree {
    pub fn new() -> Result<Self, Error> { /* ... */ }
    pub fn install_packages(&self, packages: &[String]) -> Result<(), Error> { /* ... */ }
    pub fn remove_packages(&self, packages: &[String]) -> Result<(), Error> { /* ... */ }
}

API Documentation

Core Types

Package Management

pub struct Package {
    pub name: String,
    pub version: String,
    pub architecture: String,
    pub dependencies: Vec<String>,
    pub conflicts: Vec<String>,
}

pub struct PackageTransaction {
    pub packages: Vec<Package>,
    pub operation: TransactionOperation,
    pub status: TransactionStatus,
}

OSTree Integration

pub struct Deployment {
    pub id: String,
    pub branch: String,
    pub commit: String,
    pub timestamp: DateTime<Utc>,
    pub packages: Vec<String>,
}

pub struct OSTreeRepository {
    pub path: PathBuf,
    pub mode: RepositoryMode,
    pub remotes: HashMap<String, Remote>,
}

Security

pub struct SecurityContext {
    pub user: String,
    pub groups: Vec<String>,
    pub permissions: Permissions,
}

pub struct AuthenticationResult {
    pub authenticated: bool,
    pub user: Option<String>,
    pub permissions: Permissions,
}

Public API

High-Level Operations

impl AptOstree {
    /// Install packages atomically
    pub fn install_packages(&self, packages: &[String]) -> Result<(), Error>
    
    /// Remove packages atomically
    pub fn remove_packages(&self, packages: &[String]) -> Result<(), Error>
    
    /// Upgrade all packages
    pub fn upgrade_system(&self) -> Result<(), Error>
    
    /// Rollback to previous deployment
    pub fn rollback(&self) -> Result<(), Error>
}

Transaction Management

impl TransactionManager {
    /// Start a new transaction
    pub fn start_transaction(&mut self, operation: TransactionOperation) -> Result<TransactionId, Error>
    
    /// Add packages to transaction
    pub fn add_packages(&mut self, transaction_id: TransactionId, packages: &[String]) -> Result<(), Error>
    
    /// Commit transaction
    pub fn commit_transaction(&mut self, transaction_id: TransactionId) -> Result<(), Error>
    
    /// Rollback transaction
    pub fn rollback_transaction(&mut self, transaction_id: TransactionId) -> Result<(), Error>
}

System Operations

impl SystemManager {
    /// Get system status
    pub fn get_system_status(&self) -> SystemStatus
    
    /// Manage kernel arguments
    pub fn set_kernel_args(&self, args: &[String]) -> Result<(), Error>
    
    /// Regenerate initramfs
    pub fn regenerate_initramfs(&self) -> Result<(), Error>
}

Development Workflow

Adding New Commands

1. Define Command Structure

// src/cli.rs
#[derive(Subcommand)]
pub enum Commands {
    // ... existing commands ...
    NewCommand(NewCommandArgs),
}

#[derive(Args)]
pub struct NewCommandArgs {
    #[arg(long)]
    option: Option<String>,
    
    #[arg(value_name = "TARGET")]
    target: String,
}

2. Implement Command Logic

// src/commands/new_command.rs
pub struct NewCommand;

impl Command for NewCommand {
    fn execute(&self, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
        // Implementation here
        Ok(())
    }
    
    fn help(&self) -> String {
        "Help text for new command".to_string()
    }
    
    fn usage(&self) -> String {
        "new-command [OPTIONS] TARGET".to_string()
    }
}

3. Register Command

// src/commands/mod.rs
pub mod new_command;

// In CommandRegistry::new()
self.commands.insert("new-command".to_string(), Box::new(NewCommand));

4. Add to Main Dispatch

// src/main.rs
match cli.command {
    Commands::NewCommand(args) => {
        // Handle new command
    }
}

Adding New Features

1. Library Implementation

// src/lib/new_feature.rs
pub struct NewFeature {
    // Feature implementation
}

impl NewFeature {
    pub fn new() -> Self {
        // Constructor
    }
    
    pub fn execute(&self) -> Result<(), Error> {
        // Feature logic
    }
}

2. Integration

// src/lib/mod.rs
pub mod new_feature;

// In main library struct
pub struct AptOstree {
    // ... existing fields ...
    new_feature: NewFeature,
}

3. Testing

// tests/new_feature_tests.rs
#[test]
fn test_new_feature() {
    let feature = NewFeature::new();
    assert!(feature.execute().is_ok());
}

Testing and Debugging

Unit Testing

# Run all tests
cargo test

# Run specific test module
cargo test commands::package

# Run tests with output
cargo test -- --nocapture

# Run tests with specific feature
cargo test --features development

Integration Testing

# Run integration tests
cargo test --test integration_tests

# Run specific integration test
cargo test --test integration_tests test_package_installation

Development Commands

# Run diagnostics
cargo run --features development -- internals diagnostics

# Validate system state
cargo run --features development -- internals validate-state

# Dump debug information
cargo run --features development -- internals debug-dump

Debugging Tools

Logging

use tracing::{info, warn, error, debug};

// Set log level
std::env::set_var("RUST_LOG", "debug");

// Use in code
debug!("Debug information");
info!("Information message");
warn!("Warning message");
error!("Error message");

Profiling

# Install profiling tools
cargo install flamegraph

# Generate flamegraph
cargo flamegraph --bin apt-ostree -- install nginx

# Memory profiling
cargo install cargo-valgrind
cargo valgrind test

Code Quality Tools

Clippy

# Run Clippy
cargo clippy

# Run with specific rules
cargo clippy -- -D warnings -A clippy::too_many_arguments

Formatting

# Check formatting
cargo fmt -- --check

# Format code
cargo fmt

Security Audit

# Check for vulnerabilities
cargo audit

# Update dependencies
cargo update

Contributing Guidelines

Code Style

  • Rust conventions: Follow Rust style guide and idioms
  • Documentation: Document all public APIs with doc comments
  • Error handling: Use proper error types and Result handling
  • Testing: Include tests for new functionality
  • Logging: Use appropriate log levels for debugging

Pull Request Process

  1. Fork repository: Create your own fork
  2. Create feature branch: git checkout -b feature/new-feature
  3. Implement changes: Follow coding guidelines
  4. Add tests: Include unit and integration tests
  5. Update documentation: Update relevant documentation
  6. Submit PR: Create pull request with clear description

Commit Guidelines

type(scope): description

[optional body]

[optional footer]

Types: feat, fix, docs, style, refactor, test, chore Scope: cli, daemon, lib, commands, etc.

Review Process

  • Code review: All changes require review
  • Testing: Ensure all tests pass
  • Documentation: Verify documentation is updated
  • Integration: Test integration with existing features

Issue Reporting

When reporting issues, include:

  • Environment: OS, version, dependencies
  • Steps to reproduce: Clear reproduction steps
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Logs: Relevant error logs and output

Advanced Development

Custom Builds

# Build with specific features
cargo build --features development,dev-full

# Build for specific target
cargo build --target x86_64-unknown-linux-gnu

# Cross-compilation
cargo build --target aarch64-unknown-linux-gnu

Performance Optimization

// Use appropriate data structures
use std::collections::HashMap; // O(1) lookup
use std::collections::BTreeMap; // Ordered, O(log n) lookup

// Avoid unnecessary allocations
let result = if condition { "value" } else { "default" };
// Instead of
let result = if condition { "value".to_string() } else { "default".to_string() };

// Use iterators efficiently
let sum: u64 = items.iter().map(|x| x.value).sum();

Memory Management

// Use Arc for shared ownership
use std::sync::Arc;

let shared_data = Arc::new(SharedData::new());
let clone1 = Arc::clone(&shared_data);
let clone2 = Arc::clone(&shared_data);

// Use Box for trait objects
let commands: Vec<Box<dyn Command>> = vec![
    Box::new(PackageCommand),
    Box::new(SystemCommand),
];

Async Programming

use tokio::runtime::Runtime;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let result = async_operation().await?;
    Ok(())
}

async fn async_operation() -> Result<String, Error> {
    // Async implementation
    Ok("result".to_string())
}

Troubleshooting Development Issues

Common Problems

Build Failures

# Clean and rebuild
cargo clean
cargo build

# Check Rust version
rustc --version
cargo --version

# Update Rust toolchain
rustup update

Dependency Issues

# Check dependency tree
cargo tree

# Update dependencies
cargo update

# Check for conflicts
cargo check

Test Failures

# Run specific failing test
cargo test test_name -- --nocapture

# Check test environment
cargo test --features development

# Debug test setup
RUST_LOG=debug cargo test

Getting Help

  • Documentation: Check inline documentation and rustdoc
  • Issues: Search existing GitHub issues
  • Discussions: Use GitHub Discussions for questions
  • Community: Join project community channels

This guide covers development aspects of apt-ostree. For user documentation, refer to the User Guide.