LRC-LIB-CATALOG-SWITCH: Try Again on a missing remembered library makes none in an empty folder (#3239)

This commit is contained in:
Bruno-Alumn
2026-10-29 23:01:22 +01:00
parent 8ca7280e2b
commit 72c44530ef
5 changed files with 75 additions and 10 deletions
+3 -6
View File
@@ -280,12 +280,9 @@ fn open_library_session(in_memory: bool, dir: Option<std::path::PathBuf>, rememb
};
if remembered && !lightcraft_engine::library::is_library(&dir) {
log::error!("library {} is missing", dir.display());
let why = if dir.exists() {
"There is no LightCraft library in this folder any more."
} else {
"The library isn't there: it was moved or renamed, or its drive or network share isn't connected."
};
return (unopened(), Some(LibraryProblem::new(dir.to_string_lossy(), why)));
let why = lightcraft_ui_egui::panels::library_problem::missing_library_reason(&dir);
// Try Again must not make one there either (an empty mount point, issue #3239)
return (unopened(), Some(LibraryProblem { existing_only: true, ..LibraryProblem::new(dir.to_string_lossy(), why) }));
}
let t0 = std::time::Instant::now();
let mut s = Session::new().with_fs().with_default_denoise_models().with_system_clock();
+2 -1
View File
@@ -76,12 +76,13 @@ fn a_remembered_library_missing_at_launch_is_reported_not_made_anew() {
let problem = problem.expect("the missing library is reported");
assert_eq!(problem.path, lib.to_string_lossy());
assert!(problem.can_retry, "Try Again once the drive is back");
assert!(problem.existing_only, "Try Again makes no library there either");
assert!(!gone.exists(), "nothing is created where the library was");
assert!(s.library.is_none() && s.catalog.is_empty(), "no library, no demo photos");
// a remembered folder that is there but holds no library is reported too
std::fs::create_dir_all(&lib).unwrap();
let (s, problem) = open_session(false, &launch, true);
assert!(problem.is_some() && s.library.is_none() && s.catalog.is_empty());
assert!(problem.as_ref().is_some_and(|p| p.existing_only) && s.library.is_none() && s.catalog.is_empty(), "{problem:?}");
assert!(!lightcraft_engine::library::is_library(&lib), "nothing written in it");
// the default location (or --library) is still made when it's missing, with the demo photos
let fresh = d.join("fresh").join("Lib");
+35 -1
View File
@@ -345,6 +345,11 @@ pub struct LibraryProblem {
/// Try Again reopens `path` as a library folder (`false` in the browser, whose storage isn't
/// a folder: reloading the page tries again).
pub can_retry: bool,
/// Try Again opens `path` only once it holds a library again, and never makes one there: set
/// for the library remembered in Settings that was missing at launch, whose folder can be
/// the empty mount point of a share that isn't connected yet (issue #3239). Choose Another
/// Library… still creates one where asked.
pub existing_only: bool,
/// The window lists the recent libraries to choose from instead (issue #1290); `error` then
/// says why the last one tried didn't open.
pub chooser: Option<Chooser>,
@@ -714,6 +719,31 @@ fn unavailable(path: &str) -> Option<Unavailable> {
None
}
/// Why the library at `dir` that has to exist already (a remembered one, issue #3239) can't be
/// opened: the folder is there without a catalog, or the folder itself is missing.
pub fn missing_library_reason(dir: &Path) -> &'static str {
if dir.exists() {
"There is no LightCraft library in this folder any more."
} else {
"The library isn't there: it was moved or renamed, or its drive or network share isn't connected."
}
}
/// Try Again: reopen the problem's library. One that must exist already (`existing_only`) is
/// opened only once its folder holds a library again (a share remounted): until then the window
/// stays with the reason, and nothing is created there (issue #3239).
fn retry(app: &mut LightcraftApp, problem: LibraryProblem) {
let dir = Path::new(&problem.path);
if problem.existing_only && !lightcraft_engine::library::is_library(dir) {
if let Some(p) = app.library_problem.as_mut() {
p.error = missing_library_reason(dir).to_string();
p.dismissed = false;
}
return;
}
open(app, Some(problem.path));
}
/// What the user chose.
#[derive(Clone, Copy, Debug, PartialEq)]
enum Choice {
@@ -811,6 +841,10 @@ fn open(app: &mut LightcraftApp, path: Option<String>) {
}
}
if let Some(path) = path {
// another library failed: Try Again may make that one, as it always could
if p.path != path {
p.existing_only = false;
}
p.path = path;
}
p.error = e;
@@ -1077,7 +1111,7 @@ fn act(app: &mut LightcraftApp, choice: Choice) {
let Some(problem) = app.library_problem.clone() else { return };
let chosen = problem.chooser.as_ref().and_then(|c| c.selected.and_then(|i| c.libraries.get(i)).map(|l| (l.clone(), c.over)));
match choice {
Choice::Retry => open(app, Some(problem.path)),
Choice::Retry => retry(app, problem),
Choice::Choose => open(app, None),
Choice::Open => {
let Some((library, over)) = chosen.filter(|(l, _)| l.unavailable.is_none()) else { return };
@@ -1032,3 +1032,34 @@ fn found_again(multipass: bool) {
drop(h);
let _ = std::fs::remove_dir_all(&dir);
}
/// Issue #3239: Try Again on a remembered library that was missing at launch makes no library in
/// its folder when the folder is there but empty (a share's mount point before the share is
/// connected): the window stays and says so. Once the folder holds the library again, it opens.
#[test]
fn try_again_on_a_missing_remembered_library_makes_nothing_in_an_empty_folder() {
let dir = temp("retry-existing");
let mount = dir.join("Share");
std::fs::create_dir_all(&mount).unwrap();
let path = mount.to_string_lossy().into_owned();
let mut app = LightcraftApp::new(lightcraft_engine::Session::new().with_fs(), Services::default());
app.library_problem = Some(LibraryProblem { existing_only: true, ..LibraryProblem::new(path.clone(), "missing") });
let mut h = Headless::new(app, [1300.0, 900.0], 1.0);
settle(&mut h);
assert_eq!(h.request("ui.clickWidget", json!({"id": "button:libraryRetry"}), T)["ok"], true);
settle(&mut h);
assert!(!lightcraft_engine::library::is_library(&mount), "no catalog is made in the empty folder");
assert_eq!(std::fs::read_dir(&mount).unwrap().count(), 0, "nothing is written there");
assert!(h.app.session.library.is_none());
let p = h.app.library_problem.as_ref().expect("the window stays");
assert_eq!(p.error, "There is no LightCraft library in this folder any more.");
assert!(has(&h, "button:libraryRetry"));
// the share is connected again: Try Again opens the library in it
make_library(&mount);
assert_eq!(h.request("ui.clickWidget", json!({"id": "button:libraryRetry"}), T)["ok"], true);
settle(&mut h);
assert_eq!(h.app.session.library.as_ref().map(|l| l.dir.to_string_lossy().into_owned()), Some(path));
assert!(h.app.library_problem.is_none());
drop(h);
let _ = std::fs::remove_dir_all(&dir);
}
+4 -2
View File
@@ -7,8 +7,10 @@
yet or it was moved, the window now says it couldn't open the library and offers Try Again, Choose Another
Library…, Continue Without Saving and Quit. Before, LightCraft quietly made a new, empty library at that path,
filled it with the demo photos and opened it, so it looked as if the photos and edits were gone. Nothing is
written there now. A library given with `--library` or `LIGHTCRAFT_LIBRARY`, and the default location on first
launch, are still created as before.
written there now, and Try Again opens the library once its drive or share is back: on an empty folder left in
its place, such as a share's mount point, it says so again instead of making a new library there. A library
given with `--library` or `LIGHTCRAFT_LIBRARY`, and the default location on first launch, are still created as
before.
## 2026-10-24