WIP: re-arranging the RepositoryEntry representation
Added branches to the randomized test to check the git branch Added the remaining database integrations in collab Co-authored-by: Max <max@zed.dev> Co-authored-by: Petros <petros@zed.dev>
This commit is contained in:
parent
8bde496e74
commit
b6d6f5c650
5 changed files with 169 additions and 50 deletions
|
@ -1490,6 +1490,8 @@ impl Database {
|
|||
visible: db_worktree.visible,
|
||||
updated_entries: Default::default(),
|
||||
removed_entries: Default::default(),
|
||||
updated_repositories: Default::default(),
|
||||
removed_repositories: Default::default(),
|
||||
diagnostic_summaries: Default::default(),
|
||||
scan_id: db_worktree.scan_id as u64,
|
||||
completed_scan_id: db_worktree.completed_scan_id as u64,
|
||||
|
@ -1499,38 +1501,77 @@ impl Database {
|
|||
.worktrees
|
||||
.iter()
|
||||
.find(|worktree| worktree.id == db_worktree.id as u64);
|
||||
let entry_filter = if let Some(rejoined_worktree) = rejoined_worktree {
|
||||
worktree_entry::Column::ScanId.gt(rejoined_worktree.scan_id)
|
||||
} else {
|
||||
worktree_entry::Column::IsDeleted.eq(false)
|
||||
};
|
||||
|
||||
let mut db_entries = worktree_entry::Entity::find()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(worktree_entry::Column::WorktreeId.eq(worktree.id))
|
||||
.add(entry_filter),
|
||||
)
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
|
||||
while let Some(db_entry) = db_entries.next().await {
|
||||
let db_entry = db_entry?;
|
||||
if db_entry.is_deleted {
|
||||
worktree.removed_entries.push(db_entry.id as u64);
|
||||
// File entries
|
||||
{
|
||||
let entry_filter = if let Some(rejoined_worktree) = rejoined_worktree {
|
||||
worktree_entry::Column::ScanId.gt(rejoined_worktree.scan_id)
|
||||
} else {
|
||||
worktree.updated_entries.push(proto::Entry {
|
||||
id: db_entry.id as u64,
|
||||
is_dir: db_entry.is_dir,
|
||||
path: db_entry.path,
|
||||
inode: db_entry.inode as u64,
|
||||
mtime: Some(proto::Timestamp {
|
||||
seconds: db_entry.mtime_seconds as u64,
|
||||
nanos: db_entry.mtime_nanos as u32,
|
||||
}),
|
||||
is_symlink: db_entry.is_symlink,
|
||||
is_ignored: db_entry.is_ignored,
|
||||
});
|
||||
worktree_entry::Column::IsDeleted.eq(false)
|
||||
};
|
||||
|
||||
let mut db_entries = worktree_entry::Entity::find()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(worktree_entry::Column::WorktreeId.eq(worktree.id))
|
||||
.add(entry_filter),
|
||||
)
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
|
||||
while let Some(db_entry) = db_entries.next().await {
|
||||
let db_entry = db_entry?;
|
||||
if db_entry.is_deleted {
|
||||
worktree.removed_entries.push(db_entry.id as u64);
|
||||
} else {
|
||||
worktree.updated_entries.push(proto::Entry {
|
||||
id: db_entry.id as u64,
|
||||
is_dir: db_entry.is_dir,
|
||||
path: db_entry.path,
|
||||
inode: db_entry.inode as u64,
|
||||
mtime: Some(proto::Timestamp {
|
||||
seconds: db_entry.mtime_seconds as u64,
|
||||
nanos: db_entry.mtime_nanos as u32,
|
||||
}),
|
||||
is_symlink: db_entry.is_symlink,
|
||||
is_ignored: db_entry.is_ignored,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Repository Entries
|
||||
{
|
||||
let repository_entry_filter =
|
||||
if let Some(rejoined_worktree) = rejoined_worktree {
|
||||
worktree_repository::Column::ScanId.gt(rejoined_worktree.scan_id)
|
||||
} else {
|
||||
worktree_repository::Column::IsDeleted.eq(false)
|
||||
};
|
||||
|
||||
let mut db_repositories = worktree_repository::Entity::find()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(worktree_repository::Column::WorktreeId.eq(worktree.id))
|
||||
.add(repository_entry_filter),
|
||||
)
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
|
||||
while let Some(db_repository) = db_repositories.next().await {
|
||||
let db_repository = db_repository?;
|
||||
if db_repository.is_deleted {
|
||||
worktree
|
||||
.removed_repositories
|
||||
.push(db_repository.dot_git_entry_id as u64);
|
||||
} else {
|
||||
worktree.updated_repositories.push(proto::RepositoryEntry {
|
||||
dot_git_entry_id: db_repository.dot_git_entry_id as u64,
|
||||
scan_id: db_repository.scan_id as u64,
|
||||
work_directory: db_repository.work_directory_path,
|
||||
branch: db_repository.branch,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2555,6 +2596,7 @@ impl Database {
|
|||
root_name: db_worktree.root_name,
|
||||
visible: db_worktree.visible,
|
||||
entries: Default::default(),
|
||||
repository_entries: Default::default(),
|
||||
diagnostic_summaries: Default::default(),
|
||||
scan_id: db_worktree.scan_id as u64,
|
||||
completed_scan_id: db_worktree.completed_scan_id as u64,
|
||||
|
@ -2592,6 +2634,31 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
// Populate repository entries.
|
||||
{
|
||||
let mut db_repository_entries = worktree_repository::Entity::find()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(worktree_repository::Column::ProjectId.eq(project_id))
|
||||
.add(worktree_repository::Column::IsDeleted.eq(false)),
|
||||
)
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
while let Some(db_repository_entry) = db_repository_entries.next().await {
|
||||
let db_repository_entry = db_repository_entry?;
|
||||
if let Some(worktree) =
|
||||
worktrees.get_mut(&(db_repository_entry.worktree_id as u64))
|
||||
{
|
||||
worktree.repository_entries.push(proto::RepositoryEntry {
|
||||
dot_git_entry_id: db_repository_entry.dot_git_entry_id as u64,
|
||||
scan_id: db_repository_entry.scan_id as u64,
|
||||
work_directory: db_repository_entry.work_directory_path,
|
||||
branch: db_repository_entry.branch,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate worktree diagnostic summaries.
|
||||
{
|
||||
let mut db_summaries = worktree_diagnostic_summary::Entity::find()
|
||||
|
@ -3273,6 +3340,8 @@ pub struct RejoinedWorktree {
|
|||
pub visible: bool,
|
||||
pub updated_entries: Vec<proto::Entry>,
|
||||
pub removed_entries: Vec<u64>,
|
||||
pub updated_repositories: Vec<proto::RepositoryEntry>,
|
||||
pub removed_repositories: Vec<u64>,
|
||||
pub diagnostic_summaries: Vec<proto::DiagnosticSummary>,
|
||||
pub scan_id: u64,
|
||||
pub completed_scan_id: u64,
|
||||
|
@ -3327,6 +3396,7 @@ pub struct Worktree {
|
|||
pub root_name: String,
|
||||
pub visible: bool,
|
||||
pub entries: Vec<proto::Entry>,
|
||||
pub repository_entries: Vec<proto::RepositoryEntry>,
|
||||
pub diagnostic_summaries: Vec<proto::DiagnosticSummary>,
|
||||
pub scan_id: u64,
|
||||
pub completed_scan_id: u64,
|
||||
|
|
|
@ -1386,9 +1386,8 @@ async fn join_project(
|
|||
removed_entries: Default::default(),
|
||||
scan_id: worktree.scan_id,
|
||||
is_last_update: worktree.scan_id == worktree.completed_scan_id,
|
||||
// TODO repo
|
||||
updated_repositories: vec![],
|
||||
removed_repositories: vec![],
|
||||
updated_repositories: worktree.repository_entries,
|
||||
removed_repositories: Default::default(),
|
||||
};
|
||||
for update in proto::split_worktree_update(message, MAX_CHUNK_SIZE) {
|
||||
session.peer.send(session.connection_id, update.clone())?;
|
||||
|
|
|
@ -785,6 +785,28 @@ async fn apply_client_operation(
|
|||
}
|
||||
client.fs.set_index_for_repo(&dot_git_dir, &contents).await;
|
||||
}
|
||||
|
||||
ClientOperation::WriteGitBranch {
|
||||
repo_path,
|
||||
new_branch,
|
||||
} => {
|
||||
if !client.fs.directories().contains(&repo_path) {
|
||||
return Err(TestError::Inapplicable);
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"{}: writing git branch for repo {:?}: {:?}",
|
||||
client.username,
|
||||
repo_path,
|
||||
new_branch
|
||||
);
|
||||
|
||||
let dot_git_dir = repo_path.join(".git");
|
||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
||||
client.fs.create_dir(&dot_git_dir).await?;
|
||||
}
|
||||
client.fs.set_branch_name(&dot_git_dir, new_branch).await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -859,6 +881,12 @@ fn check_consistency_between_clients(clients: &[(Rc<TestClient>, TestAppContext)
|
|||
host_snapshot.abs_path(),
|
||||
guest_project.remote_id(),
|
||||
);
|
||||
assert_eq!(guest_snapshot.repositories().collect::<Vec<_>>(), host_snapshot.repositories().collect::<Vec<_>>(),
|
||||
"{} has different repositories than the host for worktree {:?} and project {:?}",
|
||||
client.username,
|
||||
host_snapshot.abs_path(),
|
||||
guest_project.remote_id(),
|
||||
);
|
||||
assert_eq!(guest_snapshot.scan_id(), host_snapshot.scan_id(),
|
||||
"{} has different scan id than the host for worktree {:?} and project {:?}",
|
||||
client.username,
|
||||
|
@ -1151,6 +1179,10 @@ enum ClientOperation {
|
|||
repo_path: PathBuf,
|
||||
contents: Vec<(PathBuf, String)>,
|
||||
},
|
||||
WriteGitBranch {
|
||||
repo_path: PathBuf,
|
||||
new_branch: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -1664,7 +1696,7 @@ impl TestPlan {
|
|||
}
|
||||
|
||||
// Update a git index
|
||||
91..=95 => {
|
||||
91..=93 => {
|
||||
let repo_path = client
|
||||
.fs
|
||||
.directories()
|
||||
|
@ -1698,6 +1730,24 @@ impl TestPlan {
|
|||
};
|
||||
}
|
||||
|
||||
// Update a git branch
|
||||
94..=95 => {
|
||||
let repo_path = client
|
||||
.fs
|
||||
.directories()
|
||||
.choose(&mut self.rng)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let new_branch = (self.rng.gen_range(0..10) > 3)
|
||||
.then(|| Alphanumeric.sample_string(&mut self.rng, 8));
|
||||
|
||||
break ClientOperation::WriteGitBranch {
|
||||
repo_path,
|
||||
new_branch,
|
||||
};
|
||||
}
|
||||
|
||||
// Create or update a file or directory
|
||||
96.. => {
|
||||
let is_dir = self.rng.gen::<bool>();
|
||||
|
|
|
@ -117,13 +117,10 @@ pub struct Snapshot {
|
|||
completed_scan_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RepositoryEntry {
|
||||
pub(crate) scan_id: usize,
|
||||
pub(crate) dot_git_entry_id: ProjectEntryId,
|
||||
/// Relative to the worktree, the repository for the root will have
|
||||
/// a work directory equal to: ""
|
||||
pub(crate) work_directory: RepositoryWorkDirectory,
|
||||
pub(crate) work_directory_id: ProjectEntryId,
|
||||
pub(crate) branch: Option<Arc<str>>,
|
||||
}
|
||||
|
||||
|
@ -132,17 +129,16 @@ impl RepositoryEntry {
|
|||
self.branch.clone()
|
||||
}
|
||||
|
||||
pub fn work_directory(&self) -> Arc<Path> {
|
||||
self.work_directory.0.clone()
|
||||
pub fn work_directory_id(&self) -> ProjectEntryId {
|
||||
self.work_directory_id
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RepositoryEntry> for proto::RepositoryEntry {
|
||||
fn from(value: &RepositoryEntry) -> Self {
|
||||
proto::RepositoryEntry {
|
||||
dot_git_entry_id: value.dot_git_entry_id.to_proto(),
|
||||
scan_id: value.scan_id as u64,
|
||||
work_directory: value.work_directory.to_string_lossy().to_string(),
|
||||
work_directory_id: value.work_directory_id.to_proto(),
|
||||
branch: value.branch.as_ref().map(|str| str.to_string()),
|
||||
}
|
||||
}
|
||||
|
@ -212,6 +208,7 @@ impl AsRef<Path> for RepositoryWorkDirectory {
|
|||
pub struct LocalSnapshot {
|
||||
ignores_by_parent_abs_path: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,
|
||||
// The ProjectEntryId corresponds to the entry for the .git dir
|
||||
// work_directory_id
|
||||
git_repositories: TreeMap<ProjectEntryId, LocalRepositoryEntry>,
|
||||
removed_entry_ids: HashMap<u64, ProjectEntryId>,
|
||||
next_entry_id: Arc<AtomicUsize>,
|
||||
|
@ -701,12 +698,12 @@ impl LocalWorktree {
|
|||
) {
|
||||
for a_repo in a {
|
||||
let matched = b.find(|b_repo| {
|
||||
a_repo.dot_git_entry_id == b_repo.dot_git_entry_id
|
||||
a_repo.work_directory_id == b_repo.work_directory_id
|
||||
&& a_repo.scan_id == b_repo.scan_id
|
||||
});
|
||||
|
||||
if matched.is_none() {
|
||||
updated.insert(a_repo.dot_git_entry_id, a_repo.clone());
|
||||
updated.insert(a_repo.work_directory_id, a_repo.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1158,7 +1155,7 @@ impl LocalWorktree {
|
|||
repo_path: RepoPath,
|
||||
cx: &mut ModelContext<Worktree>,
|
||||
) -> Task<Option<String>> {
|
||||
let Some(git_ptr) = self.git_repositories.get(&repo.dot_git_entry_id).map(|git_ptr| git_ptr.to_owned()) else {
|
||||
let Some(git_ptr) = self.git_repositories.get(&repo.work_directory_id).map(|git_ptr| git_ptr.to_owned()) else {
|
||||
return Task::Ready(Some(None))
|
||||
};
|
||||
let git_ptr = git_ptr.repo_ptr;
|
||||
|
@ -1476,6 +1473,10 @@ impl Snapshot {
|
|||
self.traverse_from_offset(true, include_ignored, 0)
|
||||
}
|
||||
|
||||
pub fn repositories(&self) -> impl Iterator<Item = &RepositoryEntry> {
|
||||
self.repository_entries.values()
|
||||
}
|
||||
|
||||
pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
|
||||
let empty_path = Path::new("");
|
||||
self.entries_by_path
|
||||
|
|
|
@ -982,10 +982,9 @@ message Entry {
|
|||
}
|
||||
|
||||
message RepositoryEntry {
|
||||
uint64 dot_git_entry_id = 1;
|
||||
uint64 scan_id = 2;
|
||||
string work_directory = 4;
|
||||
optional string branch = 5;
|
||||
uint64 scan_id = 1;
|
||||
uint64 work_directory_id = 2;
|
||||
optional string branch = 3;
|
||||
}
|
||||
|
||||
message BufferState {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue