WIP: Track live entry status in repository
co-authored-by: petros <petros@zed.dev>
This commit is contained in:
parent
7169f5c760
commit
67491632cb
3 changed files with 165 additions and 86 deletions
|
@ -6,7 +6,10 @@ use anyhow::{anyhow, Context, Result};
|
|||
use client::{proto, Client};
|
||||
use clock::ReplicaId;
|
||||
use collections::{HashMap, VecDeque};
|
||||
use fs::{repository::{GitRepository, RepoPath, GitStatus}, Fs, LineEnding};
|
||||
use fs::{
|
||||
repository::{GitRepository, GitStatus, RepoPath},
|
||||
Fs, LineEnding,
|
||||
};
|
||||
use futures::{
|
||||
channel::{
|
||||
mpsc::{self, UnboundedSender},
|
||||
|
@ -121,7 +124,7 @@ pub struct Snapshot {
|
|||
pub struct RepositoryEntry {
|
||||
pub(crate) work_directory: WorkDirectoryEntry,
|
||||
pub(crate) branch: Option<Arc<str>>,
|
||||
// pub(crate) statuses: TreeMap<RepoPath, GitStatus>
|
||||
pub(crate) statuses: TreeMap<RepoPath, GitStatus>,
|
||||
}
|
||||
|
||||
impl RepositoryEntry {
|
||||
|
@ -169,7 +172,6 @@ impl AsRef<Path> for RepositoryWorkDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct WorkDirectoryEntry(ProjectEntryId);
|
||||
|
||||
|
@ -219,6 +221,7 @@ pub struct LocalSnapshot {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct LocalRepositoryEntry {
|
||||
pub(crate) scan_id: usize,
|
||||
pub(crate) full_scan_id: usize,
|
||||
pub(crate) repo_ptr: Arc<Mutex<dyn GitRepository>>,
|
||||
/// Path to the actual .git folder.
|
||||
/// Note: if .git is a file, this points to the folder indicated by the .git file
|
||||
|
@ -1412,6 +1415,8 @@ impl Snapshot {
|
|||
let repository = RepositoryEntry {
|
||||
work_directory: ProjectEntryId::from_proto(repository.work_directory_id).into(),
|
||||
branch: repository.branch.map(Into::into),
|
||||
// TODO: status
|
||||
statuses: Default::default(),
|
||||
};
|
||||
if let Some(entry) = self.entry_for_id(repository.work_directory_id()) {
|
||||
self.repository_entries
|
||||
|
@ -1572,6 +1577,10 @@ impl LocalSnapshot {
|
|||
current_candidate.map(|entry| entry.to_owned())
|
||||
}
|
||||
|
||||
pub(crate) fn get_local_repo(&self, repo: &RepositoryEntry) -> Option<&LocalRepositoryEntry> {
|
||||
self.git_repositories.get(&repo.work_directory.0)
|
||||
}
|
||||
|
||||
pub(crate) fn repo_for_metadata(
|
||||
&self,
|
||||
path: &Path,
|
||||
|
@ -1842,6 +1851,7 @@ impl LocalSnapshot {
|
|||
RepositoryEntry {
|
||||
work_directory: work_dir_id.into(),
|
||||
branch: repo_lock.branch_name().map(Into::into),
|
||||
statuses: repo_lock.statuses().unwrap_or_default(),
|
||||
},
|
||||
);
|
||||
drop(repo_lock);
|
||||
|
@ -1850,6 +1860,7 @@ impl LocalSnapshot {
|
|||
work_dir_id,
|
||||
LocalRepositoryEntry {
|
||||
scan_id,
|
||||
full_scan_id: scan_id,
|
||||
repo_ptr: repo,
|
||||
git_dir_path: parent_path.clone(),
|
||||
},
|
||||
|
@ -2825,26 +2836,7 @@ impl BackgroundScanner {
|
|||
fs_entry.is_ignored = ignore_stack.is_all();
|
||||
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
||||
|
||||
let scan_id = snapshot.scan_id;
|
||||
|
||||
let repo_with_path_in_dotgit = snapshot.repo_for_metadata(&path);
|
||||
if let Some((entry_id, repo)) = repo_with_path_in_dotgit {
|
||||
let work_dir = snapshot
|
||||
.entry_for_id(entry_id)
|
||||
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))?;
|
||||
|
||||
let repo = repo.lock();
|
||||
repo.reload_index();
|
||||
let branch = repo.branch_name();
|
||||
|
||||
snapshot.git_repositories.update(&entry_id, |entry| {
|
||||
entry.scan_id = scan_id;
|
||||
});
|
||||
|
||||
snapshot
|
||||
.repository_entries
|
||||
.update(&work_dir, |entry| entry.branch = branch.map(Into::into));
|
||||
}
|
||||
self.reload_repo_for_path(&path, &mut snapshot);
|
||||
|
||||
if let Some(scan_queue_tx) = &scan_queue_tx {
|
||||
let mut ancestor_inodes = snapshot.ancestor_inodes_for_path(&path);
|
||||
|
@ -2872,6 +2864,63 @@ impl BackgroundScanner {
|
|||
Some(event_paths)
|
||||
}
|
||||
|
||||
fn reload_repo_for_path(&self, path: &Path, snapshot: &mut LocalSnapshot) -> Option<()> {
|
||||
let scan_id = snapshot.scan_id;
|
||||
|
||||
if path
|
||||
.components()
|
||||
.any(|component| component.as_os_str() == *DOT_GIT)
|
||||
{
|
||||
let (entry_id, repo) = snapshot.repo_for_metadata(&path)?;
|
||||
|
||||
let work_dir = snapshot
|
||||
.entry_for_id(entry_id)
|
||||
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))?;
|
||||
|
||||
let repo = repo.lock();
|
||||
repo.reload_index();
|
||||
let branch = repo.branch_name();
|
||||
let statuses = repo.statuses().unwrap_or_default();
|
||||
|
||||
snapshot.git_repositories.update(&entry_id, |entry| {
|
||||
entry.scan_id = scan_id;
|
||||
entry.full_scan_id = scan_id;
|
||||
});
|
||||
|
||||
snapshot.repository_entries.update(&work_dir, |entry| {
|
||||
entry.branch = branch.map(Into::into);
|
||||
entry.statuses = statuses;
|
||||
});
|
||||
} else if let Some(repo) = snapshot.repo_for(&path) {
|
||||
let status = {
|
||||
let local_repo = snapshot.get_local_repo(&repo)?;
|
||||
// Short circuit if we've already scanned everything
|
||||
if local_repo.full_scan_id == scan_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
let repo_path = repo.work_directory.relativize(&snapshot, &path)?;
|
||||
let git_ptr = local_repo.repo_ptr.lock();
|
||||
git_ptr.file_status(&repo_path)?
|
||||
};
|
||||
|
||||
if status != GitStatus::Untracked {
|
||||
let work_dir = repo.work_directory(snapshot)?;
|
||||
let work_dir_id = repo.work_directory;
|
||||
|
||||
snapshot
|
||||
.git_repositories
|
||||
.update(&work_dir_id, |entry| entry.scan_id = scan_id);
|
||||
|
||||
snapshot
|
||||
.repository_entries
|
||||
.update(&work_dir, |entry| entry.statuses.insert(repo_path, status));
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
async fn update_ignore_statuses(&self) {
|
||||
use futures::FutureExt as _;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue