From fda3dd1bdeed4074b9156607bd0281f3bdbde825 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Mon, 25 May 2026 08:17:52 +0530 Subject: [PATCH] Stop tracking deleted scanner files --- crates/oxide/src/scanner/mod.rs | 5 ++++ crates/oxide/tests/scanner.rs | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/crates/oxide/src/scanner/mod.rs b/crates/oxide/src/scanner/mod.rs index 30724f162188..66d84e54da11 100644 --- a/crates/oxide/src/scanner/mod.rs +++ b/crates/oxide/src/scanner/mod.rs @@ -424,6 +424,11 @@ impl Scanner { } } + // Forget files that were tracked during a previous scan but no longer + // appear in the current source walk. + self.files.retain(|file| seen_files.contains(file)); + self.mtimes.retain(|file, _| seen_files.contains(file)); + // Read + preprocess all discovered files in parallel let scanned_blobs: Vec> = content_paths .into_par_iter() diff --git a/crates/oxide/tests/scanner.rs b/crates/oxide/tests/scanner.rs index 4003ff253048..2fe50f85bb31 100644 --- a/crates/oxide/tests/scanner.rs +++ b/crates/oxide/tests/scanner.rs @@ -142,6 +142,20 @@ mod scanner { scan_with_globs(paths_with_content, vec!["@source '**/*'"]) } + fn scanned_files(scanner: &mut Scanner, base: &Path) -> Vec { + let base_dir = + format!("{}{}", dunce::canonicalize(base).unwrap().display(), "/").replace('\\', "/"); + + let mut files = scanner + .get_files() + .iter() + // Normalize paths to use unix style separators + .map(|file| file.replace('\\', "/").replace(&base_dir, "")) + .collect::>(); + files.sort(); + files + } + #[test] fn it_should_work_with_a_set_of_root_files() { let ScanResult { @@ -840,6 +854,43 @@ mod scanner { ); } + #[test] + fn it_should_stop_tracking_deleted_files() { + // Create a temporary working directory + let dir = tempdir().unwrap().into_path(); + + // Initialize this directory as a git repository + let _ = Command::new("git").arg("init").current_dir(&dir).output(); + + // Create files + create_files_in( + &dir, + &[ + ("src/index.html", "content-['src/index.html']"), + ("src/assets/icon.svg", ""), + ], + ); + + let sources = vec![public_source_entry_from_pattern( + dir.clone(), + "@source '**/*'", + )]; + + let mut scanner = Scanner::new(sources); + let _ = scanner.scan(); + + assert_eq!( + scanned_files(&mut scanner, &dir), + vec!["src/assets/icon.svg", "src/index.html"] + ); + + fs::remove_file(dir.join("src/assets/icon.svg")).unwrap(); + + let _ = scanner.scan(); + + assert_eq!(scanned_files(&mut scanner, &dir), vec!["src/index.html"]); + } + #[test] fn it_should_ignore_negated_custom_sources() { let ScanResult {