diff options
| -rw-r--r-- | src/build.rs | 42 | ||||
| -rw-r--r-- | tests/build.rs | 45 |
2 files changed, 69 insertions, 18 deletions
diff --git a/src/build.rs b/src/build.rs index 7fd3989..8b6ebb0 100644 --- a/src/build.rs +++ b/src/build.rs @@ -109,25 +109,31 @@ impl<I: PackageInstaller, B: InitramfsBuilder> BuildExecutor<I, B> { Ok(initrd) => initrd, Err(error) => return Self::fail_and_remove_workspace(workspace, error), }; - std::fs::create_dir_all(parent) - .with_context(|| format!("create artifact directory {}", parent.display()))?; - self.tar_writer.write(&rootfs, artifact)?; - let manifest = ArtifactManifest::collect( - &rootfs, - Vec::new(), - Some(InitrdRecord::new( - initrd.initrd_path().display().to_string(), - initrd.sha256(), - )), - artifact, - )?; - let manifest_path = manifest.write_beside(artifact)?; + let result = (|| { + std::fs::create_dir_all(parent) + .with_context(|| format!("create artifact directory {}", parent.display()))?; + self.tar_writer.write(&rootfs, artifact)?; + let manifest = ArtifactManifest::collect( + &rootfs, + Vec::new(), + Some(InitrdRecord::new( + initrd.initrd_path().display().to_string(), + initrd.sha256(), + )), + artifact, + )?; + let manifest_path = manifest.write_beside(artifact)?; - Ok(BuildResult { - artifact: artifact.to_path_buf(), - manifest: manifest_path, - initrd: Some(initrd), - }) + Ok(BuildResult { + artifact: artifact.to_path_buf(), + manifest: manifest_path, + initrd: Some(initrd), + }) + })(); + match result { + Ok(result) => Ok(result), + Err(error) => Self::fail_and_remove_workspace(workspace, error), + } } fn fail_and_remove_workspace<T>(workspace: &Path, error: anyhow::Error) -> Result<T> { diff --git a/tests/build.rs b/tests/build.rs index 7d67b29..2fcd1bf 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -59,6 +59,20 @@ impl InitramfsBuilder for FailingInitramfsBuilder { } } +struct ArchiveFailingInstaller; + +impl PackageInstaller for ArchiveFailingInstaller { + fn install(&self, request: &PackageRequest) -> anyhow::Result<()> { + let rootfs = request.workdir().join("chroot"); + fs::create_dir_all(rootfs.join("boot"))?; + fs::write(rootfs.join("boot/vmlinuz-6.12.0-rt1"), "kernel")?; + std::os::unix::net::UnixListener::bind(rootfs.join("unsupported.socket")) + .expect("create unsupported socket fixture") + .set_nonblocking(true)?; + Ok(()) + } +} + #[derive(Default)] struct FixtureInitramfsBuilder; @@ -310,3 +324,34 @@ fn removes_the_new_workspace_when_initramfs_build_fails() { ); assert!(!artifact.exists()); } + +#[test] +fn removes_the_new_workspace_and_partial_artifact_when_packaging_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(ArchiveFailingInstaller, FixtureInitramfsBuilder); + let workspace = fixture.path().join("work"); + let artifact = fixture.path().join("out/image.tar"); + + let error = executor + .execute(&plan, &workspace, "profiles/apt.conf", &artifact) + .expect_err("unsupported rootfs entry must fail packaging"); + + assert!(error.to_string().contains("unsupported rootfs entry type")); + assert!( + !workspace.exists(), + "failed build must not leave a workspace" + ); + assert!( + !artifact.exists(), + "failed packaging must not leave an artifact" + ); + assert!( + !ArtifactManifest::path_beside(&artifact) + .expect("manifest path") + .exists(), + "failed packaging must not leave a companion manifest" + ); +} |