deb: use qemu_binfmt on ephemeral/local builds of different arch
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user