Track git status changes with the changed_paths system
This commit is contained in:
parent
ca077408d7
commit
e56fcd69b5
2 changed files with 83 additions and 45 deletions
|
@ -1974,7 +1974,8 @@ impl LocalSnapshot {
|
||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_repo(&mut self, parent_path: Arc<Path>, fs: &dyn Fs) -> Option<()> {
|
#[must_use = "Changed paths must be used for diffing later"]
|
||||||
|
fn build_repo(&mut self, parent_path: Arc<Path>, fs: &dyn Fs) -> Option<Vec<Arc<Path>>> {
|
||||||
let abs_path = self.abs_path.join(&parent_path);
|
let abs_path = self.abs_path.join(&parent_path);
|
||||||
let work_dir: Arc<Path> = parent_path.parent().unwrap().into();
|
let work_dir: Arc<Path> = parent_path.parent().unwrap().into();
|
||||||
|
|
||||||
|
@ -1991,42 +1992,46 @@ impl LocalSnapshot {
|
||||||
.entry_for_path(work_dir.clone())
|
.entry_for_path(work_dir.clone())
|
||||||
.map(|entry| entry.id)?;
|
.map(|entry| entry.id)?;
|
||||||
|
|
||||||
if self.git_repositories.get(&work_dir_id).is_none() {
|
if self.git_repositories.get(&work_dir_id).is_some() {
|
||||||
let repo = fs.open_repo(abs_path.as_path())?;
|
return None;
|
||||||
let work_directory = RepositoryWorkDirectory(work_dir.clone());
|
|
||||||
|
|
||||||
let repo_lock = repo.lock();
|
|
||||||
|
|
||||||
self.repository_entries.insert(
|
|
||||||
work_directory.clone(),
|
|
||||||
RepositoryEntry {
|
|
||||||
work_directory: work_dir_id.into(),
|
|
||||||
branch: repo_lock.branch_name().map(Into::into),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.scan_statuses(repo_lock.deref(), &work_directory);
|
|
||||||
|
|
||||||
drop(repo_lock);
|
|
||||||
|
|
||||||
self.git_repositories.insert(
|
|
||||||
work_dir_id,
|
|
||||||
LocalRepositoryEntry {
|
|
||||||
git_dir_scan_id: 0,
|
|
||||||
repo_ptr: repo,
|
|
||||||
git_dir_path: parent_path.clone(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(())
|
let repo = fs.open_repo(abs_path.as_path())?;
|
||||||
|
let work_directory = RepositoryWorkDirectory(work_dir.clone());
|
||||||
|
|
||||||
|
let repo_lock = repo.lock();
|
||||||
|
|
||||||
|
self.repository_entries.insert(
|
||||||
|
work_directory.clone(),
|
||||||
|
RepositoryEntry {
|
||||||
|
work_directory: work_dir_id.into(),
|
||||||
|
branch: repo_lock.branch_name().map(Into::into),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let changed_paths = self.scan_statuses(repo_lock.deref(), &work_directory);
|
||||||
|
|
||||||
|
drop(repo_lock);
|
||||||
|
|
||||||
|
self.git_repositories.insert(
|
||||||
|
work_dir_id,
|
||||||
|
LocalRepositoryEntry {
|
||||||
|
git_dir_scan_id: 0,
|
||||||
|
repo_ptr: repo,
|
||||||
|
git_dir_path: parent_path.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(changed_paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "Changed paths must be used for diffing later"]
|
||||||
fn scan_statuses(
|
fn scan_statuses(
|
||||||
&mut self,
|
&mut self,
|
||||||
repo_ptr: &dyn GitRepository,
|
repo_ptr: &dyn GitRepository,
|
||||||
work_directory: &RepositoryWorkDirectory,
|
work_directory: &RepositoryWorkDirectory,
|
||||||
) {
|
) -> Vec<Arc<Path>> {
|
||||||
|
let mut changes = vec![];
|
||||||
let mut edits = vec![];
|
let mut edits = vec![];
|
||||||
for mut entry in self
|
for mut entry in self
|
||||||
.descendent_entries(false, false, &work_directory.0)
|
.descendent_entries(false, false, &work_directory.0)
|
||||||
|
@ -2038,10 +2043,12 @@ impl LocalSnapshot {
|
||||||
let git_file_status = repo_ptr.status(&RepoPath(repo_path.into()));
|
let git_file_status = repo_ptr.status(&RepoPath(repo_path.into()));
|
||||||
let status = git_file_status;
|
let status = git_file_status;
|
||||||
entry.git_status = status;
|
entry.git_status = status;
|
||||||
|
changes.push(entry.path.clone());
|
||||||
edits.push(Edit::Insert(entry));
|
edits.push(Edit::Insert(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.entries_by_path.edit(edits, &());
|
self.entries_by_path.edit(edits, &());
|
||||||
|
changes
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ancestor_inodes_for_path(&self, path: &Path) -> TreeSet<u64> {
|
fn ancestor_inodes_for_path(&self, path: &Path) -> TreeSet<u64> {
|
||||||
|
@ -2096,13 +2103,14 @@ impl BackgroundScannerState {
|
||||||
self.snapshot.insert_entry(entry, fs)
|
self.snapshot.insert_entry(entry, fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "Changed paths must be used for diffing later"]
|
||||||
fn populate_dir(
|
fn populate_dir(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_path: Arc<Path>,
|
parent_path: Arc<Path>,
|
||||||
entries: impl IntoIterator<Item = Entry>,
|
entries: impl IntoIterator<Item = Entry>,
|
||||||
ignore: Option<Arc<Gitignore>>,
|
ignore: Option<Arc<Gitignore>>,
|
||||||
fs: &dyn Fs,
|
fs: &dyn Fs,
|
||||||
) {
|
) -> Option<Vec<Arc<Path>>> {
|
||||||
let mut parent_entry = if let Some(parent_entry) = self
|
let mut parent_entry = if let Some(parent_entry) = self
|
||||||
.snapshot
|
.snapshot
|
||||||
.entries_by_path
|
.entries_by_path
|
||||||
|
@ -2114,7 +2122,7 @@ impl BackgroundScannerState {
|
||||||
"populating a directory {:?} that has been removed",
|
"populating a directory {:?} that has been removed",
|
||||||
parent_path
|
parent_path
|
||||||
);
|
);
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match parent_entry.kind {
|
match parent_entry.kind {
|
||||||
|
@ -2122,7 +2130,7 @@ impl BackgroundScannerState {
|
||||||
parent_entry.kind = EntryKind::Dir;
|
parent_entry.kind = EntryKind::Dir;
|
||||||
}
|
}
|
||||||
EntryKind::Dir => {}
|
EntryKind::Dir => {}
|
||||||
_ => return,
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ignore) = ignore {
|
if let Some(ignore) = ignore {
|
||||||
|
@ -2152,8 +2160,9 @@ impl BackgroundScannerState {
|
||||||
self.snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
self.snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
||||||
|
|
||||||
if parent_path.file_name() == Some(&DOT_GIT) {
|
if parent_path.file_name() == Some(&DOT_GIT) {
|
||||||
self.snapshot.build_repo(parent_path, fs);
|
return self.snapshot.build_repo(parent_path, fs);
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_path(&mut self, path: &Path) {
|
fn remove_path(&mut self, path: &Path) {
|
||||||
|
@ -2822,14 +2831,16 @@ impl BackgroundScanner {
|
||||||
self.update_ignore_statuses().await;
|
self.update_ignore_statuses().await;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut snapshot = &mut self.state.lock().snapshot;
|
let mut state = self.state.lock();
|
||||||
|
|
||||||
if let Some(paths) = paths {
|
if let Some(paths) = paths {
|
||||||
for path in paths {
|
for path in paths {
|
||||||
self.reload_git_repo(&path, &mut *snapshot, self.fs.as_ref());
|
self.reload_git_repo(&path, &mut *state, self.fs.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut snapshot = &mut state.snapshot;
|
||||||
|
|
||||||
let mut git_repositories = mem::take(&mut snapshot.git_repositories);
|
let mut git_repositories = mem::take(&mut snapshot.git_repositories);
|
||||||
git_repositories.retain(|work_directory_id, _| {
|
git_repositories.retain(|work_directory_id, _| {
|
||||||
snapshot
|
snapshot
|
||||||
|
@ -3071,10 +3082,19 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
state.populate_dir(job.path.clone(), new_entries, new_ignore, self.fs.as_ref());
|
let changed_paths =
|
||||||
|
state.populate_dir(job.path.clone(), new_entries, new_ignore, self.fs.as_ref());
|
||||||
if let Err(ix) = state.changed_paths.binary_search(&job.path) {
|
if let Err(ix) = state.changed_paths.binary_search(&job.path) {
|
||||||
state.changed_paths.insert(ix, job.path.clone());
|
state.changed_paths.insert(ix, job.path.clone());
|
||||||
}
|
}
|
||||||
|
if let Some(changed_paths) = changed_paths {
|
||||||
|
util::extend_sorted(
|
||||||
|
&mut state.changed_paths,
|
||||||
|
changed_paths,
|
||||||
|
usize::MAX,
|
||||||
|
Ord::cmp,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for new_job in new_jobs {
|
for new_job in new_jobs {
|
||||||
|
@ -3221,22 +3241,31 @@ impl BackgroundScanner {
|
||||||
fn reload_git_repo(
|
fn reload_git_repo(
|
||||||
&self,
|
&self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
snapshot: &mut LocalSnapshot,
|
state: &mut BackgroundScannerState,
|
||||||
fs: &dyn Fs,
|
fs: &dyn Fs,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let scan_id = snapshot.scan_id;
|
let scan_id = state.snapshot.scan_id;
|
||||||
|
|
||||||
if path
|
if path
|
||||||
.components()
|
.components()
|
||||||
.any(|component| component.as_os_str() == *DOT_GIT)
|
.any(|component| component.as_os_str() == *DOT_GIT)
|
||||||
{
|
{
|
||||||
let (entry_id, repo_ptr) = {
|
let (entry_id, repo_ptr) = {
|
||||||
let Some((entry_id, repo)) = snapshot.repo_for_metadata(&path) else {
|
let Some((entry_id, repo)) = state.snapshot.repo_for_metadata(&path) else {
|
||||||
let dot_git_dir = path.ancestors()
|
let dot_git_dir = path.ancestors()
|
||||||
.skip_while(|ancestor| ancestor.file_name() != Some(&*DOT_GIT))
|
.skip_while(|ancestor| ancestor.file_name() != Some(&*DOT_GIT))
|
||||||
.next()?;
|
.next()?;
|
||||||
|
|
||||||
snapshot.build_repo(dot_git_dir.into(), fs);
|
let changed_paths = state.snapshot.build_repo(dot_git_dir.into(), fs);
|
||||||
|
if let Some(changed_paths) = changed_paths {
|
||||||
|
util::extend_sorted(
|
||||||
|
&mut state.changed_paths,
|
||||||
|
changed_paths,
|
||||||
|
usize::MAX,
|
||||||
|
Ord::cmp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
if repo.git_dir_scan_id == scan_id {
|
if repo.git_dir_scan_id == scan_id {
|
||||||
|
@ -3246,7 +3275,8 @@ impl BackgroundScanner {
|
||||||
(*entry_id, repo.repo_ptr.to_owned())
|
(*entry_id, repo.repo_ptr.to_owned())
|
||||||
};
|
};
|
||||||
|
|
||||||
let work_dir = snapshot
|
let work_dir = state
|
||||||
|
.snapshot
|
||||||
.entry_for_id(entry_id)
|
.entry_for_id(entry_id)
|
||||||
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))?;
|
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))?;
|
||||||
|
|
||||||
|
@ -3254,18 +3284,26 @@ impl BackgroundScanner {
|
||||||
repo.reload_index();
|
repo.reload_index();
|
||||||
let branch = repo.branch_name();
|
let branch = repo.branch_name();
|
||||||
|
|
||||||
snapshot.git_repositories.update(&entry_id, |entry| {
|
state.snapshot.git_repositories.update(&entry_id, |entry| {
|
||||||
entry.git_dir_scan_id = scan_id;
|
entry.git_dir_scan_id = scan_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
snapshot
|
state
|
||||||
|
.snapshot
|
||||||
.snapshot
|
.snapshot
|
||||||
.repository_entries
|
.repository_entries
|
||||||
.update(&work_dir, |entry| {
|
.update(&work_dir, |entry| {
|
||||||
entry.branch = branch.map(Into::into);
|
entry.branch = branch.map(Into::into);
|
||||||
});
|
});
|
||||||
|
|
||||||
snapshot.scan_statuses(repo.deref(), &work_dir);
|
let changed_paths = state.snapshot.scan_statuses(repo.deref(), &work_dir);
|
||||||
|
|
||||||
|
util::extend_sorted(
|
||||||
|
&mut state.changed_paths,
|
||||||
|
changed_paths,
|
||||||
|
usize::MAX,
|
||||||
|
Ord::cmp,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub fn post_inc<T: From<u8> + AddAssign<T> + Copy>(value: &mut T) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend a sorted vector with a sorted sequence of items, maintaining the vector's sort order and
|
/// Extend a sorted vector with a sorted sequence of items, maintaining the vector's sort order and
|
||||||
/// enforcing a maximum length. Sort the items according to the given callback. Before calling this,
|
/// enforcing a maximum length. This also de-duplicates items. Sort the items according to the given callback. Before calling this,
|
||||||
/// both `vec` and `new_items` should already be sorted according to the `cmp` comparator.
|
/// both `vec` and `new_items` should already be sorted according to the `cmp` comparator.
|
||||||
pub fn extend_sorted<T, I, F>(vec: &mut Vec<T>, new_items: I, limit: usize, mut cmp: F)
|
pub fn extend_sorted<T, I, F>(vec: &mut Vec<T>, new_items: I, limit: usize, mut cmp: F)
|
||||||
where
|
where
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue