From f50240181a669f2359c0f35722b3e6737c40881a Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 16 May 2023 13:00:39 -0400 Subject: [PATCH 1/2] Avoid removing fake fs entry when rename fails later in the process Co-Authored-By: Antonio Scandurra --- crates/fs/src/fs.rs | 21 +++++++++++++++++---- crates/project/src/worktree.rs | 11 +++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index 3285eb328a..99562405b5 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -572,15 +572,15 @@ impl FakeFs { Ok(()) } - pub async fn pause_events(&self) { + pub fn pause_events(&self) { self.state.lock().events_paused = true; } - pub async fn buffered_event_count(&self) -> usize { + pub fn buffered_event_count(&self) -> usize { self.state.lock().buffered_events.len() } - pub async fn flush_events(&self, count: usize) { + pub fn flush_events(&self, count: usize) { self.state.lock().flush_events(count); } @@ -832,14 +832,16 @@ impl Fs for FakeFs { let old_path = normalize_path(old_path); let new_path = normalize_path(new_path); + let mut state = self.state.lock(); let moved_entry = state.write_path(&old_path, |e| { if let btree_map::Entry::Occupied(e) = e { - Ok(e.remove()) + Ok(e.get().clone()) } else { Err(anyhow!("path does not exist: {}", &old_path.display())) } })?; + state.write_path(&new_path, |e| { match e { btree_map::Entry::Occupied(mut e) => { @@ -855,6 +857,17 @@ impl Fs for FakeFs { } Ok(()) })?; + + state + .write_path(&old_path, |e| { + if let btree_map::Entry::Occupied(e) = e { + Ok(e.remove()) + } else { + unreachable!() + } + }) + .unwrap(); + state.emit_event(&[old_path, new_path]); Ok(()) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index cc16ed91b8..958e72fa18 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -4632,6 +4632,7 @@ mod tests { .detach(); }); + fs.as_fake().pause_events(); let mut snapshots = Vec::new(); let mut mutations_len = operations; while mutations_len > 1 { @@ -4641,16 +4642,16 @@ mod tests { randomly_mutate_worktree(worktree, &mut rng, cx) }) .await - .unwrap(); + .log_err(); } else { randomly_mutate_fs(&fs, root_dir, 1.0, &mut rng).await; } - let buffered_event_count = fs.as_fake().buffered_event_count().await; + let buffered_event_count = fs.as_fake().buffered_event_count(); if buffered_event_count > 0 && rng.gen_bool(0.3) { let len = rng.gen_range(0..=buffered_event_count); log::info!("flushing {} events", len); - fs.as_fake().flush_events(len).await; + fs.as_fake().flush_events(len); } else { randomly_mutate_fs(&fs, root_dir, 0.6, &mut rng).await; mutations_len -= 1; @@ -4666,7 +4667,7 @@ mod tests { } log::info!("quiescing"); - fs.as_fake().flush_events(usize::MAX).await; + fs.as_fake().flush_events(usize::MAX); cx.foreground().run_until_parked(); let snapshot = worktree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot()); snapshot.check_invariants(); @@ -4726,6 +4727,7 @@ mod tests { rng: &mut impl Rng, cx: &mut ModelContext, ) -> Task> { + log::info!("mutating worktree"); let worktree = worktree.as_local_mut().unwrap(); let snapshot = worktree.snapshot(); let entry = snapshot.entries(false).choose(rng).unwrap(); @@ -4787,6 +4789,7 @@ mod tests { insertion_probability: f64, rng: &mut impl Rng, ) { + log::info!("mutating fs"); let mut files = Vec::new(); let mut dirs = Vec::new(); for path in fs.as_fake().paths() { From 8b63caa0bd6bc57d837bf9a52f5c0d70c0c92513 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 16 May 2023 13:01:29 -0400 Subject: [PATCH 2/2] Fix worktree refresh request causing gitignore to not update Co-Authored-By: Antonio Scandurra --- crates/project/src/worktree.rs | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 958e72fa18..403d893425 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -338,7 +338,7 @@ impl<'a> From for WorkDirectoryEntry { #[derive(Debug, Clone)] pub struct LocalSnapshot { - ignores_by_parent_abs_path: HashMap, (Arc, usize)>, + ignores_by_parent_abs_path: HashMap, (Arc, bool)>, // (gitignore, needs_update) // The ProjectEntryId corresponds to the entry for the .git dir // work_directory_id git_repositories: TreeMap, @@ -1882,10 +1882,8 @@ impl LocalSnapshot { let abs_path = self.abs_path.join(&entry.path); match smol::block_on(build_gitignore(&abs_path, fs)) { Ok(ignore) => { - self.ignores_by_parent_abs_path.insert( - abs_path.parent().unwrap().into(), - (Arc::new(ignore), self.scan_id), - ); + self.ignores_by_parent_abs_path + .insert(abs_path.parent().unwrap().into(), (Arc::new(ignore), true)); } Err(error) => { log::error!( @@ -1955,10 +1953,8 @@ impl LocalSnapshot { } if let Some(ignore) = ignore { - self.ignores_by_parent_abs_path.insert( - self.abs_path.join(&parent_path).into(), - (ignore, self.scan_id), - ); + self.ignores_by_parent_abs_path + .insert(self.abs_path.join(&parent_path).into(), (ignore, false)); } if parent_path.file_name() == Some(&DOT_GIT) { @@ -2062,11 +2058,11 @@ impl LocalSnapshot { if path.file_name() == Some(&GITIGNORE) { let abs_parent_path = self.abs_path.join(path.parent().unwrap()); - if let Some((_, scan_id)) = self + if let Some((_, needs_update)) = self .ignores_by_parent_abs_path .get_mut(abs_parent_path.as_path()) { - *scan_id = self.snapshot.scan_id; + *needs_update = true; } } } @@ -2609,7 +2605,7 @@ impl BackgroundScanner { self.snapshot .lock() .ignores_by_parent_abs_path - .insert(ancestor.into(), (ignore.into(), 0)); + .insert(ancestor.into(), (ignore.into(), false)); } } { @@ -2662,7 +2658,7 @@ impl BackgroundScanner { // these before handling changes reported by the filesystem. request = self.refresh_requests_rx.recv().fuse() => { let Ok((paths, barrier)) = request else { break }; - if !self.process_refresh_request(paths, barrier).await { + if !self.process_refresh_request(paths.clone(), barrier).await { return; } } @@ -2673,7 +2669,7 @@ impl BackgroundScanner { while let Poll::Ready(Some(more_events)) = futures::poll!(events_rx.next()) { paths.extend(more_events.into_iter().map(|e| e.path)); } - self.process_events(paths).await; + self.process_events(paths.clone()).await; } } } @@ -3181,16 +3177,18 @@ impl BackgroundScanner { let mut snapshot = self.snapshot.lock().clone(); let mut ignores_to_update = Vec::new(); let mut ignores_to_delete = Vec::new(); - for (parent_abs_path, (_, scan_id)) in &snapshot.ignores_by_parent_abs_path { - if let Ok(parent_path) = parent_abs_path.strip_prefix(&snapshot.abs_path) { - if *scan_id > snapshot.completed_scan_id - && snapshot.entry_for_path(parent_path).is_some() - { - ignores_to_update.push(parent_abs_path.clone()); + let abs_path = snapshot.abs_path.clone(); + for (parent_abs_path, (_, needs_update)) in &mut snapshot.ignores_by_parent_abs_path { + if let Ok(parent_path) = parent_abs_path.strip_prefix(&abs_path) { + if *needs_update { + *needs_update = false; + if snapshot.snapshot.entry_for_path(parent_path).is_some() { + ignores_to_update.push(parent_abs_path.clone()); + } } let ignore_path = parent_path.join(&*GITIGNORE); - if snapshot.entry_for_path(ignore_path).is_none() { + if snapshot.snapshot.entry_for_path(ignore_path).is_none() { ignores_to_delete.push(parent_abs_path.clone()); } }