apt-ostree/src/commands/compose/package_manager.rs
robojerk 791774eb66 Major cleanup and optimization: Remove unused dependencies, clean build artifacts, and improve project structure
- Remove 7 unused dependencies: apt-pkg-native, pkg-config, walkdir, lazy_static, futures, async-trait, cap-std
- Delete dead code: Remove unused parallel.rs module
- Clean build artifacts: Remove debian/cargo/, debian/.debhelper/, and other build files
- Update .gitignore: Comprehensive patterns for build artifacts, test files, and temporary files
- Move documentation: Relocate project docs to docs/ directory
- Remove test artifacts: Clean up test files and package archives
- Update Cargo.toml: Streamline dependencies and remove unused features
- Verify build: Ensure project still compiles after cleanup

This commit significantly reduces project size and improves build efficiency.
2025-08-19 10:51:37 -07:00

240 lines
8.9 KiB
Rust

//! Package manager integration for apt-ostree compose
use std::path::PathBuf;
use std::process::Command;
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
use super::treefile::Repository;
/// Package manager for APT operations
pub struct PackageManager {
build_root: PathBuf,
apt_config_dir: PathBuf,
sources_list_path: PathBuf,
preferences_path: PathBuf,
}
impl PackageManager {
/// Create a new package manager instance
pub fn new(_options: &crate::commands::compose::ComposeOptions) -> AptOstreeResult<Self> {
let build_root = PathBuf::from("/tmp/apt-ostree-build");
let apt_config_dir = build_root.join("etc/apt");
let sources_list_path = apt_config_dir.join("sources.list");
let preferences_path = apt_config_dir.join("preferences");
Ok(Self {
build_root,
apt_config_dir,
sources_list_path,
preferences_path,
})
}
/// Set up package sources from treefile repositories
pub async fn setup_package_sources(&self, repositories: &[Repository]) -> AptOstreeResult<()> {
println!("Setting up package sources...");
// Ensure APT config directory exists
std::fs::create_dir_all(&self.apt_config_dir)
.map_err(|e| AptOstreeError::System(format!("Failed to create APT config directory: {}", e)))?;
// Write sources.list
let mut sources_content = String::new();
for repo in repositories {
sources_content.push_str(&format!("{}\n", repo.url));
}
std::fs::write(&self.sources_list_path, sources_content)
.map_err(|e| AptOstreeError::System(format!("Failed to write sources.list: {}", e)))?;
// Create preferences file for package pinning if needed
let preferences_content = "# Package preferences for apt-ostree compose\n";
std::fs::write(&self.preferences_path, preferences_content)
.map_err(|e| AptOstreeError::System(format!("Failed to write preferences: {}", e)))?;
println!("✅ Package sources configured successfully");
Ok(())
}
/// Update package cache
pub async fn update_cache(&self) -> AptOstreeResult<()> {
println!("Updating package cache...");
// Use chroot to run apt-get update in the build environment
let output = Command::new("chroot")
.arg(&self.build_root)
.arg("apt-get")
.arg("update")
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to run apt-get update: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AptOstreeError::System(format!("apt-get update failed: {}", stderr)));
}
println!("✅ Package cache updated successfully");
Ok(())
}
/// Install a package using APT
pub async fn install_package(&self, package: &str) -> AptOstreeResult<()> {
println!("Installing package: {}", package);
// Use chroot to run apt-get install in the build environment
let output = Command::new("chroot")
.arg(&self.build_root)
.arg("apt-get")
.arg("install")
.arg("-y") // Non-interactive
.arg("--no-install-recommends") // Don't install recommended packages
.arg(package)
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to run apt-get install: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AptOstreeError::System(format!("apt-get install {} failed: {}", package, stderr)));
}
println!("✅ Package {} installed successfully", package);
Ok(())
}
/// Resolve package dependencies
pub async fn resolve_dependencies(&self, packages: &[String]) -> AptOstreeResult<Vec<String>> {
println!("Resolving package dependencies...");
let mut all_packages = Vec::new();
for package in packages {
// Use apt-cache to get dependencies
let output = Command::new("chroot")
.arg(&self.build_root)
.arg("apt-cache")
.arg("depends")
.arg(package)
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to get dependencies for {}: {}", package, e)))?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.starts_with(" ") && !line.contains("PreDepends:") {
let dep = line.trim();
if !all_packages.contains(&dep.to_string()) {
all_packages.push(dep.to_string());
}
}
}
}
}
// Add original packages
for package in packages {
if !all_packages.contains(package) {
all_packages.push(package.clone());
}
}
println!("✅ Resolved {} packages (including dependencies)", all_packages.len());
Ok(all_packages)
}
/// Run post-installation scripts
pub async fn run_post_install_scripts(&self) -> AptOstreeResult<()> {
println!("Running post-installation scripts...");
// Run dpkg configure -a to configure all packages
let output = Command::new("chroot")
.arg(&self.build_root)
.arg("dpkg")
.arg("--configure")
.arg("-a")
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to run dpkg configure: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
println!("Warning: dpkg configure had issues: {}", stderr);
}
println!("✅ Post-installation scripts completed");
Ok(())
}
/// Update package database
pub async fn update_package_database(&self) -> AptOstreeResult<()> {
println!("Updating package database...");
// Update package lists
self.update_cache().await?;
// Clean up any broken packages
let output = Command::new("chroot")
.arg(&self.build_root)
.arg("apt-get")
.arg("check")
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to run apt-get check: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
println!("Warning: apt-get check had issues: {}", stderr);
}
println!("✅ Package database updated successfully");
Ok(())
}
/// Initialize base system using debootstrap
pub async fn initialize_base_system(&self, base_image: &str) -> AptOstreeResult<()> {
println!("Initializing base system using debootstrap...");
// Extract Debian release from base image (e.g., "debian:trixie" -> "trixie")
let release = if base_image.contains(':') {
base_image.split(':').nth(1).unwrap_or("trixie")
} else {
base_image
};
// Use debootstrap to create base system
let output = Command::new("debootstrap")
.arg("--variant=minbase")
.arg("--include=apt,dpkg")
.arg(release)
.arg(&self.build_root)
.arg("http://deb.debian.org/debian")
.output()
.map_err(|e| AptOstreeError::System(format!("Failed to run debootstrap: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AptOstreeError::System(format!("debootstrap failed: {}", stderr)));
}
println!("✅ Base system initialized successfully");
Ok(())
}
/// Clean up package manager state
pub async fn cleanup(&self) -> AptOstreeResult<()> {
println!("Cleaning up package manager state...");
// Remove APT cache to reduce image size
let cache_dir = self.build_root.join("var/cache/apt");
if cache_dir.exists() {
std::fs::remove_dir_all(&cache_dir)
.map_err(|e| AptOstreeError::System(format!("Failed to remove APT cache: {}", e)))?;
}
// Remove APT lists
let lists_dir = self.build_root.join("var/lib/apt/lists");
if lists_dir.exists() {
std::fs::remove_dir_all(&lists_dir)
.map_err(|e| AptOstreeError::System(format!("Failed to remove APT lists: {}", e)))?;
}
println!("✅ Package manager cleanup completed");
Ok(())
}
}