Move repository state RPC handlers to the GitStore (#27391)
This is another in the series of PRs to make the GitStore own all repository state and enable better concurrency control for git repository scans. After this PR, the `RepositoryEntry`s stored in worktree snapshots are used only as a staging ground for local GitStores to pull from after git-related events; non-local worktrees don't store them at all, although this is not reflected in the types. GitTraversal and other places that need information about repositories get it from the GitStore. The GitStore also takes over handling of the new UpdateRepository and RemoveRepository messages. However, repositories are still discovered and scanned on a per-worktree basis, and we're still identifying them by the (worktree-specific) project entry ID of their working directory. - [x] Remove WorkDirectory from RepositoryEntry - [x] Remove worktree IDs from repository-related RPC messages - [x] Handle UpdateRepository and RemoveRepository RPCs from the GitStore Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
1e8b50f471
commit
6924720b35
22 changed files with 1387 additions and 1399 deletions
|
@ -6,7 +6,8 @@ use buffer_diff::{
|
|||
};
|
||||
use fs::FakeFs;
|
||||
use futures::{future, StreamExt};
|
||||
use gpui::{App, SemanticVersion, UpdateGlobal};
|
||||
use git::repository::RepoPath;
|
||||
use gpui::{App, BackgroundExecutor, SemanticVersion, UpdateGlobal};
|
||||
use http_client::Url;
|
||||
use language::{
|
||||
language_settings::{language_settings, AllLanguageSettings, LanguageSettingsContent},
|
||||
|
@ -34,6 +35,7 @@ use util::{
|
|||
test::{marked_text_offsets, TempTree},
|
||||
uri, TryFutureExt as _,
|
||||
};
|
||||
use worktree::WorktreeModelHandle as _;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_block_via_channel(cx: &mut gpui::TestAppContext) {
|
||||
|
@ -6769,6 +6771,158 @@ async fn test_single_file_diffs(cx: &mut gpui::TestAppContext) {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_repository_and_path_for_project_path(
|
||||
background_executor: BackgroundExecutor,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
let fs = FakeFs::new(background_executor);
|
||||
fs.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"c.txt": "",
|
||||
"dir1": {
|
||||
".git": {},
|
||||
"deps": {
|
||||
"dep1": {
|
||||
".git": {},
|
||||
"src": {
|
||||
"a.txt": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"src": {
|
||||
"b.txt": ""
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||
tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
tree.flush_fs_events(cx).await;
|
||||
|
||||
project.read_with(cx, |project, cx| {
|
||||
let git_store = project.git_store().read(cx);
|
||||
let pairs = [
|
||||
("c.txt", None),
|
||||
("dir1/src/b.txt", Some((path!("/root/dir1"), "src/b.txt"))),
|
||||
(
|
||||
"dir1/deps/dep1/src/a.txt",
|
||||
Some((path!("/root/dir1/deps/dep1"), "src/a.txt")),
|
||||
),
|
||||
];
|
||||
let expected = pairs
|
||||
.iter()
|
||||
.map(|(path, result)| {
|
||||
(
|
||||
path,
|
||||
result.map(|(repo, repo_path)| {
|
||||
(Path::new(repo).to_owned(), RepoPath::from(repo_path))
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let actual = pairs
|
||||
.iter()
|
||||
.map(|(path, _)| {
|
||||
let project_path = (tree_id, Path::new(path)).into();
|
||||
let result = maybe!({
|
||||
let (repo, repo_path) =
|
||||
git_store.repository_and_path_for_project_path(&project_path, cx)?;
|
||||
Some((
|
||||
repo.read(cx)
|
||||
.repository_entry
|
||||
.work_directory_abs_path
|
||||
.clone(),
|
||||
repo_path,
|
||||
))
|
||||
});
|
||||
(path, result)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
pretty_assertions::assert_eq!(expected, actual);
|
||||
});
|
||||
|
||||
fs.remove_dir(path!("/root/dir1/.git").as_ref(), RemoveOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
tree.flush_fs_events(cx).await;
|
||||
|
||||
project.read_with(cx, |project, cx| {
|
||||
let git_store = project.git_store().read(cx);
|
||||
assert_eq!(
|
||||
git_store.repository_and_path_for_project_path(
|
||||
&(tree_id, Path::new("dir1/src/b.txt")).into(),
|
||||
cx
|
||||
),
|
||||
None
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_home_dir_as_git_repository(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
let fs = FakeFs::new(cx.background_executor.clone());
|
||||
fs.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"home": {
|
||||
".git": {},
|
||||
"project": {
|
||||
"a.txt": "A"
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
fs.set_home_dir(Path::new(path!("/root/home")).to_owned());
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/root/home/project").as_ref()], cx).await;
|
||||
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||
tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
tree.flush_fs_events(cx).await;
|
||||
|
||||
project.read_with(cx, |project, cx| {
|
||||
let containing = project
|
||||
.git_store()
|
||||
.read(cx)
|
||||
.repository_and_path_for_project_path(&(tree_id, "a.txt").into(), cx);
|
||||
assert!(containing.is_none());
|
||||
});
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/root/home").as_ref()], cx).await;
|
||||
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||
tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
tree.flush_fs_events(cx).await;
|
||||
|
||||
project.read_with(cx, |project, cx| {
|
||||
let containing = project
|
||||
.git_store()
|
||||
.read(cx)
|
||||
.repository_and_path_for_project_path(&(tree_id, "project/a.txt").into(), cx);
|
||||
assert_eq!(
|
||||
containing
|
||||
.unwrap()
|
||||
.0
|
||||
.read(cx)
|
||||
.repository_entry
|
||||
.work_directory_abs_path,
|
||||
Path::new(path!("/root/home"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async fn search(
|
||||
project: &Entity<Project>,
|
||||
query: SearchQuery,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue