worktree: Prevent background scanner from trying to scan file worktrees (#39277)

Release Notes:

- N/A *or* Added/Fixed/Improved ...
This commit is contained in:
Lukas Wirth 2025-10-03 15:12:24 +02:00 committed by GitHub
parent 1b94d74dc3
commit 86322a186f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 32 deletions

View file

@ -791,11 +791,15 @@ impl Fs for RealFs {
let watcher = Arc::new(fs_watcher::FsWatcher::new(tx, pending_paths.clone()));
// If the path doesn't exist yet (e.g. settings.json), watch the parent dir to learn when it's created.
if watcher.add(path).is_err()
if let Err(e) = watcher.add(path)
&& let Some(parent) = path.parent()
&& let Err(e) = watcher.add(parent)
&& let Err(parent_e) = watcher.add(parent)
{
log::warn!("Failed to watch: {e}");
log::warn!(
"Failed to watch {} and its parent directory {}:\n{e}\n{parent_e}",
path.display(),
parent.display()
);
}
// Check if path is a symlink and follow the target parent

View file

@ -1380,7 +1380,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
cx.executor().run_until_parked();
assert_eq!(mem::take(&mut *file_changes.lock()), &[]);
assert_eq!(fs.read_dir_call_count() - prev_read_dir_count, 5);
assert_eq!(fs.read_dir_call_count() - prev_read_dir_count, 4);
let mut new_watched_paths = fs.watched_paths();
new_watched_paths.retain(|path| {

View file

@ -158,6 +158,7 @@ pub struct RemoteWorktree {
#[derive(Clone)]
pub struct Snapshot {
id: WorktreeId,
/// The absolute path of the worktree root.
abs_path: Arc<SanitizedPath>,
path_style: PathStyle,
root_name: Arc<RelPath>,
@ -235,7 +236,7 @@ pub struct LocalSnapshot {
/// All of the git repositories in the worktree, indexed by the project entry
/// id of their parent directory.
git_repositories: TreeMap<ProjectEntryId, LocalRepositoryEntry>,
/// The file handle of the root dir
/// The file handle of the worktree root. `None` if the worktree is a directory.
/// (so we can find it after it's been moved)
root_file_handle: Option<Arc<dyn fs::FileHandle>>,
}
@ -370,11 +371,19 @@ impl Worktree {
true
});
let root_file_handle = fs
.open_handle(&abs_path)
.await
.context("failed to open local worktree root")
.log_err();
let root_file_handle = if metadata.as_ref().is_some() {
fs.open_handle(&abs_path)
.await
.with_context(|| {
format!(
"failed to open local worktree root at {}",
abs_path.display()
)
})
.log_err()
} else {
None
};
cx.new(move |cx: &mut Context<Worktree>| {
let mut snapshot = LocalSnapshot {
@ -3572,25 +3581,25 @@ impl BackgroundScanner {
log::trace!("containing git repository: {containing_git_repository:?}");
let global_gitignore_path = paths::global_gitignore_path();
self.state.lock().snapshot.global_gitignore =
if let Some(global_gitignore_path) = global_gitignore_path.as_ref() {
build_gitignore(global_gitignore_path, self.fs.as_ref())
let mut global_gitignore_events =
if let Some(global_gitignore_path) = &paths::global_gitignore_path() {
self.state.lock().snapshot.global_gitignore =
if self.fs.is_file(&global_gitignore_path).await {
build_gitignore(global_gitignore_path, self.fs.as_ref())
.await
.ok()
.map(Arc::new)
} else {
None
};
self.fs
.watch(global_gitignore_path, FS_WATCH_LATENCY)
.await
.ok()
.map(Arc::new)
.0
} else {
None
self.state.lock().snapshot.global_gitignore = None;
Box::pin(futures::stream::empty())
};
let mut global_gitignore_events = if let Some(global_gitignore_path) = global_gitignore_path
{
self.fs
.watch(&global_gitignore_path, FS_WATCH_LATENCY)
.await
.0
} else {
Box::pin(futures::stream::empty())
};
let (scan_job_tx, scan_job_rx) = channel::unbounded();
{
@ -3606,12 +3615,14 @@ impl BackgroundScanner {
root_entry.is_ignored = true;
state.insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref());
}
state.enqueue_scan_dir(
root_abs_path.as_path().into(),
&root_entry,
&scan_job_tx,
self.fs.as_ref(),
);
if root_entry.is_dir() {
state.enqueue_scan_dir(
root_abs_path.as_path().into(),
&root_entry,
&scan_job_tx,
self.fs.as_ref(),
);
}
}
};