deb: use qemu_binfmt on ephemeral/local builds of different arch
Some checks failed
CI / build (push) Failing after 18m19s
CI / snap (push) Has been skipped

This commit is contained in:
2026-02-11 11:58:59 +01:00
parent 97725efb34
commit 7c53b268dd
2 changed files with 54 additions and 17 deletions

View File

@@ -17,7 +17,12 @@ pub struct EphemeralContextGuard {
impl EphemeralContextGuard { impl EphemeralContextGuard {
/// Create a new ephemeral unshare context for the specified series /// Create a new ephemeral unshare context for the specified series
pub async fn new(series: &str) -> Result<Self, Box<dyn Error>> { ///
/// # Arguments
/// * `series` - The distribution series (e.g., "noble", "sid")
/// * `arch` - Optional target architecture. If provided and different from host,
/// downloads a chroot for that architecture (uses qemu_binfmt transparently)
pub async fn new(series: &str, arch: Option<&str>) -> Result<Self, Box<dyn Error>> {
let current_context_name = context::manager().current_name(); let current_context_name = context::manager().current_name();
// Create a temporary directory for the chroot // Create a temporary directory for the chroot
@@ -25,13 +30,14 @@ impl EphemeralContextGuard {
let chroot_path = PathBuf::from(chroot_path_str); let chroot_path = PathBuf::from(chroot_path_str);
log::debug!( log::debug!(
"Creating new chroot for {} at {}...", "Creating new chroot for {} (arch: {:?}) at {}...",
series, series,
arch,
chroot_path.display() chroot_path.display()
); );
// Download and extract the chroot tarball // Download and extract the chroot tarball
Self::download_and_extract_chroot(series, &chroot_path).await?; Self::download_and_extract_chroot(series, arch, &chroot_path).await?;
// Switch to an ephemeral context to build the package in the chroot // Switch to an ephemeral context to build the package in the chroot
context::manager().set_current_ephemeral(Context::new(ContextConfig::Unshare { context::manager().set_current_ephemeral(Context::new(ContextConfig::Unshare {
@@ -48,6 +54,7 @@ impl EphemeralContextGuard {
async fn download_and_extract_chroot( async fn download_and_extract_chroot(
series: &str, series: &str,
arch: Option<&str>,
chroot_path: &PathBuf, chroot_path: &PathBuf,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
// Get project directories for caching // Get project directories for caching
@@ -56,8 +63,12 @@ impl EphemeralContextGuard {
let cache_dir = proj_dirs.cache_dir(); let cache_dir = proj_dirs.cache_dir();
fs::create_dir_all(cache_dir)?; fs::create_dir_all(cache_dir)?;
// Create tarball filename based on series // Create tarball filename based on series and architecture
let tarball_filename = format!("{}-buildd.tar.xz", series); let tarball_filename = if let Some(a) = arch {
format!("{}-{}-buildd.tar.xz", series, a)
} else {
format!("{}-buildd.tar.xz", series)
};
let tarball_path = cache_dir.join(&tarball_filename); let tarball_path = cache_dir.join(&tarball_filename);
// Check for existing lockfile, and wait for a timeout if it exists // Check for existing lockfile, and wait for a timeout if it exists
@@ -94,10 +105,18 @@ impl EphemeralContextGuard {
// Download tarball if it doesn't exist // Download tarball if it doesn't exist
if !tarball_path.exists() { if !tarball_path.exists() {
log::debug!("Downloading chroot tarball for {}...", series); log::debug!(
Self::download_chroot_tarball(series, &tarball_path).await?; "Downloading chroot tarball for {} (arch: {:?})...",
series,
arch
);
Self::download_chroot_tarball(series, arch, &tarball_path).await?;
} else { } else {
log::debug!("Using cached chroot tarball for {}", series); log::debug!(
"Using cached chroot tarball for {} (arch: {:?})",
series,
arch
);
} }
// Extract tarball to chroot directory // Extract tarball to chroot directory
@@ -113,6 +132,7 @@ impl EphemeralContextGuard {
async fn download_chroot_tarball( async fn download_chroot_tarball(
series: &str, series: &str,
arch: Option<&str>,
tarball_path: &Path, tarball_path: &Path,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let ctx = context::current(); let ctx = context::current();
@@ -134,15 +154,21 @@ impl EphemeralContextGuard {
} }
// Use mmdebstrap to download the tarball to the cache directory // Use mmdebstrap to download the tarball to the cache directory
let status = ctx let mut cmd = ctx.command("mmdebstrap");
.command("mmdebstrap") cmd.arg("--variant=buildd")
.arg("--variant=buildd")
.arg("--mode=unshare") .arg("--mode=unshare")
.arg("--include=mount,curl,ca-certificates") .arg("--include=mount,curl,ca-certificates")
.arg("--format=tar") .arg("--format=tar");
.arg(series)
.arg(tarball_path.to_string_lossy().to_string()) // Add architecture if specified
.status()?; if let Some(a) = arch {
cmd.arg(format!("--arch={}", a));
}
cmd.arg(series)
.arg(tarball_path.to_string_lossy().to_string());
let status = cmd.status()?;
if !status.success() { if !status.success() {
// Remove file on error // Remove file on error
@@ -156,7 +182,11 @@ impl EphemeralContextGuard {
.arg("-f") .arg("-f")
.arg(lockfile_path.to_string_lossy().to_string()) .arg(lockfile_path.to_string_lossy().to_string())
.status(); .status();
return Err(format!("Failed to download chroot tarball for series {}", series).into()); return Err(format!(
"Failed to download chroot tarball for series {} (arch: {:?})",
series, arch
)
.into());
} }
// Remove lockfile: tarball is fully downloaded // Remove lockfile: tarball is fully downloaded

View File

@@ -49,8 +49,15 @@ pub async fn build_binary_package(
}; };
// Create an ephemeral unshare context for all Local builds // Create an ephemeral unshare context for all Local builds
// Use qemu_binfmt when target architecture differs from host and cross is not requested
let chroot_arch = if mode == BuildMode::Local && arch != current_arch && !cross {
Some(arch)
} else {
None
};
let mut guard = if mode == BuildMode::Local { let mut guard = if mode == BuildMode::Local {
Some(ephemeral::EphemeralContextGuard::new(series).await?) Some(ephemeral::EphemeralContextGuard::new(series, chroot_arch).await?)
} else { } else {
None None
}; };