Load .gitignore files from the Fs object so we can test this with a FakeFs
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
co-authored by
Max Brunsfeld
parent
dde782a006
commit
bd7bf82d18
+102
-31
@@ -11,7 +11,7 @@ use crate::{
|
||||
time::{self, ReplicaId},
|
||||
util::{Bias, TryFutureExt},
|
||||
};
|
||||
use ::ignore::gitignore::Gitignore;
|
||||
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::{Stream, StreamExt};
|
||||
pub use fuzzy::{match_paths, PathMatch};
|
||||
@@ -732,12 +732,15 @@ impl LocalWorktree {
|
||||
next_entry_id: Arc::new(next_entry_id),
|
||||
};
|
||||
if let Some(metadata) = metadata {
|
||||
snapshot.insert_entry(Entry::new(
|
||||
path.into(),
|
||||
&metadata,
|
||||
&snapshot.next_entry_id,
|
||||
snapshot.root_char_bag,
|
||||
));
|
||||
snapshot.insert_entry(
|
||||
Entry::new(
|
||||
path.into(),
|
||||
&metadata,
|
||||
&snapshot.next_entry_id,
|
||||
snapshot.root_char_bag,
|
||||
),
|
||||
fs.as_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
let (mut remote_id_tx, remote_id_rx) = watch::channel();
|
||||
@@ -1156,6 +1159,16 @@ impl LocalWorktree {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
|
||||
let contents = smol::block_on(fs.load(&abs_path))?;
|
||||
let parent = abs_path.parent().unwrap_or(Path::new("/"));
|
||||
let mut builder = GitignoreBuilder::new(parent);
|
||||
for line in contents.lines() {
|
||||
builder.add_line(Some(abs_path.into()), line)?;
|
||||
}
|
||||
Ok(builder.build()?)
|
||||
}
|
||||
|
||||
pub fn refresh_buffer(abs_path: PathBuf, fs: &Arc<dyn Fs>, cx: &mut ModelContext<Buffer>) {
|
||||
let fs = fs.clone();
|
||||
cx.spawn(|buffer, mut cx| async move {
|
||||
@@ -1578,16 +1591,24 @@ impl Snapshot {
|
||||
self.entry_for_path(path.as_ref()).map(|e| e.inode)
|
||||
}
|
||||
|
||||
fn insert_entry(&mut self, mut entry: Entry) -> Entry {
|
||||
fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs) -> Entry {
|
||||
println!("insert entry {:?}", entry.path);
|
||||
if !entry.is_dir() && entry.path.file_name() == Some(&GITIGNORE) {
|
||||
let (ignore, err) = Gitignore::new(self.abs_path.join(&entry.path));
|
||||
if let Some(err) = err {
|
||||
log::error!("error in ignore file {:?} - {:?}", &entry.path, err);
|
||||
let abs_path = self.abs_path.join(&entry.path);
|
||||
match build_gitignore(&abs_path, fs) {
|
||||
Ok(ignore) => {
|
||||
let ignore_dir_path = entry.path.parent().unwrap();
|
||||
self.ignores
|
||||
.insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id));
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"error loading .gitignore file {:?} - {:?}",
|
||||
&entry.path,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let ignore_dir_path = entry.path.parent().unwrap();
|
||||
self.ignores
|
||||
.insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id));
|
||||
}
|
||||
|
||||
self.reuse_entry_id(&mut entry);
|
||||
@@ -2206,13 +2227,16 @@ impl BackgroundScanner {
|
||||
|
||||
// If we find a .gitignore, add it to the stack of ignores used to determine which paths are ignored
|
||||
if child_name == *GITIGNORE {
|
||||
let (ignore, err) = Gitignore::new(&child_abs_path);
|
||||
if let Some(err) = err {
|
||||
log::error!("error in ignore file {:?} - {:?}", child_name, err);
|
||||
match build_gitignore(&child_abs_path, self.fs.as_ref()) {
|
||||
Ok(ignore) => {
|
||||
let ignore = Arc::new(ignore);
|
||||
ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
|
||||
new_ignore = Some(ignore);
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!("error loading .gitignore file {:?} - {:?}", child_name, error);
|
||||
}
|
||||
}
|
||||
let ignore = Arc::new(ignore);
|
||||
ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
|
||||
new_ignore = Some(ignore);
|
||||
|
||||
// Update ignore status of any child entries we've already processed to reflect the
|
||||
// ignore file in the current directory. Because `.gitignore` starts with a `.`,
|
||||
@@ -2321,7 +2345,7 @@ impl BackgroundScanner {
|
||||
snapshot.root_char_bag,
|
||||
);
|
||||
fs_entry.is_ignored = ignore_stack.is_all();
|
||||
snapshot.insert_entry(fs_entry);
|
||||
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
||||
if metadata.is_dir {
|
||||
scan_queue_tx
|
||||
.send(ScanJob {
|
||||
@@ -2490,7 +2514,7 @@ async fn refresh_entry(
|
||||
&next_entry_id,
|
||||
root_char_bag,
|
||||
);
|
||||
Ok(snapshot.lock().insert_entry(entry))
|
||||
Ok(snapshot.lock().insert_entry(entry, fs))
|
||||
}
|
||||
|
||||
fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
|
||||
@@ -2774,6 +2798,50 @@ mod tests {
|
||||
use std::time::UNIX_EPOCH;
|
||||
use std::{env, fmt::Write, os::unix, time::SystemTime};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_traversal(cx: gpui::TestAppContext) {
|
||||
let fs = FakeFs::new();
|
||||
fs.insert_tree(
|
||||
"/root",
|
||||
json!({
|
||||
".gitignore": "a/b\n",
|
||||
"a": {
|
||||
"b": "",
|
||||
"c": "",
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let tree = Worktree::open_local(
|
||||
rpc::Client::new(),
|
||||
Arc::from(Path::new("/root")),
|
||||
Arc::new(fs),
|
||||
Default::default(),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
|
||||
tree.read_with(&cx, |tree, cx| {
|
||||
dbg!(tree.entries_by_path.items(&()));
|
||||
|
||||
assert_eq!(
|
||||
tree.entries(false)
|
||||
.map(|entry| entry.path.as_ref())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
Path::new(""),
|
||||
Path::new(".gitignore"),
|
||||
Path::new("a"),
|
||||
Path::new("a/c"),
|
||||
]
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_populate_and_search(cx: gpui::TestAppContext) {
|
||||
let dir = temp_tree(json!({
|
||||
@@ -3260,14 +3328,17 @@ mod tests {
|
||||
root_char_bag: Default::default(),
|
||||
next_entry_id: next_entry_id.clone(),
|
||||
};
|
||||
initial_snapshot.insert_entry(Entry::new(
|
||||
Path::new("").into(),
|
||||
&smol::block_on(fs.metadata(root_dir.path()))
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
&next_entry_id,
|
||||
Default::default(),
|
||||
));
|
||||
initial_snapshot.insert_entry(
|
||||
Entry::new(
|
||||
Path::new("").into(),
|
||||
&smol::block_on(fs.metadata(root_dir.path()))
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
&next_entry_id,
|
||||
Default::default(),
|
||||
),
|
||||
fs.as_ref(),
|
||||
);
|
||||
let mut scanner = BackgroundScanner::new(
|
||||
Arc::new(Mutex::new(initial_snapshot.clone())),
|
||||
notify_tx,
|
||||
|
||||
Reference in New Issue
Block a user