Fix bug where git statuses would not be initialized on startup

move git status queries to be on entry creation

co-authored-by: max <max@zed.dev>
This commit is contained in:
Mikayla Maki 2023-06-02 17:38:39 -07:00
parent 2f97c7a4f1
commit ca077408d7
No known key found for this signature in database

View file

@ -1822,6 +1822,14 @@ impl LocalSnapshot {
self.git_repositories.get(&repo.work_directory.0) self.git_repositories.get(&repo.work_directory.0)
} }
pub(crate) fn local_repo_for_path(
&self,
path: &Path,
) -> Option<(RepositoryWorkDirectory, &LocalRepositoryEntry)> {
let (path, repo) = self.repository_and_work_directory_for_path(path)?;
Some((path, self.git_repositories.get(&repo.work_directory_id())?))
}
pub(crate) fn repo_for_metadata( pub(crate) fn repo_for_metadata(
&self, &self,
path: &Path, path: &Path,
@ -1997,6 +2005,8 @@ impl LocalSnapshot {
}, },
); );
self.scan_statuses(repo_lock.deref(), &work_directory);
drop(repo_lock); drop(repo_lock);
self.git_repositories.insert( self.git_repositories.insert(
@ -2016,10 +2026,12 @@ impl LocalSnapshot {
&mut self, &mut self,
repo_ptr: &dyn GitRepository, repo_ptr: &dyn GitRepository,
work_directory: &RepositoryWorkDirectory, work_directory: &RepositoryWorkDirectory,
path: &Path,
) { ) {
let mut edits = vec![]; let mut edits = vec![];
for mut entry in self.descendent_entries(false, false, path).cloned() { for mut entry in self
.descendent_entries(false, false, &work_directory.0)
.cloned()
{
let Ok(repo_path) = entry.path.strip_prefix(&work_directory.0) else { let Ok(repo_path) = entry.path.strip_prefix(&work_directory.0) else {
continue; continue;
}; };
@ -2754,6 +2766,7 @@ impl BackgroundScanner {
let mut state = self.state.lock(); let mut state = self.state.lock();
state.snapshot.completed_scan_id = state.snapshot.scan_id; state.snapshot.completed_scan_id = state.snapshot.scan_id;
} }
self.send_status_update(false, None); self.send_status_update(false, None);
// Process any any FS events that occurred while performing the initial scan. // Process any any FS events that occurred while performing the initial scan.
@ -2813,7 +2826,7 @@ impl BackgroundScanner {
if let Some(paths) = paths { if let Some(paths) = paths {
for path in paths { for path in paths {
self.reload_git_status(&path, &mut *snapshot, self.fs.as_ref()); self.reload_git_repo(&path, &mut *snapshot, self.fs.as_ref());
} }
} }
@ -2940,14 +2953,18 @@ impl BackgroundScanner {
let mut new_jobs: Vec<Option<ScanJob>> = Vec::new(); let mut new_jobs: Vec<Option<ScanJob>> = Vec::new();
let mut ignore_stack = job.ignore_stack.clone(); let mut ignore_stack = job.ignore_stack.clone();
let mut new_ignore = None; let mut new_ignore = None;
let (root_abs_path, root_char_bag, next_entry_id) = { let (root_abs_path, root_char_bag, next_entry_id, repository) = {
let snapshot = &self.state.lock().snapshot; let snapshot = &self.state.lock().snapshot;
( (
snapshot.abs_path().clone(), snapshot.abs_path().clone(),
snapshot.root_char_bag, snapshot.root_char_bag,
self.next_entry_id.clone(), self.next_entry_id.clone(),
snapshot
.local_repo_for_path(&job.path)
.map(|(work_dir, repo)| (work_dir, repo.clone())),
) )
}; };
let mut child_paths = self.fs.read_dir(&job.abs_path).await?; let mut child_paths = self.fs.read_dir(&job.abs_path).await?;
while let Some(child_abs_path) = child_paths.next().await { while let Some(child_abs_path) = child_paths.next().await {
let child_abs_path: Arc<Path> = match child_abs_path { let child_abs_path: Arc<Path> = match child_abs_path {
@ -3040,6 +3057,13 @@ impl BackgroundScanner {
} }
} else { } else {
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false); child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
if let Some((repo_path, repo)) = &repository {
if let Ok(path) = child_path.strip_prefix(&repo_path.0) {
child_entry.git_status =
repo.repo_ptr.lock().status(&RepoPath(path.into()));
}
}
} }
new_entries.push(child_entry); new_entries.push(child_entry);
@ -3117,6 +3141,7 @@ impl BackgroundScanner {
let ignore_stack = state let ignore_stack = state
.snapshot .snapshot
.ignore_stack_for_abs_path(&abs_path, metadata.is_dir); .ignore_stack_for_abs_path(&abs_path, metadata.is_dir);
let mut fs_entry = Entry::new( let mut fs_entry = Entry::new(
path.clone(), path.clone(),
&metadata, &metadata,
@ -3124,6 +3149,16 @@ impl BackgroundScanner {
state.snapshot.root_char_bag, state.snapshot.root_char_bag,
); );
fs_entry.is_ignored = ignore_stack.is_all(); fs_entry.is_ignored = ignore_stack.is_all();
if !fs_entry.is_dir() {
if let Some((work_dir, repo)) = state.snapshot.local_repo_for_path(&path) {
if let Ok(path) = path.strip_prefix(work_dir.0) {
fs_entry.git_status =
repo.repo_ptr.lock().status(&RepoPath(path.into()))
}
}
}
state.insert_entry(fs_entry, self.fs.as_ref()); state.insert_entry(fs_entry, self.fs.as_ref());
if let Some(scan_queue_tx) = &scan_queue_tx { if let Some(scan_queue_tx) = &scan_queue_tx {
@ -3183,7 +3218,7 @@ impl BackgroundScanner {
Some(()) Some(())
} }
fn reload_git_status( fn reload_git_repo(
&self, &self,
path: &Path, path: &Path,
snapshot: &mut LocalSnapshot, snapshot: &mut LocalSnapshot,
@ -3230,32 +3265,7 @@ impl BackgroundScanner {
entry.branch = branch.map(Into::into); entry.branch = branch.map(Into::into);
}); });
snapshot.scan_statuses(repo.deref(), &work_dir, &work_dir.0); snapshot.scan_statuses(repo.deref(), &work_dir);
} else {
if snapshot
.entry_for_path(&path)
.map(|entry| entry.is_ignored)
.unwrap_or(false)
{
return None;
}
let repo = snapshot.repository_for_path(&path)?;
let work_directory = &repo.work_directory(snapshot)?;
let work_dir_id = repo.work_directory.clone();
let (local_repo, git_dir_scan_id) =
snapshot.git_repositories.update(&work_dir_id, |entry| {
(entry.repo_ptr.clone(), entry.git_dir_scan_id)
})?;
// Short circuit if we've already scanned everything
if git_dir_scan_id == scan_id {
return None;
}
let repo_ptr = local_repo.lock();
snapshot.scan_statuses(repo_ptr.deref(), &work_directory, path);
} }
Some(()) Some(())
@ -5270,6 +5280,15 @@ mod tests {
) )
.await; .await;
fs.set_status_for_repo(
&Path::new("/root/.git"),
&[
(Path::new("a/b/c1.txt"), GitFileStatus::Added),
(Path::new("a/d/e2.txt"), GitFileStatus::Modified),
(Path::new("g/h2.txt"), GitFileStatus::Conflict),
],
);
let http_client = FakeHttpClient::with_404_response(); let http_client = FakeHttpClient::with_404_response();
let client = cx.read(|cx| Client::new(http_client, cx)); let client = cx.read(|cx| Client::new(http_client, cx));
let tree = Worktree::local( let tree = Worktree::local(
@ -5285,17 +5304,6 @@ mod tests {
cx.foreground().run_until_parked(); cx.foreground().run_until_parked();
fs.set_status_for_repo(
&Path::new("/root/.git"),
&[
(Path::new("a/b/c1.txt"), GitFileStatus::Added),
(Path::new("a/d/e2.txt"), GitFileStatus::Modified),
(Path::new("g/h2.txt"), GitFileStatus::Conflict),
],
);
cx.foreground().run_until_parked();
let snapshot = tree.read_with(cx, |tree, _| tree.snapshot()); let snapshot = tree.read_with(cx, |tree, _| tree.snapshot());
assert_eq!( assert_eq!(