From 2759ed4d006bb46c50ce1df00f5b5a3fd3acdefb Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 17 Nov 2023 14:30:07 +0200 Subject: [PATCH] An attempt to ignore git regularly --- crates/project/src/worktree.rs | 71 ++++++++++++++++------------ crates/project/src/worktree_tests.rs | 15 ++++++ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index aa6341f330..a169e062f3 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -2464,14 +2464,17 @@ impl BackgroundScannerState { // Remove any git repositories whose .git entry no longer exists. let snapshot = &mut self.snapshot; + // TODO kb stop cleaning those up here? let mut repositories = mem::take(&mut snapshot.git_repositories); let mut repository_entries = mem::take(&mut snapshot.repository_entries); - repositories.retain(|work_directory_id, _| { - snapshot - .entry_for_id(*work_directory_id) - .map_or(false, |entry| { - snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some() - }) + repositories.retain(|_, entry| { + // TODO kb use fs + snapshot.abs_path().join(&entry.git_dir_path).exists() + // snapshot + // .entry_for_id(*work_directory_id) + // .map_or(false, |entry| { + // snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some() + // }) }); repository_entries.retain(|_, entry| repositories.get(&entry.work_directory.0).is_some()); snapshot.git_repositories = repositories; @@ -3322,11 +3325,11 @@ impl BackgroundScanner { .entry_for_path(parent) .map_or(false, |entry| entry.kind == EntryKind::Dir) }); - if !parent_dir_is_loaded { + if !parent_dir_is_loaded && !is_git_related(&abs_path) { log::debug!("ignoring event {relative_path:?} within unloaded directory"); return false; } - if snapshot.is_abs_path_excluded(abs_path) { + if snapshot.is_abs_path_excluded(abs_path) && !is_git_related(&abs_path) { log::debug!( "ignoring FS event for path {relative_path:?} within excluded directory" ); @@ -3502,7 +3505,6 @@ impl BackgroundScanner { let state = self.state.lock(); let snapshot = &state.snapshot; root_abs_path = snapshot.abs_path().clone(); - // TODO kb we need `DOT_GIT` and `GITIGNORE` entries always processed. if snapshot.is_abs_path_excluded(&job.abs_path) { log::error!("skipping excluded directory {:?}", job.path); return Ok(()); @@ -3529,27 +3531,7 @@ impl BackgroundScanner { } }; let child_name = child_abs_path.file_name().unwrap(); - { - let mut state = self.state.lock(); - if state.snapshot.is_abs_path_excluded(&child_abs_path) { - let relative_path = job.path.join(child_name); - log::debug!("skipping excluded child entry {relative_path:?}"); - state.remove_path(&relative_path); - continue; - } - drop(state); - } - let child_path: Arc = job.path.join(child_name).into(); - let child_metadata = match self.fs.metadata(&child_abs_path).await { - Ok(Some(metadata)) => metadata, - Ok(None) => continue, - Err(err) => { - log::error!("error processing {:?}: {:?}", child_abs_path, err); - continue; - } - }; - // If we find a .gitignore, add it to the stack of ignores used to determine which paths are ignored if child_name == *GITIGNORE { match build_gitignore(&child_abs_path, self.fs.as_ref()).await { @@ -3591,8 +3573,33 @@ impl BackgroundScanner { // If we find a .git, we'll need to load the repository. else if child_name == *DOT_GIT { dotgit_path = Some(child_path.clone()); + { + let mut state = self.state.lock(); + state.build_git_repository(child_path.clone(), self.fs.as_ref()); + drop(state); + } } + { + let mut state = self.state.lock(); + if state.snapshot.is_abs_path_excluded(&child_abs_path) { + let relative_path = job.path.join(child_name); + log::debug!("skipping excluded child entry {relative_path:?}"); + state.remove_path(&relative_path); + continue; + } + drop(state); + } + + let child_metadata = match self.fs.metadata(&child_abs_path).await { + Ok(Some(metadata)) => metadata, + Ok(None) => continue, + Err(err) => { + log::error!("error processing {:?}: {:?}", child_abs_path, err); + continue; + } + }; + let mut child_entry = Entry::new( child_path.clone(), &child_metadata, @@ -4117,6 +4124,12 @@ impl BackgroundScanner { } } +fn is_git_related(abs_path: &&PathBuf) -> bool { + abs_path + .components() + .any(|c| c.as_os_str() == *DOT_GIT || c.as_os_str() == *GITIGNORE) +} + fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag { let mut result = root_char_bag; result.extend( diff --git a/crates/project/src/worktree_tests.rs b/crates/project/src/worktree_tests.rs index f2b519021c..22a5cc1e01 100644 --- a/crates/project/src/worktree_tests.rs +++ b/crates/project/src/worktree_tests.rs @@ -731,6 +731,13 @@ async fn test_dirs_no_longer_ignored(cx: &mut TestAppContext) { #[gpui::test(iterations = 10)] async fn test_rescan_with_gitignore(cx: &mut TestAppContext) { init_test(cx); + cx.update(|cx| { + cx.update_global::(|store, cx| { + store.update_user_settings::(cx, |project_settings| { + project_settings.file_scan_exclusions = Some(Vec::new()); + }); + }); + }); let fs = FakeFs::new(cx.background()); fs.insert_tree( "/root", @@ -1860,6 +1867,14 @@ async fn test_git_repository_for_path(cx: &mut TestAppContext) { #[gpui::test] async fn test_git_status(deterministic: Arc, cx: &mut TestAppContext) { init_test(cx); + cx.update(|cx| { + cx.update_global::(|store, cx| { + store.update_user_settings::(cx, |project_settings| { + project_settings.file_scan_exclusions = + Some(vec!["**/.git".to_string(), "**/.gitignore".to_string()]); + }); + }); + }); const IGNORE_RULE: &'static str = "**/target"; let root = temp_tree(json!({