diff options
| author | Hermes Agent <hermes@localhost> | 2026-08-12 04:01:16 +0000 |
|---|---|---|
| committer | Hermes Agent <hermes@localhost> | 2026-08-12 04:01:16 +0000 |
| commit | 196f315321643a0ce2327f750c779a7d40e4b427 (patch) | |
| tree | 700f3f67afea6f0a5086ce36782747ee63c26983 | |
| parent | 815ec6e06e05f03022c2076f6e8573f1d2c454c9 (diff) | |
Avoid manifest collisions beside artifacts
| -rw-r--r-- | src/manifest.rs | 18 | ||||
| -rw-r--r-- | tests/compare.rs | 20 |
2 files changed, 34 insertions, 4 deletions
diff --git a/src/manifest.rs b/src/manifest.rs index 8e9d13c..3a34af7 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -46,14 +46,26 @@ impl ArtifactManifest { } pub fn write_beside(&self, artifact: impl AsRef<Path>) -> Result<PathBuf> { - let artifact = artifact.as_ref(); - let directory = artifact.parent().unwrap_or_else(|| Path::new(".")); - let path = directory.join("artifact.manifest.toml"); + let path = Self::path_beside(artifact)?; let text = toml::to_string_pretty(self).context("serialize artifact manifest")?; fs::write(&path, text).with_context(|| format!("write artifact manifest {}", path.display()))?; Ok(path) } + /// Return the unambiguous companion-manifest path for one artifact. + /// Keeping the artifact filename prevents legacy and native manifests from + /// overwriting one another when both are written to the comparison output + /// directory. + pub fn path_beside(artifact: impl AsRef<Path>) -> Result<PathBuf> { + let artifact = artifact.as_ref(); + let name = artifact + .file_name() + .ok_or_else(|| anyhow::anyhow!("artifact path has no filename: {}", artifact.display()))?; + let mut manifest_name = name.to_os_string(); + manifest_name.push(".manifest.toml"); + Ok(artifact.with_file_name(manifest_name)) + } + /// Collect native filesystem and archive facts from a completed build. /// Package records come from the typed package-installation boundary because /// the RPM database is not a portable filesystem format. diff --git a/tests/compare.rs b/tests/compare.rs index 2e06a39..43c91e0 100644 --- a/tests/compare.rs +++ b/tests/compare.rs @@ -136,11 +136,29 @@ fn reads_and_writes_a_toml_manifest_beside_an_artifact() { let manifest = baseline(); let manifest_path = manifest.write_beside(&artifact).expect("write manifest"); - assert_eq!(manifest_path, fixture.path().join("artifact.manifest.toml")); + assert_eq!(manifest_path, fixture.path().join("controller.tar.manifest.toml")); assert_eq!(ArtifactManifest::load(&manifest_path).expect("load manifest"), manifest); } #[test] +fn writes_distinct_manifests_for_artifacts_in_the_same_directory() { + let fixture = tempdir().expect("temporary directory"); + let legacy = fixture.path().join("legacy.tar"); + let native = fixture.path().join("native.tar"); + let legacy_manifest = baseline(); + let native_manifest = ArtifactManifest::new(vec![], vec![], None, vec![], vec![]) + .expect("valid native manifest"); + + let legacy_path = legacy_manifest.write_beside(&legacy).expect("write legacy manifest"); + let native_path = native_manifest.write_beside(&native).expect("write native manifest"); + + assert_eq!(legacy_path, fixture.path().join("legacy.tar.manifest.toml")); + assert_eq!(native_path, fixture.path().join("native.tar.manifest.toml")); + assert_eq!(ArtifactManifest::load(&legacy_path).expect("load legacy manifest"), legacy_manifest); + assert_eq!(ArtifactManifest::load(&native_path).expect("load native manifest"), native_manifest); +} + +#[test] fn rejects_duplicate_semantic_keys() { let error = ArtifactManifest::new( vec![PackageRecord::new("controller", "1"), PackageRecord::new("controller", "2")], |