# apt-ostree Developer Guide ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Development Setup](#development-setup) 3. [Code Organization](#code-organization) 4. [API Documentation](#api-documentation) 5. [Development Workflow](#development-workflow) 6. [Testing and Debugging](#testing-and-debugging) 7. [Contributing Guidelines](#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 ```bash # 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 ```bash # 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: ```rust pub trait Command { fn execute(&self, args: &[String]) -> Result<(), Box>; fn help(&self) -> String; fn usage(&self) -> String; } pub struct CommandRegistry { commands: HashMap>, } ``` #### Library Interface The library provides a clean API for external consumers: ```rust pub struct AptOstree { apt_manager: AptManager, ostree_manager: OstreeManager, security_manager: SecurityManager, } impl AptOstree { pub fn new() -> Result { /* ... */ } pub fn install_packages(&self, packages: &[String]) -> Result<(), Error> { /* ... */ } pub fn remove_packages(&self, packages: &[String]) -> Result<(), Error> { /* ... */ } } ``` ## API Documentation ### Core Types #### Package Management ```rust pub struct Package { pub name: String, pub version: String, pub architecture: String, pub dependencies: Vec, pub conflicts: Vec, } pub struct PackageTransaction { pub packages: Vec, pub operation: TransactionOperation, pub status: TransactionStatus, } ``` #### OSTree Integration ```rust pub struct Deployment { pub id: String, pub branch: String, pub commit: String, pub timestamp: DateTime, pub packages: Vec, } pub struct OSTreeRepository { pub path: PathBuf, pub mode: RepositoryMode, pub remotes: HashMap, } ``` #### Security ```rust pub struct SecurityContext { pub user: String, pub groups: Vec, pub permissions: Permissions, } pub struct AuthenticationResult { pub authenticated: bool, pub user: Option, pub permissions: Permissions, } ``` ### Public API #### High-Level Operations ```rust 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 ```rust impl TransactionManager { /// Start a new transaction pub fn start_transaction(&mut self, operation: TransactionOperation) -> Result /// 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 ```rust 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 ```rust // src/cli.rs #[derive(Subcommand)] pub enum Commands { // ... existing commands ... NewCommand(NewCommandArgs), } #[derive(Args)] pub struct NewCommandArgs { #[arg(long)] option: Option, #[arg(value_name = "TARGET")] target: String, } ``` #### 2. Implement Command Logic ```rust // src/commands/new_command.rs pub struct NewCommand; impl Command for NewCommand { fn execute(&self, args: &[String]) -> Result<(), Box> { // 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 ```rust // 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 ```rust // src/main.rs match cli.command { Commands::NewCommand(args) => { // Handle new command } } ``` ### Adding New Features #### 1. Library Implementation ```rust // 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 ```rust // src/lib/mod.rs pub mod new_feature; // In main library struct pub struct AptOstree { // ... existing fields ... new_feature: NewFeature, } ``` #### 3. Testing ```rust // tests/new_feature_tests.rs #[test] fn test_new_feature() { let feature = NewFeature::new(); assert!(feature.execute().is_ok()); } ``` ## Testing and Debugging ### Unit Testing ```bash # 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 ```bash # Run integration tests cargo test --test integration_tests # Run specific integration test cargo test --test integration_tests test_package_installation ``` ### Development Commands ```bash # 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 ```rust 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 ```bash # 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 ```bash # Run Clippy cargo clippy # Run with specific rules cargo clippy -- -D warnings -A clippy::too_many_arguments ``` #### Formatting ```bash # Check formatting cargo fmt -- --check # Format code cargo fmt ``` #### Security Audit ```bash # 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 ```bash # 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 ```rust // 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 ```rust // 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> = vec![ Box::new(PackageCommand), Box::new(SystemCommand), ]; ``` ### Async Programming ```rust use tokio::runtime::Runtime; #[tokio::main] async fn main() -> Result<(), Box> { let result = async_operation().await?; Ok(()) } async fn async_operation() -> Result { // Async implementation Ok("result".to_string()) } ``` ## Troubleshooting Development Issues ### Common Problems #### Build Failures ```bash # Clean and rebuild cargo clean cargo build # Check Rust version rustc --version cargo --version # Update Rust toolchain rustup update ``` #### Dependency Issues ```bash # Check dependency tree cargo tree # Update dependencies cargo update # Check for conflicts cargo check ``` #### Test Failures ```bash # 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.*