diff --git a/src/compose.rs b/src/compose.rs index d37e2460..f15fbf6e 100644 --- a/src/compose.rs +++ b/src/compose.rs @@ -223,19 +223,124 @@ impl ComposeManager { async fn install_packages_in_staging(&self, staging_path: &std::path::Path, packages: &[String]) -> AptOstreeResult<()> { info!("Installing packages in staging directory: {:?}", packages); - // For now, we'll use a simplified approach - // TODO: Implement proper APT package installation in staging directory + if packages.is_empty() { + return Ok(()); + } - // Create a temporary package installation directory + // Create package installation directory let package_dir = staging_path.join("var/lib/apt-ostree/packages"); std::fs::create_dir_all(&package_dir)?; - // Create a package list file + // Initialize APT manager for package operations + let apt_manager = crate::apt::AptManager::new()?; + + // Download and install each package + for package_name in packages { + info!("Installing package: {}", package_name); + + // Get package metadata + let package_info = apt_manager.get_package_info(package_name).await?; + info!("Got package info: {} version {}", package_name, package_info.version); + + // Download the package + let deb_path = apt_manager.download_package(package_name).await?; + info!("Downloaded package to: {:?}", deb_path); + + // Create package metadata file + let package_meta_path = package_dir.join(format!("{}.json", package_name)); + let package_metadata = serde_json::json!({ + "name": package_name, + "version": package_info.version, + "architecture": package_info.architecture, + "description": package_info.description, + "dependencies": package_info.depends, + "install_timestamp": chrono::Utc::now().timestamp() + }); + std::fs::write(&package_meta_path, serde_json::to_string_pretty(&package_metadata)?)?; + + // Extract package contents to staging directory + self.extract_package_to_staging(&deb_path, staging_path).await?; + } + + // Create package list file let package_list_path = package_dir.join("installed-packages.txt"); let package_list = packages.join("\n"); std::fs::write(&package_list_path, package_list)?; - info!("Package installation placeholder completed"); + info!("Package installation completed for {} packages", packages.len()); + Ok(()) + } + + /// Extract package contents to staging directory + async fn extract_package_to_staging(&self, deb_path: &std::path::Path, staging_path: &std::path::Path) -> AptOstreeResult<()> { + info!("Extracting package {:?} to staging directory", deb_path); + + // Create temporary directory for package extraction + let temp_dir = tempfile::tempdir()?; + let extract_path = temp_dir.path(); + + // Extract DEB package + if !deb_path.exists() { + return Err(crate::error::AptOstreeError::InvalidArgument( + format!("DEB package not found: {:?}", deb_path) + )); + } + + // Extract DEB contents using dpkg-deb + let output = tokio::process::Command::new("dpkg-deb") + .args(&["-R", deb_path.to_str().unwrap(), extract_path.to_str().unwrap()]) + .output() + .await?; + + if !output.status.success() { + return Err(crate::error::AptOstreeError::SystemError( + format!("Failed to extract DEB package: {}", String::from_utf8_lossy(&output.stderr)) + )); + } + + // Copy extracted files to staging directory + let data_dir = extract_path.join("data"); + if data_dir.exists() { + self.copy_directory_recursive(&data_dir, staging_path)?; + } + + // Copy control files to package metadata + let control_dir = extract_path.join("control"); + if control_dir.exists() { + let package_name = deb_path.file_stem().and_then(|s| s.to_str()).unwrap_or("unknown"); + let control_dest = staging_path.join("var/lib/apt-ostree/packages").join(package_name).join("control"); + std::fs::create_dir_all(&control_dest)?; + self.copy_directory_recursive(&control_dir, &control_dest)?; + } + + info!("Package extracted successfully"); + Ok(()) + } + + /// Copy directory recursively + fn copy_directory_recursive(&self, src: &std::path::Path, dst: &std::path::Path) -> AptOstreeResult<()> { + if src.is_dir() { + std::fs::create_dir_all(dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dst_path = dst.join(entry.file_name()); + + if entry.file_type()?.is_dir() { + self.copy_directory_recursive(&src_path, &dst_path)?; + } else { + if let Some(parent) = dst_path.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::copy(&src_path, &dst_path)?; + } + } + } else { + if let Some(parent) = dst.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::copy(src, dst)?; + } Ok(()) }