WIP
This commit is contained in:
parent
ce5fbbb46b
commit
e19a56c366
2 changed files with 56 additions and 42 deletions
|
@ -27,7 +27,7 @@ unsafe impl<F> Send for EventStream<F> {}
|
|||
|
||||
impl<F> EventStream<F>
|
||||
where
|
||||
F: FnMut(&[Event]) -> bool,
|
||||
F: FnMut(Vec<Event>) -> bool,
|
||||
{
|
||||
pub fn new(paths: &[&Path], latency: Duration, callback: F) -> Self {
|
||||
unsafe {
|
||||
|
@ -128,7 +128,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if !callback(&events) {
|
||||
if !callback(events) {
|
||||
fs::FSEventStreamStop(stream_ref);
|
||||
cf::CFRunLoopStop(cf::CFRunLoopGetCurrent());
|
||||
}
|
||||
|
|
|
@ -620,7 +620,7 @@ impl BackgroundScanner {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn process_events(&self, events: &[fsevent::Event]) -> Result<bool> {
|
||||
fn process_events(&self, mut events: Vec<fsevent::Event>) -> Result<bool> {
|
||||
if self.notify.receiver_count() == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
@ -633,45 +633,40 @@ impl BackgroundScanner {
|
|||
root_inode: self.root_inode(),
|
||||
};
|
||||
let mut removed = HashSet::new();
|
||||
let mut paths = events.into_iter().map(|e| &*e.path).collect::<Vec<_>>();
|
||||
paths.sort_unstable();
|
||||
let mut observed = HashSet::new();
|
||||
|
||||
let (scan_queue_tx, scan_queue_rx) = crossbeam_channel::unbounded();
|
||||
let mut paths = paths.into_iter().peekable();
|
||||
|
||||
events.sort_unstable_by(|a, b| a.path.cmp(&b.path));
|
||||
let mut paths = events.into_iter().map(|e| e.path).peekable();
|
||||
while let Some(path) = paths.next() {
|
||||
let relative_path = path.strip_prefix(&root_path)?.to_path_buf();
|
||||
|
||||
// Don't scan descendants of this path.
|
||||
while paths.peek().map_or(false, |p| p.starts_with(path)) {
|
||||
paths.next();
|
||||
}
|
||||
|
||||
let mut stack = Vec::new();
|
||||
stack.extend(snapshot.inode_for_path(&relative_path));
|
||||
while let Some(inode) = stack.pop() {
|
||||
removed.insert(inode);
|
||||
if let Some(Entry::Dir { children, .. }) = snapshot.entries.get(&inode) {
|
||||
stack.extend(children.iter().copied())
|
||||
}
|
||||
}
|
||||
|
||||
match fs::metadata(path) {
|
||||
match fs::metadata(&path) {
|
||||
Ok(metadata) => {
|
||||
let inode = metadata.ino();
|
||||
let is_symlink = fs::symlink_metadata(path)?.file_type().is_symlink();
|
||||
let is_symlink = fs::symlink_metadata(&path)?.file_type().is_symlink();
|
||||
let name: Arc<OsStr> = Arc::from(path.file_name().unwrap_or(OsStr::new("/")));
|
||||
let mut ignore = IgnoreBuilder::new().build().add_parents(path).unwrap();
|
||||
let mut ignore = IgnoreBuilder::new().build().add_parents(&path).unwrap();
|
||||
if metadata.is_dir() {
|
||||
ignore = ignore.add_child(path).unwrap();
|
||||
ignore = ignore.add_child(&path).unwrap();
|
||||
}
|
||||
let is_ignored = ignore.matched(path, metadata.is_dir()).is_ignore();
|
||||
let is_ignored = ignore.matched(&path, metadata.is_dir()).is_ignore();
|
||||
let parent = if path == root_path {
|
||||
None
|
||||
} else {
|
||||
Some(fs::metadata(path.parent().unwrap())?.ino())
|
||||
};
|
||||
|
||||
removed.remove(&inode);
|
||||
let prev_entry = snapshot.entries.get(&inode);
|
||||
// If we haven't seen this inode yet, we are going to recursively scan it, so
|
||||
// ignore event involving a descendant.
|
||||
if prev_entry.is_none() {
|
||||
while paths.peek().map_or(false, |p| p.starts_with(&path)) {
|
||||
paths.next();
|
||||
}
|
||||
}
|
||||
|
||||
observed.insert(inode);
|
||||
if metadata.file_type().is_dir() {
|
||||
let is_ignored = is_ignored || name.as_ref() == ".git";
|
||||
let dir_entry = Entry::Dir {
|
||||
|
@ -707,7 +702,18 @@ impl BackgroundScanner {
|
|||
}
|
||||
}
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::NotFound {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
// Fill removed with the inodes of all descendants of this path.
|
||||
let mut stack = Vec::new();
|
||||
stack.extend(snapshot.inode_for_path(&relative_path));
|
||||
while let Some(inode) = stack.pop() {
|
||||
removed.insert(inode);
|
||||
if let Some(Entry::Dir { children, .. }) = snapshot.entries.get(&inode)
|
||||
{
|
||||
stack.extend(children.iter().copied())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow::Error::new(err));
|
||||
}
|
||||
}
|
||||
|
@ -735,10 +741,10 @@ impl BackgroundScanner {
|
|||
|
||||
for worker_inodes in scanned_inodes {
|
||||
for inode in worker_inodes? {
|
||||
removed.remove(&inode);
|
||||
remove_counts.remove(&inode);
|
||||
}
|
||||
}
|
||||
self.remove_entries(removed);
|
||||
self.remove_entries(remove_counts);
|
||||
|
||||
Ok(self.notify.receiver_count() != 0)
|
||||
}
|
||||
|
@ -943,9 +949,20 @@ mod tests {
|
|||
#[test]
|
||||
fn test_rescan() {
|
||||
App::test_async((), |mut app| async move {
|
||||
let dir2 = temp_tree(json!({
|
||||
"dir1": {
|
||||
"dir3": {
|
||||
"file": "contents",
|
||||
}
|
||||
},
|
||||
"dir2": {
|
||||
}
|
||||
}));
|
||||
let dir = temp_tree(json!({
|
||||
"dir1": {
|
||||
"file": "contents"
|
||||
"dir3": {
|
||||
"file": "contents",
|
||||
}
|
||||
},
|
||||
"dir2": {
|
||||
}
|
||||
|
@ -954,41 +971,38 @@ mod tests {
|
|||
let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx));
|
||||
assert_condition(1, 300, || app.read(|ctx| tree.read(ctx).file_count() == 1)).await;
|
||||
|
||||
let file_inode = app.read(|ctx| {
|
||||
let dir_inode = app.read(|ctx| {
|
||||
tree.read(ctx)
|
||||
.snapshot()
|
||||
.inode_for_path("dir1/file")
|
||||
.inode_for_path("dir1/dir3")
|
||||
.unwrap()
|
||||
});
|
||||
app.read(|ctx| {
|
||||
let tree = tree.read(ctx);
|
||||
assert_eq!(
|
||||
tree.path_for_inode(file_inode, false)
|
||||
tree.path_for_inode(dir_inode, false)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
"dir1/file"
|
||||
"dir1/dir3"
|
||||
);
|
||||
});
|
||||
|
||||
std::fs::rename(dir.path().join("dir1/file"), dir.path().join("dir2/file")).unwrap();
|
||||
std::fs::rename(dir2.path(), dir.path().join("foo")).unwrap();
|
||||
assert_condition(1, 300, || {
|
||||
app.read(|ctx| {
|
||||
let tree = tree.read(ctx);
|
||||
tree.path_for_inode(file_inode, false)
|
||||
tree.path_for_inode(dir_inode, false)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
== "dir2/file"
|
||||
== "dir2/dir3"
|
||||
})
|
||||
})
|
||||
.await;
|
||||
app.read(|ctx| {
|
||||
let tree = tree.read(ctx);
|
||||
assert_eq!(
|
||||
tree.snapshot().inode_for_path("dir2/file"),
|
||||
Some(file_inode)
|
||||
);
|
||||
assert_eq!(tree.snapshot().inode_for_path("dir2/dir3"), Some(dir_inode));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue