working_copy: in ignored directories, visit only already tracked paths

`.gitignores` in ignored directories should be ignored. Before this
commit, we would visit ignored directories like any others if there
were any ignored paths in them.

I've done a lot of preparation for this commit, but There's still a
bit of duplication between the new code and the existing code. I don't
mind improving it if anyone has suggestions. Otherwise I might end up
doing that when I get back to working on snapshotting tree-level
conflicts soon.

This fixes #1785.
This commit is contained in:
Martin von Zweigbergk 2023-07-26 14:10:51 -07:00 committed by Martin von Zweigbergk
parent bcba1c6682
commit 48b1a1c533
2 changed files with 54 additions and 14 deletions

View file

@ -20,6 +20,7 @@ use std::ffi::OsString;
use std::fs;
use std::fs::{File, Metadata, OpenOptions};
use std::io::{Read, Write};
use std::ops::Bound;
#[cfg(unix)]
use std::os::unix::fs::symlink;
#[cfg(unix)]
@ -680,19 +681,59 @@ impl TreeState {
}
if file_type.is_dir() {
// If the whole directory is ignored, skip it unless we're already tracking
// some file in it.
if git_ignore.matches_all_files_in(&path.to_internal_dir_string())
&& current_tree.path_value(&path).is_none()
{
if git_ignore.matches_all_files_in(&path.to_internal_dir_string()) {
// If the whole directory is ignored, visit only paths we're already
// tracking.
let tracked_paths = self
.file_states
.range((Bound::Excluded(&path), Bound::Unbounded))
.take_while(|(sub_path, _)| path.contains(sub_path))
.map(|(sub_path, file_state)| {
(sub_path.clone(), file_state.clone())
})
.collect_vec();
for (tracked_path, current_file_state) in tracked_paths {
if !matcher.matches(&tracked_path) {
continue;
}
let disk_path = tracked_path.to_fs_path(&self.working_copy_path);
let metadata = match disk_path.metadata() {
Ok(metadata) => metadata,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
continue;
}
Err(err) => {
return Err(SnapshotError::IoError {
message: format!(
"Failed to stat file {}",
disk_path.display()
),
err,
});
}
};
if let Some(new_file_state) = file_state(&metadata) {
deleted_files.remove(&tracked_path);
let update = self.get_updated_tree_value(
&tracked_path,
disk_path,
Some(&current_file_state),
&current_tree,
&new_file_state,
)?;
if let Some(tree_value) = update {
tree_builder.set(tracked_path.clone(), tree_value);
}
self.file_states.insert(tracked_path, new_file_state);
}
}
} else {
work.push(WorkItem {
dir: path,
disk_dir: entry.path(),
git_ignore: git_ignore.clone(),
});
}
} else if matcher.matches(&path) {
if let Some(progress) = progress {
progress(&path);

View file

@ -594,8 +594,7 @@ fn test_gitignores_in_ignored_dir(use_git: bool) {
locked_wc.finish(OperationId::from_hex("abc123")).unwrap();
let new_tree = test_workspace.snapshot();
// TODO(#1785): should be equal
assert_ne!(
assert_eq!(
new_tree.entries().collect_vec(),
tree2.entries().collect_vec()
);