Fix the bugs
This commit is contained in:
parent
126e4cce8f
commit
b8be720490
3 changed files with 50 additions and 69 deletions
|
@ -1,5 +1,5 @@
|
||||||
use ignore::gitignore::Gitignore;
|
use ignore::gitignore::Gitignore;
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{ffi::OsStr, path::Path, sync::Arc};
|
||||||
|
|
||||||
pub enum IgnoreStack {
|
pub enum IgnoreStack {
|
||||||
None,
|
None,
|
||||||
|
@ -30,4 +30,23 @@ impl IgnoreStack {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_abs_path_ignored(&self, abs_path: &Path, is_dir: bool) -> bool {
|
||||||
|
if is_dir && abs_path.file_name() == Some(OsStr::new(".git")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
match self {
|
||||||
|
Self::None => false,
|
||||||
|
Self::All => true,
|
||||||
|
Self::Some {
|
||||||
|
abs_base_path,
|
||||||
|
ignore,
|
||||||
|
parent: prev,
|
||||||
|
} => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) {
|
||||||
|
ignore::Match::None => prev.is_abs_path_ignored(abs_path, is_dir),
|
||||||
|
ignore::Match::Ignore(_) => true,
|
||||||
|
ignore::Match::Whitelist(_) => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct ProjectSettings {
|
||||||
pub git: GitSettings,
|
pub git: GitSettings,
|
||||||
// TODO kb better names and docs and tests
|
// TODO kb better names and docs and tests
|
||||||
// TODO kb how to react on their changes?
|
// TODO kb how to react on their changes?
|
||||||
|
// TODO kb /something/node_modules/ does not match `"**/node_modules/**"` glob!!!
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub scan_exclude_files: Vec<String>,
|
pub scan_exclude_files: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2060,7 +2060,7 @@ impl LocalSnapshot {
|
||||||
|
|
||||||
let mut ignore_stack = IgnoreStack::none();
|
let mut ignore_stack = IgnoreStack::none();
|
||||||
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
|
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
|
||||||
if !self.is_abs_path_ignored(parent_abs_path, &ignore_stack, true) {
|
if !ignore_stack.is_abs_path_ignored(parent_abs_path, true) {
|
||||||
ignore_stack = IgnoreStack::all();
|
ignore_stack = IgnoreStack::all();
|
||||||
break;
|
break;
|
||||||
} else if let Some(ignore) = ignore {
|
} else if let Some(ignore) = ignore {
|
||||||
|
@ -2068,7 +2068,7 @@ impl LocalSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_abs_path_ignored(abs_path, &ignore_stack, is_dir) {
|
if !ignore_stack.is_abs_path_ignored(abs_path, is_dir) {
|
||||||
ignore_stack = IgnoreStack::all();
|
ignore_stack = IgnoreStack::all();
|
||||||
}
|
}
|
||||||
ignore_stack
|
ignore_stack
|
||||||
|
@ -2164,41 +2164,16 @@ impl LocalSnapshot {
|
||||||
paths
|
paths
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_abs_path_ignored(
|
fn is_abs_path_excluded(&self, abs_path: &Path) -> bool {
|
||||||
&self,
|
self.scan_exclude_files
|
||||||
abs_path: &Path,
|
|
||||||
ignore_stack: &IgnoreStack,
|
|
||||||
is_dir: bool,
|
|
||||||
) -> bool {
|
|
||||||
if self
|
|
||||||
.scan_exclude_files
|
|
||||||
.iter()
|
.iter()
|
||||||
.any(|exclude_matcher| exclude_matcher.is_match(abs_path))
|
.any(|exclude_matcher| exclude_matcher.is_match(abs_path))
|
||||||
{
|
|
||||||
return true;
|
|
||||||
} else if is_dir && abs_path.file_name() == Some(OsStr::new(".git")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
match ignore_stack {
|
|
||||||
IgnoreStack::None => false,
|
|
||||||
IgnoreStack::All => true,
|
|
||||||
IgnoreStack::Some {
|
|
||||||
abs_base_path,
|
|
||||||
ignore,
|
|
||||||
parent: prev,
|
|
||||||
} => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) {
|
|
||||||
ignore::Match::None => self.is_abs_path_ignored(abs_path, &prev, is_dir),
|
|
||||||
ignore::Match::Ignore(_) => true,
|
|
||||||
ignore::Match::Whitelist(_) => false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackgroundScannerState {
|
impl BackgroundScannerState {
|
||||||
fn should_scan_directory(&self, entry: &Entry) -> bool {
|
fn should_scan_directory(&self, entry: &Entry, entry_abs_path: &Path) -> bool {
|
||||||
!entry.is_external
|
!entry.is_external && !self.snapshot.is_abs_path_excluded(entry_abs_path)
|
||||||
|| entry.path.file_name() == Some(&*DOT_GIT)
|
|| entry.path.file_name() == Some(&*DOT_GIT)
|
||||||
|| self.scanned_dirs.contains(&entry.id) // If we've ever scanned it, keep scanning
|
|| self.scanned_dirs.contains(&entry.id) // If we've ever scanned it, keep scanning
|
||||||
|| self
|
|| self
|
||||||
|
@ -2216,13 +2191,17 @@ impl BackgroundScannerState {
|
||||||
let ignore_stack = self.snapshot.ignore_stack_for_abs_path(&abs_path, true);
|
let ignore_stack = self.snapshot.ignore_stack_for_abs_path(&abs_path, true);
|
||||||
let mut ancestor_inodes = self.snapshot.ancestor_inodes_for_path(&path);
|
let mut ancestor_inodes = self.snapshot.ancestor_inodes_for_path(&path);
|
||||||
let mut containing_repository = None;
|
let mut containing_repository = None;
|
||||||
if let Some((workdir_path, repo)) = self.snapshot.local_repo_for_path(&path) {
|
if !matches!(ignore_stack.as_ref(), &IgnoreStack::All)
|
||||||
if let Ok(repo_path) = path.strip_prefix(&workdir_path.0) {
|
&& !self.snapshot.is_abs_path_excluded(&abs_path)
|
||||||
containing_repository = Some((
|
{
|
||||||
workdir_path,
|
if let Some((workdir_path, repo)) = self.snapshot.local_repo_for_path(&path) {
|
||||||
repo.repo_ptr.clone(),
|
if let Ok(repo_path) = path.strip_prefix(&workdir_path.0) {
|
||||||
repo.repo_ptr.lock().staged_statuses(repo_path),
|
containing_repository = Some((
|
||||||
));
|
workdir_path,
|
||||||
|
repo.repo_ptr.clone(),
|
||||||
|
repo.repo_ptr.lock().staged_statuses(repo_path),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ancestor_inodes.contains(&entry.inode) {
|
if !ancestor_inodes.contains(&entry.inode) {
|
||||||
|
@ -3140,10 +3119,7 @@ impl BackgroundScanner {
|
||||||
let ignore_stack = state
|
let ignore_stack = state
|
||||||
.snapshot
|
.snapshot
|
||||||
.ignore_stack_for_abs_path(&root_abs_path, true);
|
.ignore_stack_for_abs_path(&root_abs_path, true);
|
||||||
if state
|
if ignore_stack.is_abs_path_ignored(&root_abs_path, true) {
|
||||||
.snapshot
|
|
||||||
.is_abs_path_ignored(&root_abs_path, &ignore_stack, true)
|
|
||||||
{
|
|
||||||
root_entry.is_ignored = true;
|
root_entry.is_ignored = true;
|
||||||
state.insert_entry(root_entry.clone(), self.fs.as_ref());
|
state.insert_entry(root_entry.clone(), self.fs.as_ref());
|
||||||
}
|
}
|
||||||
|
@ -3513,7 +3489,7 @@ impl BackgroundScanner {
|
||||||
for entry in &mut new_entries {
|
for entry in &mut new_entries {
|
||||||
let entry_abs_path = root_abs_path.join(&entry.path);
|
let entry_abs_path = root_abs_path.join(&entry.path);
|
||||||
entry.is_ignored =
|
entry.is_ignored =
|
||||||
self.is_abs_path_ignored(&entry_abs_path, &ignore_stack, entry.is_dir());
|
ignore_stack.is_abs_path_ignored(&entry_abs_path, entry.is_dir());
|
||||||
|
|
||||||
if entry.is_dir() {
|
if entry.is_dir() {
|
||||||
if let Some(job) = new_jobs.next().expect("missing scan job for entry") {
|
if let Some(job) = new_jobs.next().expect("missing scan job for entry") {
|
||||||
|
@ -3572,8 +3548,7 @@ impl BackgroundScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
if child_entry.is_dir() {
|
if child_entry.is_dir() {
|
||||||
child_entry.is_ignored =
|
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true);
|
||||||
self.is_abs_path_ignored(&child_abs_path, &ignore_stack, true);
|
|
||||||
|
|
||||||
// Avoid recursing until crash in the case of a recursive symlink
|
// Avoid recursing until crash in the case of a recursive symlink
|
||||||
if !job.ancestor_inodes.contains(&child_entry.inode) {
|
if !job.ancestor_inodes.contains(&child_entry.inode) {
|
||||||
|
@ -3597,8 +3572,7 @@ impl BackgroundScanner {
|
||||||
new_jobs.push(None);
|
new_jobs.push(None);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
child_entry.is_ignored =
|
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
|
||||||
self.is_abs_path_ignored(&child_abs_path, &ignore_stack, false);
|
|
||||||
if let Some((repository_dir, repository, staged_statuses)) =
|
if let Some((repository_dir, repository, staged_statuses)) =
|
||||||
&job.containing_repository
|
&job.containing_repository
|
||||||
{
|
{
|
||||||
|
@ -3624,7 +3598,7 @@ impl BackgroundScanner {
|
||||||
for entry in &mut new_entries {
|
for entry in &mut new_entries {
|
||||||
state.reuse_entry_id(entry);
|
state.reuse_entry_id(entry);
|
||||||
if entry.is_dir() {
|
if entry.is_dir() {
|
||||||
if state.should_scan_directory(&entry) {
|
if state.should_scan_directory(&entry, &job.path.join(&entry.path)) {
|
||||||
job_ix += 1;
|
job_ix += 1;
|
||||||
} else {
|
} else {
|
||||||
log::debug!("defer scanning directory {:?}", entry.path);
|
log::debug!("defer scanning directory {:?}", entry.path);
|
||||||
|
@ -3712,13 +3686,12 @@ impl BackgroundScanner {
|
||||||
state.snapshot.root_char_bag,
|
state.snapshot.root_char_bag,
|
||||||
);
|
);
|
||||||
let is_dir = fs_entry.is_dir();
|
let is_dir = fs_entry.is_dir();
|
||||||
fs_entry.is_ignored =
|
fs_entry.is_ignored = ignore_stack.is_abs_path_ignored(&abs_path, is_dir);
|
||||||
state
|
|
||||||
.snapshot
|
|
||||||
.is_abs_path_ignored(&abs_path, &ignore_stack, is_dir);
|
|
||||||
fs_entry.is_external = !canonical_path.starts_with(&root_canonical_path);
|
fs_entry.is_external = !canonical_path.starts_with(&root_canonical_path);
|
||||||
|
|
||||||
if !is_dir {
|
if !is_dir
|
||||||
|
&& !(fs_entry.is_ignored || state.snapshot.is_abs_path_excluded(&abs_path))
|
||||||
|
{
|
||||||
if let Some((work_dir, repo)) = state.snapshot.local_repo_for_path(&path) {
|
if let Some((work_dir, repo)) = state.snapshot.local_repo_for_path(&path) {
|
||||||
if let Ok(repo_path) = path.strip_prefix(work_dir.0) {
|
if let Ok(repo_path) = path.strip_prefix(work_dir.0) {
|
||||||
let repo_path = RepoPath(repo_path.into());
|
let repo_path = RepoPath(repo_path.into());
|
||||||
|
@ -3729,7 +3702,7 @@ impl BackgroundScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Some(scan_queue_tx), true) = (&scan_queue_tx, fs_entry.is_dir()) {
|
if let (Some(scan_queue_tx), true) = (&scan_queue_tx, fs_entry.is_dir()) {
|
||||||
if state.should_scan_directory(&fs_entry) {
|
if state.should_scan_directory(&fs_entry, &abs_path) {
|
||||||
state.enqueue_scan_dir(abs_path, &fs_entry, scan_queue_tx);
|
state.enqueue_scan_dir(abs_path, &fs_entry, scan_queue_tx);
|
||||||
} else {
|
} else {
|
||||||
fs_entry.kind = EntryKind::UnloadedDir;
|
fs_entry.kind = EntryKind::UnloadedDir;
|
||||||
|
@ -3874,7 +3847,7 @@ impl BackgroundScanner {
|
||||||
for mut entry in snapshot.child_entries(path).cloned() {
|
for mut entry in snapshot.child_entries(path).cloned() {
|
||||||
let was_ignored = entry.is_ignored;
|
let was_ignored = entry.is_ignored;
|
||||||
let abs_path: Arc<Path> = snapshot.abs_path().join(&entry.path).into();
|
let abs_path: Arc<Path> = snapshot.abs_path().join(&entry.path).into();
|
||||||
entry.is_ignored = self.is_abs_path_ignored(&abs_path, &ignore_stack, entry.is_dir());
|
entry.is_ignored = ignore_stack.is_abs_path_ignored(&abs_path, entry.is_dir());
|
||||||
if entry.is_dir() {
|
if entry.is_dir() {
|
||||||
let child_ignore_stack = if entry.is_ignored {
|
let child_ignore_stack = if entry.is_ignored {
|
||||||
IgnoreStack::all()
|
IgnoreStack::all()
|
||||||
|
@ -3885,7 +3858,7 @@ impl BackgroundScanner {
|
||||||
// Scan any directories that were previously ignored and weren't previously scanned.
|
// Scan any directories that were previously ignored and weren't previously scanned.
|
||||||
if was_ignored && !entry.is_ignored && entry.kind.is_unloaded() {
|
if was_ignored && !entry.is_ignored && entry.kind.is_unloaded() {
|
||||||
let state = self.state.lock();
|
let state = self.state.lock();
|
||||||
if state.should_scan_directory(&entry) {
|
if state.should_scan_directory(&entry, &abs_path) {
|
||||||
state.enqueue_scan_dir(abs_path.clone(), &entry, &job.scan_queue);
|
state.enqueue_scan_dir(abs_path.clone(), &entry, &job.scan_queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4056,18 +4029,6 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
smol::Timer::after(Duration::from_millis(100)).await;
|
smol::Timer::after(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_abs_path_ignored(
|
|
||||||
&self,
|
|
||||||
abs_path: &Path,
|
|
||||||
ignore_stack: &IgnoreStack,
|
|
||||||
is_dir: bool,
|
|
||||||
) -> bool {
|
|
||||||
self.state
|
|
||||||
.lock()
|
|
||||||
.snapshot
|
|
||||||
.is_abs_path_ignored(abs_path, ignore_stack, is_dir)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
|
fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue