diff --git a/src/deb/ephemeral.rs b/src/deb/ephemeral.rs index 573ff90..a307fd0 100644 --- a/src/deb/ephemeral.rs +++ b/src/deb/ephemeral.rs @@ -58,6 +58,38 @@ impl EphemeralContextGuard { let tarball_filename = format!("{}-buildd.tar.xz", series); let tarball_path = cache_dir.join(&tarball_filename); + // Check for existing lockfile, and wait for a timeout if it exists + // After timeout, warn the user + let lockfile_path = tarball_path.with_extension("lock"); + let ctx = context::current(); + + // Check if lockfile exists and wait for it to be removed + let mut wait_time = 0; + let timeout = 300; // 5 minutes timeout + let poll_interval = 5; // Check every 5 seconds + + while ctx.exists(&lockfile_path)? { + if wait_time >= timeout { + log::warn!( + "Lockfile {} exists and has been present for more than {} seconds. \ + Another process may be downloading the chroot tarball. Continuing anyway...", + lockfile_path.display(), + timeout + ); + break; + } + + log::info!( + "Lockfile {} exists, waiting for download to complete... ({}s/{})", + lockfile_path.display(), + wait_time, + timeout + ); + + std::thread::sleep(std::time::Duration::from_secs(poll_interval)); + wait_time += poll_interval; + } + // Download tarball if it doesn't exist if !tarball_path.exists() { log::debug!("Downloading chroot tarball for {}...", series); @@ -74,8 +106,16 @@ impl EphemeralContextGuard { } fn download_chroot_tarball(series: &str, tarball_path: &Path) -> Result<(), Box> { + let ctx = context::current(); + + // Create a lock file to make sure that noone tries to use the file while it's not fully downloaded + let lockfile_path = tarball_path.with_extension("lock"); + ctx.command("touch") + .arg(lockfile_path.to_string_lossy().to_string()) + .status()?; + // Use mmdebstrap to download the tarball to the cache directory - let status = context::current() + let status = ctx .command("mmdebstrap") .arg("--variant=buildd") .arg("--mode=unshare") @@ -86,9 +126,27 @@ impl EphemeralContextGuard { .status()?; if !status.success() { + // Remove file on error + let _ = ctx + .command("rm") + .arg("-f") + .arg(tarball_path.to_string_lossy().to_string()) + .status(); + let _ = ctx + .command("rm") + .arg("-f") + .arg(lockfile_path.to_string_lossy().to_string()) + .status(); return Err(format!("Failed to download chroot tarball for series {}", series).into()); } + // Remove lockfile: tarball is fully downloaded + let _ = ctx + .command("rm") + .arg("-f") + .arg(lockfile_path.to_string_lossy().to_string()) + .status(); + Ok(()) }