mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 12:13:19 +00:00
Merge pull request #5914 from adikshan11/fix/library-file-name-collision
Keep the other library when two names share a file name
This commit is contained in:
@@ -211,7 +211,28 @@ impl<L: LibraryFile> Libraries<L> {
|
||||
.user_dir()
|
||||
.ok_or_else(|| bad(cmd, "no user library folder here (save with a path, or without one to get the data)"))?
|
||||
.to_string();
|
||||
let file = library_file_name(name, ext);
|
||||
let mut file = library_file_name(name, ext);
|
||||
// `COM¹` is saved as `COM¹-`, which can be another library's own name, and a library put
|
||||
// under a numbered name holds a file another name can ask for: such a file is kept.
|
||||
self.rescan();
|
||||
let device = crate::file_access::is_device_name;
|
||||
let id = format!("user/{file}").to_lowercase();
|
||||
let fallback = |other: &str| library_file_name(other, ext).to_lowercase() != file.to_lowercase();
|
||||
if self
|
||||
.extra
|
||||
.iter()
|
||||
.any(|e| e.info.id.to_lowercase() == id && e.lib.name() != name && (device(name) || device(e.lib.name()) || fallback(e.lib.name())))
|
||||
{
|
||||
// Saved again, it goes back to the file it was given the first time.
|
||||
let own = self.extra.iter().find(|e| e.info.category == "user" && e.lib.name() == name && extension(&e.info.id) == extension(&file));
|
||||
file = match own.and_then(|e| e.info.id.strip_prefix("user/")) {
|
||||
Some(own) => own.to_string(),
|
||||
None => {
|
||||
let mut taken: HashSet<String> = library_files(&dir, L::EXTS).iter().map(|p| file_name(p).to_lowercase()).collect();
|
||||
free_name(&file, &mut taken)
|
||||
}
|
||||
};
|
||||
}
|
||||
let path = std::path::Path::new(&dir).join(&file).to_string_lossy().to_string();
|
||||
// The app's own folder, under a name made safe: no root applies.
|
||||
crate::file_access::unconfined(|| create_dir(&dir).and_then(|()| write_file(&path, bytes)))?;
|
||||
|
||||
@@ -765,6 +765,33 @@ fn a_pattern_library_adds_only_the_picked_pattern_and_it_undoes_and_saves() {
|
||||
assert_eq!(back.swatch("Checkerboard").map(|w| &w.paint), doc(&s).swatch("Checkerboard").map(|w| &w.paint));
|
||||
}
|
||||
|
||||
/// A device name is saved with a `-` after it, which can be another library's own name: neither
|
||||
/// library replaces the other, and saving either again replaces only itself.
|
||||
#[test]
|
||||
fn a_library_named_like_a_device_keeps_the_library_with_its_file_name() {
|
||||
for (first, second) in [("COM¹", "COM¹-"), ("COM¹-", "COM¹"), ("com¹", "COM¹-")] {
|
||||
let dir = temp_dir("device-collision");
|
||||
let mut s = session();
|
||||
s.swatch_libraries.set_user_dir(Some(dir.to_string_lossy().to_string()));
|
||||
let save =
|
||||
|s: &mut Session, name: &str| run(s, "swatch.library.save", json!({"user": true, "name": name}))["library"].as_str().unwrap().to_string();
|
||||
let a = save(&mut s, first);
|
||||
let b = save(&mut s, second);
|
||||
assert_ne!(a, b);
|
||||
assert_eq!(save(&mut s, first), a, "saving {first} again replaces {first}");
|
||||
assert_eq!(save(&mut s, second), b, "saving {second} again replaces {second}");
|
||||
assert_eq!(s.swatch_libraries.get(&a).unwrap().1.name, first);
|
||||
assert_eq!(s.swatch_libraries.get(&b).unwrap().1.name, second);
|
||||
// The name of the numbered file the second one got is a third library's own name.
|
||||
let third = b.strip_prefix("user/").unwrap().strip_suffix(".vcswatches").unwrap().to_string();
|
||||
let c = save(&mut s, &third);
|
||||
assert!(c != a && c != b, "{third}: {c}");
|
||||
assert_eq!(save(&mut s, &third), c, "saving {third} again replaces {third}");
|
||||
assert_eq!(s.swatch_libraries.get(&b).unwrap().1.name, second);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// #3602: a library titled with a Windows device name is saved under a name that is not one.
|
||||
#[test]
|
||||
fn a_library_file_name_is_never_a_windows_device_name() {
|
||||
|
||||
Reference in New Issue
Block a user