Skip to content

Commit a1b3c60

Browse files
committed
no-mistakes(review): Locate deleted-directory events in symlinked workspaces
1 parent 9a2d7cd commit a1b3c60

1 file changed

Lines changed: 31 additions & 5 deletions

File tree

‎crates/codegraph-server/src/indexer.rs‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,13 @@ impl WorkspaceFilter {
129129
/// opened as `/var/folders/...` or through any symlinked directory is
130130
/// reported by FSEvents at its resolved location, `/private/var/folders/...`,
131131
/// so a plain prefix test rejected every event and the watcher admitted
132-
/// nothing at all. Both sides are compared resolved and as given.
132+
/// nothing at all. The event path is compared, as reported, against both
133+
/// spellings of the root; that needs no filesystem access, so it still
134+
/// works when the file's directory was deleted along with it.
133135
///
134-
/// The event path is resolved through its parent directory, which still
135-
/// exists when the file itself was just deleted. The most specific root
136-
/// wins when workspace folders nest.
136+
/// A path reported in unresolved form is additionally resolved through its
137+
/// parent directory. The most specific root wins when workspace folders
138+
/// nest.
137139
fn locate(&self, path: &Path) -> Option<(PathBuf, PathBuf, &IndexConfig, &globset::GlobSet)> {
138140
let resolved = path
139141
.parent()
@@ -143,7 +145,11 @@ impl WorkspaceFilter {
143145

144146
let mut best: Option<(usize, PathBuf, PathBuf, &IndexConfig, &globset::GlobSet)> = None;
145147
for (given, canonical, config, exclude_set) in &self.roots {
146-
for (candidate, root) in [(Some(path), given), (resolved.as_deref(), canonical)] {
148+
for (candidate, root) in [
149+
(Some(path), given),
150+
(Some(path), canonical),
151+
(resolved.as_deref(), canonical),
152+
] {
147153
let Some(candidate) = candidate else { continue };
148154
let Ok(relative) = candidate.strip_prefix(root) else {
149155
continue;
@@ -867,6 +873,26 @@ mod tests {
867873
);
868874
}
869875

876+
/// Deleting a directory removes the parent an event path would be resolved
877+
/// through, so a resolved-form path must be located without touching disk.
878+
#[cfg(unix)]
879+
#[test]
880+
fn workspace_filter_locates_files_in_a_deleted_directory() {
881+
let tmp = tempfile::tempdir().unwrap();
882+
let real = tmp.path().join("real");
883+
std::fs::create_dir_all(real.join("src/old")).unwrap();
884+
std::fs::write(real.join("src/old/a.rs"), "fn a() {}\n").unwrap();
885+
let link = tmp.path().join("link");
886+
std::os::unix::fs::symlink(&real, &link).unwrap();
887+
888+
let filter = WorkspaceFilter::new(std::slice::from_ref(&link), &filter_config(&[], 20));
889+
let deleted = real.canonicalize().unwrap().join("src/old/a.rs");
890+
std::fs::remove_dir_all(real.join("src/old")).unwrap();
891+
892+
assert!(filter.admits(&deleted));
893+
assert_eq!(filter.indexed_form(&deleted), link.join("src/old/a.rs"));
894+
}
895+
870896
#[test]
871897
fn workspace_filter_prefers_the_most_specific_root() {
872898
let tmp = tempfile::tempdir().unwrap();

0 commit comments

Comments
 (0)