summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHermes Agent <hermes@localhost>2026-08-12 07:06:09 +0000
committerHermes Agent <hermes@localhost>2026-08-12 07:06:09 +0000
commite09ee680abd286d25604c2242fa3e128fbdeed69 (patch)
tree2bfa3f97a8de8655dd087fb6ff4341dfec7dfe3c
parent177d6b8bf30bfd6f7f9386b78d8ad2e05d9a88fe (diff)
Clean workspace after package installation failure
-rw-r--r--src/build.rs6
-rw-r--r--tests/build.rs27
2 files changed, 32 insertions, 1 deletions
diff --git a/src/build.rs b/src/build.rs
index fcacfc0..305c059 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -57,7 +57,11 @@ impl<I: PackageInstaller, B: InitramfsBuilder> BuildExecutor<I, B> {
let request = plan.package_request(workspace, apt_config)?;
std::fs::create_dir_all(workspace)
.with_context(|| format!("create workspace {}", workspace.display()))?;
- self.installer.install(&request)?;
+ if let Err(error) = self.installer.install(&request) {
+ std::fs::remove_dir_all(workspace)
+ .with_context(|| format!("remove failed workspace {}", workspace.display()))?;
+ return Err(error);
+ }
let rootfs = workspace.join("chroot");
if !rootfs.is_dir() {
diff --git a/tests/build.rs b/tests/build.rs
index c6ed70d..dc9443c 100644
--- a/tests/build.rs
+++ b/tests/build.rs
@@ -23,6 +23,14 @@ impl PackageInstaller for FixtureInstaller {
}
}
+struct FailingInstaller;
+
+impl PackageInstaller for FailingInstaller {
+ fn install(&self, _request: &PackageRequest) -> anyhow::Result<()> {
+ anyhow::bail!("simulated package installation failure")
+ }
+}
+
#[derive(Default)]
struct FixtureInitramfsBuilder;
@@ -154,3 +162,22 @@ fn rejects_a_missing_apt_configuration_before_creating_the_workspace() {
assert!(!workspace.exists());
assert!(installer.requests.borrow().is_empty());
}
+
+#[test]
+fn removes_the_new_workspace_when_package_installation_fails() {
+ let fixture = tempdir().expect("fixture directory");
+ let spec = ImageSpec::load(std::path::Path::new("profiles/alt-controller.toml"))
+ .expect("load controller spec");
+ let plan = BuildPlan::compile(spec).expect("compile build plan");
+ let mut executor = BuildExecutor::new(FailingInstaller, FixtureInitramfsBuilder);
+ let workspace = fixture.path().join("work");
+ let artifact = fixture.path().join("image.tar");
+
+ let error = executor
+ .execute(&plan, &workspace, "profiles/apt.conf", &artifact)
+ .expect_err("failed installation must fail the build");
+
+ assert!(error.to_string().contains("simulated package installation failure"));
+ assert!(!workspace.exists(), "failed build must not leave a workspace");
+ assert!(!artifact.exists());
+}