From 047e9bb9627b74bbdf61df7791410d718e50fb79 Mon Sep 17 00:00:00 2001 From: aiongg Date: Wed, 21 Oct 2026 14:55:45 +0000 Subject: [PATCH] Integration: #1924 a fresh re-import keeps its own stem sidecar --- crates/engine/src/sidecar.rs | 5 ++++- crates/engine/src/tests_import.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/sidecar.rs b/crates/engine/src/sidecar.rs index 005a30722..2e1092140 100644 --- a/crates/engine/src/sidecar.rs +++ b/crates/engine/src/sidecar.rs @@ -644,7 +644,9 @@ impl ImportStems { pub(crate) fn for_import<'a>(cat: Option<&lightcraft_catalog::Catalog>, incoming: impl Iterator) -> ImportStems { // per stem: the best of the library's files, and the best arriving file with its path let mut best: HashMap, Option<(Rank, &'a str)>)> = HashMap::new(); + let mut arriving_paths = HashSet::new(); for (arriving, (path, kind)) in incoming.enumerate() { + arriving_paths.insert(path); let e = best.entry(stem_key(path)).or_default(); let rank = rank_of(path, kind, arriving as u64); if e.1.as_ref().is_none_or(|(b, _)| rank < *b) { @@ -654,7 +656,8 @@ impl ImportStems { if let Some(cat) = cat { let mut key = String::new(); for p in cat.photos().filter(|p| p.copy_of.is_none()) { - let Some(path) = file_path(p) else { continue }; + // the arriving file's own record (a trashed photo imported again) is not a rival + let Some(path) = file_path(p).filter(|path| !arriving_paths.contains(*path)) else { continue }; stem_key_into(&mut key, path); let Some(e) = best.get_mut(key.as_str()) else { continue }; let rank = rank_of(path, p.kind, p.id.0); diff --git a/crates/engine/src/tests_import.rs b/crates/engine/src/tests_import.rs index 49ffafc8a..c5ff90456 100644 --- a/crates/engine/src/tests_import.rs +++ b/crates/engine/src/tests_import.rs @@ -1132,6 +1132,25 @@ fn import_can_replace_a_duplicate_from_recently_deleted() { let _ = std::fs::remove_dir_all(&src); } +/// A trashed photo imported again as a new one owns its stem sidecar: its own old record is not a +/// rival for `a.xmp` (issue #1905's ranking), so the fresh photo reads it. +#[test] +fn a_fresh_reimport_reads_its_own_stem_sidecar() { + let (mut s, src, id) = trashed_photo("trash-fresh-sidecar"); + std::fs::write( + src.join("a.xmp"), + r#" +"#, + ) + .unwrap(); + let r = s.execute("library.import", &json!({"paths": [src.to_string_lossy()], "onDeleted": "fresh"})).unwrap(); + assert_eq!(ids(&r, "imported"), 1, "{r}"); + let new = r["imported"][0].as_u64().unwrap(); + assert_ne!(new, id); + assert_eq!(s.catalog.photo(lightcraft_catalog::PhotoId(new)).unwrap().rating, 3, "the fresh photo reads a.xmp: {r}"); + let _ = std::fs::remove_dir_all(&src); +} + #[test] fn unknown_on_deleted_is_an_error() { let mut s = Session::new().with_fs();