/// Local binary package building /// Directly calling 'debian/rules' in current context use crate::context; use crate::deb::find_dsc_file; use std::collections::HashMap; use std::error::Error; use std::path::Path; use crate::apt; use crate::deb::cross; pub fn build( package: &str, version: &str, arch: &str, series: &str, build_root: &str, cross: bool, ) -> Result<(), Box> { // Environment let mut env = HashMap::::new(); env.insert("LANG".to_string(), "C".to_string()); env.insert("DEBIAN_FRONTEND".to_string(), "noninteractive".to_string()); let ctx = context::current(); if cross { log::debug!("Setting up environment for local cross build..."); cross::setup_environment(&mut env, arch)?; cross::ensure_repositories(arch, series)?; } // UBUNTU: Ensure 'universe' repository is enabled let mut sources = apt::load(None)?; let mut modified = false; for source in &mut sources { if source.uri.contains("ubuntu") && !source.components.contains(&"universe".to_string()) { source.components.push("universe".to_string()); modified = true; } } if modified { apt::save_legacy(None, sources, "/etc/apt/sources.list")?; } // Update package lists log::debug!("Updating package lists for local build..."); let status = ctx .command("apt-get") .envs(env.clone()) .arg("update") .status()?; if !status.success() { return Err( "Could not execute apt-get update. If this is a local build, try executing with sudo." .into(), ); } // Install essential packages log::debug!("Installing essential packages for local build..."); let mut cmd = ctx.command("apt-get"); cmd.envs(env.clone()) .arg("-y") .arg("install") .arg("build-essential") .arg("dose-builddebcheck") .arg("fakeroot"); if cross { cmd.arg(format!("crossbuild-essential-{arch}")); cmd.arg(format!("libc6-{arch}-cross")); cmd.arg(format!("libc6-dev-{arch}-cross")); cmd.arg("dpkg-cross"); cmd.arg(format!("libc6:{arch}")); cmd.arg(format!("libc6-dev:{arch}")); } let status = cmd.status()?; if !status.success() { return Err("Could not install essential packages for the build".into()); } // Install build dependencies log::debug!("Installing build dependencies..."); let mut cmd = ctx.command("apt-get"); cmd.current_dir(format!("{build_root}/{package}")) .envs(env.clone()) .arg("-y") .arg("build-dep"); if cross { cmd.arg(format!("--host-architecture={arch}")); } let status = cmd.arg("./").status()?; // If build-dep fails, we try to explain the failure using dose-debcheck if !status.success() { dose3_explain_dependencies(package, version, arch, build_root, cross)?; return Err("Could not install build-dependencies for the build".into()); } // Run the build step log::debug!("Building (debian/rules build) package..."); let status = ctx .command("debian/rules") .current_dir(format!("{build_root}/{package}")) .envs(env.clone()) .arg("build") .status()?; if !status.success() { return Err("Error while building the package".into()); } // Run the 'binary' step to produce deb let status = ctx .command("fakeroot") .current_dir(format!("{build_root}/{package}")) .envs(env.clone()) .arg("debian/rules") .arg("binary") .status()?; if !status.success() { return Err( "Error while building the binary artifacts (.deb) from the built package".into(), ); } Ok(()) } fn dose3_explain_dependencies( package: &str, version: &str, arch: &str, build_root: &str, cross: bool, ) -> Result<(), Box> { let ctx = context::current(); // Construct the list of Packages files let mut bg_args = Vec::new(); let mut cmd = ctx.command("apt-get"); cmd.arg("indextargets") .arg("--format") .arg("$(FILENAME)") .arg("Created-By: Packages"); let output = cmd.output()?; if output.status.success() { let filenames = String::from_utf8_lossy(&output.stdout); for file in filenames.lines() { let file = file.trim(); if !file.is_empty() { bg_args.push(file.to_string()); } } } // Transform the dsc file into a 'Source' stanza (replacing 'Source' with 'Package') let dsc_path = find_dsc_file(build_root, package, version)?; let mut dsc_content = ctx.read_file(&dsc_path)?; dsc_content = dsc_content.replace("Source", "Package"); ctx.write_file( Path::new(&format!("{build_root}/dsc-processed")), &dsc_content, )?; // Call dose-builddebcheck let local_arch = crate::get_current_arch(); let mut cmd = ctx.command("dose-builddebcheck"); cmd.arg("--verbose") .arg("--failures") .arg("--explain") .arg("--summary") .arg(format!("--deb-native-arch={}", local_arch)); if cross { cmd.arg(format!("--deb-host-arch={}", arch)) .arg("--deb-profiles=cross") .arg(format!("--deb-foreign-archs={}", arch)); } cmd.args(bg_args).arg(format!("{build_root}/dsc-processed")); cmd.status()?; Ok(()) }