deb: cross-compilation, ephemeral contexts, local builds
All checks were successful
CI / build (push) Successful in 7m18s
All checks were successful
CI / build (push) Successful in 7m18s
Multiple changes: - New contexts (schroot, unshare) - Cross-building quirks, with ephemeral contexts and repositories management - Contexts with parents, global context manager, better lifetime handling - Local building of binary packages - Pull: pulling dsc files by default - Many small bugfixes and changes Co-authored-by: Valentin Haudiquet <valentin.haudiquet@canonical.com> Co-committed-by: Valentin Haudiquet <valentin.haudiquet@canonical.com>
This commit was merged in pull request #1.
This commit is contained in:
171
src/deb/local.rs
Normal file
171
src/deb/local.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
/// 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::deb::cross;
|
||||
|
||||
pub fn build(
|
||||
package: &str,
|
||||
version: &str,
|
||||
arch: &str,
|
||||
series: &str,
|
||||
build_root: &str,
|
||||
cross: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Environment
|
||||
let mut env = HashMap::<String, String>::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)?;
|
||||
}
|
||||
|
||||
// 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<dyn Error>> {
|
||||
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(())
|
||||
}
|
||||
Reference in New Issue
Block a user