SSH Remoting: Fix bugs in worktree syncing (#18406)
Release Notes: - N/A --------- Co-authored-by: conrad <conrad@zed.dev>
This commit is contained in:
parent
11058765be
commit
71da81c743
12 changed files with 157 additions and 92 deletions
|
@ -32,6 +32,7 @@ macro_rules! id_type {
|
|||
#[allow(unused)]
|
||||
#[allow(missing_docs)]
|
||||
pub fn from_proto(value: u64) -> Self {
|
||||
debug_assert!(value != 0);
|
||||
Self(value as i32)
|
||||
}
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ impl Database {
|
|||
)
|
||||
.one(&*tx)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("no such project"))?;
|
||||
.ok_or_else(|| anyhow!("no such project: {project_id}"))?;
|
||||
|
||||
// Update metadata.
|
||||
worktree::Entity::update(worktree::ActiveModel {
|
||||
|
|
|
@ -246,7 +246,7 @@ async fn test_channel_notes_participant_indices(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||
|
||||
// Clients A and B open the same file.
|
||||
|
|
|
@ -76,7 +76,7 @@ async fn test_host_disconnect(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
cx_a.background_executor.run_until_parked();
|
||||
|
||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
|
||||
|
@ -192,7 +192,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a buffer as client A
|
||||
let buffer_a = project_a
|
||||
|
@ -308,7 +308,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a file in an editor as the guest.
|
||||
let buffer_b = project_b
|
||||
|
@ -565,7 +565,7 @@ async fn test_collaborating_with_code_actions(
|
|||
.unwrap();
|
||||
|
||||
// Join the project as client B.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||
let editor_b = workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
|
@ -780,7 +780,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||
let editor_b = workspace_b
|
||||
|
@ -1030,7 +1030,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
.await
|
||||
.unwrap();
|
||||
executor.run_until_parked();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
|
@ -1126,9 +1126,7 @@ async fn test_share_project(
|
|||
.await
|
||||
.unwrap();
|
||||
let client_b_peer_id = client_b.peer_id().unwrap();
|
||||
let project_b = client_b
|
||||
.build_dev_server_project(initial_project.id, cx_b)
|
||||
.await;
|
||||
let project_b = client_b.join_remote_project(initial_project.id, cx_b).await;
|
||||
|
||||
let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
|
||||
|
||||
|
@ -1230,9 +1228,7 @@ async fn test_share_project(
|
|||
.update(cx_c, |call, cx| call.accept_incoming(cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let _project_c = client_c
|
||||
.build_dev_server_project(initial_project.id, cx_c)
|
||||
.await;
|
||||
let _project_c = client_c.join_remote_project(initial_project.id, cx_c).await;
|
||||
|
||||
// Client B closes the editor, and client A sees client B's selections removed.
|
||||
cx_b.update(move |_| drop(editor_b));
|
||||
|
@ -1291,7 +1287,7 @@ async fn test_on_input_format_from_host_to_guest(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a file in an editor as the host.
|
||||
let buffer_a = project_a
|
||||
|
@ -1411,7 +1407,7 @@ async fn test_on_input_format_from_guest_to_host(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a file in an editor as the guest.
|
||||
let buffer_b = project_b
|
||||
|
@ -1574,7 +1570,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
|||
.unwrap();
|
||||
|
||||
// Client B joins the project
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -1836,7 +1832,7 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -2050,7 +2046,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
|||
.unwrap();
|
||||
|
||||
// Join the project as client B.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||
let editor_b = workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
|
|
|
@ -74,7 +74,7 @@ async fn test_basic_following(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -162,7 +162,7 @@ async fn test_basic_following(
|
|||
|
||||
executor.run_until_parked();
|
||||
let active_call_c = cx_c.read(ActiveCall::global);
|
||||
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
let (workspace_c, cx_c) = client_c.build_workspace(&project_c, cx_c);
|
||||
active_call_c
|
||||
.update(cx_c, |call, cx| call.set_location(Some(&project_c), cx))
|
||||
|
@ -175,7 +175,7 @@ async fn test_basic_following(
|
|||
|
||||
cx_d.executor().run_until_parked();
|
||||
let active_call_d = cx_d.read(ActiveCall::global);
|
||||
let project_d = client_d.build_dev_server_project(project_id, cx_d).await;
|
||||
let project_d = client_d.join_remote_project(project_id, cx_d).await;
|
||||
let (workspace_d, cx_d) = client_d.build_workspace(&project_d, cx_d);
|
||||
active_call_d
|
||||
.update(cx_d, |call, cx| call.set_location(Some(&project_d), cx))
|
||||
|
@ -569,7 +569,7 @@ async fn test_following_tab_order(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -686,7 +686,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T
|
|||
.unwrap();
|
||||
|
||||
// Client B joins the project.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -1199,7 +1199,7 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
@ -1335,7 +1335,7 @@ async fn test_peers_simultaneously_following_each_other(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||
|
||||
executor.run_until_parked();
|
||||
|
@ -1685,7 +1685,7 @@ async fn test_following_into_excluded_file(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
active_call_b
|
||||
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
|
||||
.await
|
||||
|
|
|
@ -1372,7 +1372,7 @@ async fn test_unshare_project(
|
|||
.unwrap();
|
||||
|
||||
let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
|
||||
|
@ -1392,7 +1392,7 @@ async fn test_unshare_project(
|
|||
assert!(project_b.read_with(cx_b, |project, _| project.is_disconnected()));
|
||||
|
||||
// Client C opens the project.
|
||||
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
|
||||
// When client A unshares the project, client C's project becomes read-only.
|
||||
project_a
|
||||
|
@ -1409,7 +1409,7 @@ async fn test_unshare_project(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_c2 = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_c2 = client_c.join_remote_project(project_id, cx_c).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
|
||||
|
@ -1514,9 +1514,9 @@ async fn test_project_reconnect(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b1 = client_b.build_dev_server_project(project1_id, cx_b).await;
|
||||
let project_b2 = client_b.build_dev_server_project(project2_id, cx_b).await;
|
||||
let project_b3 = client_b.build_dev_server_project(project3_id, cx_b).await;
|
||||
let project_b1 = client_b.join_remote_project(project1_id, cx_b).await;
|
||||
let project_b2 = client_b.join_remote_project(project2_id, cx_b).await;
|
||||
let project_b3 = client_b.join_remote_project(project3_id, cx_b).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
let worktree1_id = worktree_a1.read_with(cx_a, |worktree, _| {
|
||||
|
@ -2310,8 +2310,8 @@ async fn test_propagate_saves_and_fs_changes(
|
|||
.unwrap();
|
||||
|
||||
// Join that worktree as clients B and C.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let project_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
|
||||
let worktree_b = project_b.read_with(cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||
|
||||
|
@ -2535,7 +2535,7 @@ async fn test_git_diff_base_change(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let diff_base = "
|
||||
one
|
||||
|
@ -2791,7 +2791,7 @@ async fn test_git_branch_name(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
|
||||
client_a
|
||||
.fs()
|
||||
.set_branch_name(Path::new("/dir/.git"), Some("branch-1"));
|
||||
|
@ -2836,7 +2836,7 @@ async fn test_git_branch_name(
|
|||
assert_branch(Some("branch-2"), project, cx)
|
||||
});
|
||||
|
||||
let project_remote_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_remote_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
project_remote_c.read_with(cx_c, |project, cx| {
|
||||
|
@ -2891,7 +2891,7 @@ async fn test_git_status_sync(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Wait for it to catch up to the new status
|
||||
executor.run_until_parked();
|
||||
|
@ -2967,7 +2967,7 @@ async fn test_git_status_sync(
|
|||
});
|
||||
|
||||
// And synchronization while joining
|
||||
let project_remote_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_remote_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
project_remote_c.read_with(cx_c, |project, cx| {
|
||||
|
@ -3015,7 +3015,7 @@ async fn test_fs_operations(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
|
@ -3316,7 +3316,7 @@ async fn test_local_settings(
|
|||
executor.run_until_parked();
|
||||
|
||||
// As client B, join that project and observe the local settings.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
|
||||
executor.run_until_parked();
|
||||
|
@ -3439,7 +3439,7 @@ async fn test_buffer_conflict_after_save(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a buffer as client B
|
||||
let buffer_b = project_b
|
||||
|
@ -3503,7 +3503,7 @@ async fn test_buffer_reloading(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a buffer as client B
|
||||
let buffer_b = project_b
|
||||
|
@ -3557,7 +3557,7 @@ async fn test_editing_while_guest_opens_buffer(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open a buffer as client A
|
||||
let buffer_a = project_a
|
||||
|
@ -3605,7 +3605,7 @@ async fn test_leaving_worktree_while_opening_buffer(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// See that a guest has joined as client A.
|
||||
executor.run_until_parked();
|
||||
|
@ -3652,7 +3652,7 @@ async fn test_canceling_buffer_opening(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let buffer_a = project_a
|
||||
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
|
||||
|
@ -3709,8 +3709,8 @@ async fn test_leaving_project(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b1 = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_b1 = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let project_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
|
||||
// Client A sees that a guest has joined.
|
||||
executor.run_until_parked();
|
||||
|
@ -3751,7 +3751,7 @@ async fn test_leaving_project(
|
|||
});
|
||||
|
||||
// Client B re-joins the project and can open buffers as before.
|
||||
let project_b2 = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b2 = client_b.join_remote_project(project_id, cx_b).await;
|
||||
executor.run_until_parked();
|
||||
|
||||
project_a.read_with(cx_a, |project, _| {
|
||||
|
@ -3927,7 +3927,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
);
|
||||
|
||||
// Join the worktree as client B.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Wait for server to see the diagnostics update.
|
||||
executor.run_until_parked();
|
||||
|
@ -3952,7 +3952,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
});
|
||||
|
||||
// Join project as client C and observe the diagnostics.
|
||||
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
|
||||
let project_c = client_c.join_remote_project(project_id, cx_c).await;
|
||||
executor.run_until_parked();
|
||||
let project_c_diagnostic_summaries =
|
||||
Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
|
||||
|
@ -4160,7 +4160,7 @@ async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
|
|||
.unwrap();
|
||||
|
||||
// Join the project as client B and open all three files.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let guest_buffers = futures::future::try_join_all(file_names.iter().map(|file_name| {
|
||||
project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, file_name), cx))
|
||||
}))
|
||||
|
@ -4266,7 +4266,7 @@ async fn test_reloading_buffer_manually(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
|
||||
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
|
||||
|
@ -4364,7 +4364,7 @@ async fn test_formatting_buffer(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
|
||||
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
|
||||
|
@ -4486,7 +4486,7 @@ async fn test_prettier_formatting_buffer(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.ts"), cx));
|
||||
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
|
||||
|
||||
|
@ -4599,7 +4599,7 @@ async fn test_definition(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open the file on client B.
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
|
||||
|
@ -4744,7 +4744,7 @@ async fn test_references(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open the file on client B.
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx));
|
||||
|
@ -4901,7 +4901,7 @@ async fn test_project_search(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Perform a search as the guest.
|
||||
let mut results = HashMap::default();
|
||||
|
@ -4991,7 +4991,7 @@ async fn test_document_highlights(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open the file on client B.
|
||||
let open_b = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx));
|
||||
|
@ -5109,7 +5109,7 @@ async fn test_lsp_hover(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Open the file as the guest
|
||||
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx));
|
||||
|
@ -5286,7 +5286,7 @@ async fn test_project_symbols(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Cause the language server to start.
|
||||
let open_buffer_task =
|
||||
|
@ -5381,7 +5381,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
let open_buffer_task = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
|
||||
let buffer_b1 = cx_b.executor().spawn(open_buffer_task).await.unwrap();
|
||||
|
@ -6470,7 +6470,7 @@ async fn test_context_collaboration_with_reconnect(
|
|||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
|
||||
// Client A sees that a guest has joined.
|
||||
executor.run_until_parked();
|
||||
|
|
|
@ -9,7 +9,7 @@ use remote_server::HeadlessProject;
|
|||
use serde_json::json;
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
#[gpui::test]
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_sharing_an_ssh_remote_project(
|
||||
cx_a: &mut TestAppContext,
|
||||
cx_b: &mut TestAppContext,
|
||||
|
@ -54,9 +54,8 @@ async fn test_sharing_an_ssh_remote_project(
|
|||
let (project_a, worktree_id) = client_a
|
||||
.build_ssh_project("/code/project1", client_ssh, cx_a)
|
||||
.await;
|
||||
executor.run_until_parked();
|
||||
|
||||
// User A shares the remote project.
|
||||
// While the SSH worktree is being scanned, user A shares the remote project.
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
let project_id = active_call_a
|
||||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
|
@ -64,12 +63,30 @@ async fn test_sharing_an_ssh_remote_project(
|
|||
.unwrap();
|
||||
|
||||
// User B joins the project.
|
||||
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let worktree_b = project_b
|
||||
.update(cx_b, |project, cx| project.worktree_for_id(worktree_id, cx))
|
||||
.unwrap();
|
||||
|
||||
let worktree_a = project_a
|
||||
.update(cx_a, |project, cx| project.worktree_for_id(worktree_id, cx))
|
||||
.unwrap();
|
||||
|
||||
executor.run_until_parked();
|
||||
|
||||
worktree_a.update(cx_a, |worktree, _cx| {
|
||||
assert_eq!(
|
||||
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
|
||||
vec![
|
||||
Path::new(".zed"),
|
||||
Path::new(".zed/settings.json"),
|
||||
Path::new("README.md"),
|
||||
Path::new("src"),
|
||||
Path::new("src/lib.rs"),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
worktree_b.update(cx_b, |worktree, _cx| {
|
||||
assert_eq!(
|
||||
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
|
||||
|
|
|
@ -921,7 +921,7 @@ impl TestClient {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn build_dev_server_project(
|
||||
pub async fn join_remote_project(
|
||||
&self,
|
||||
host_project_id: u64,
|
||||
guest_cx: &mut TestAppContext,
|
||||
|
|
|
@ -204,8 +204,11 @@ impl WorktreeStore {
|
|||
self.loading_worktrees.insert(path.clone(), task.shared());
|
||||
}
|
||||
let task = self.loading_worktrees.get(&path).unwrap().clone();
|
||||
cx.background_executor().spawn(async move {
|
||||
match task.await {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let result = task.await;
|
||||
this.update(&mut cx, |this, _| this.loading_worktrees.remove(&path))
|
||||
.ok();
|
||||
match result {
|
||||
Ok(worktree) => Ok(worktree),
|
||||
Err(err) => Err((*err).cloned()),
|
||||
}
|
||||
|
@ -219,7 +222,8 @@ impl WorktreeStore {
|
|||
visible: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<Worktree>, Arc<anyhow::Error>>> {
|
||||
let mut abs_path = abs_path.as_ref().to_string_lossy().to_string();
|
||||
let path_key: Arc<Path> = abs_path.as_ref().into();
|
||||
let mut abs_path = path_key.clone().to_string_lossy().to_string();
|
||||
// If we start with `/~` that means the ssh path was something like `ssh://user@host/~/home-dir-folder/`
|
||||
// in which case want to strip the leading the `/`.
|
||||
// On the host-side, the `~` will get expanded.
|
||||
|
@ -261,8 +265,9 @@ impl WorktreeStore {
|
|||
)
|
||||
})?;
|
||||
|
||||
this.update(&mut cx, |this, cx| this.add(&worktree, cx))?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.add(&worktree, cx);
|
||||
})?;
|
||||
Ok(worktree)
|
||||
})
|
||||
}
|
||||
|
@ -280,10 +285,6 @@ impl WorktreeStore {
|
|||
cx.spawn(move |this, mut cx| async move {
|
||||
let worktree = Worktree::local(path.clone(), visible, fs, next_entry_id, &mut cx).await;
|
||||
|
||||
this.update(&mut cx, |project, _| {
|
||||
project.loading_worktrees.remove(&path);
|
||||
})?;
|
||||
|
||||
let worktree = worktree?;
|
||||
this.update(&mut cx, |this, cx| this.add(&worktree, cx))?;
|
||||
|
||||
|
@ -317,7 +318,7 @@ impl WorktreeStore {
|
|||
});
|
||||
|
||||
let abs_path = abs_path.as_ref().to_path_buf();
|
||||
cx.spawn(move |project, mut cx| async move {
|
||||
cx.spawn(move |project, cx| async move {
|
||||
let (tx, rx) = futures::channel::oneshot::channel();
|
||||
let tx = RefCell::new(Some(tx));
|
||||
let Some(project) = project.upgrade() else {
|
||||
|
@ -339,14 +340,10 @@ impl WorktreeStore {
|
|||
request.await?;
|
||||
let worktree = rx.await.map_err(|e| anyhow!(e))?;
|
||||
drop(observer);
|
||||
project.update(&mut cx, |project, _| {
|
||||
project.loading_worktrees.remove(&path);
|
||||
})?;
|
||||
Ok(worktree)
|
||||
})
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn add(&mut self, worktree: &Model<Worktree>, cx: &mut ModelContext<Self>) {
|
||||
let worktree_id = worktree.read(cx).id();
|
||||
debug_assert!(self.worktrees().all(|w| w.read(cx).id() != worktree_id));
|
||||
|
@ -553,9 +550,12 @@ impl WorktreeStore {
|
|||
let client = client.clone();
|
||||
async move {
|
||||
if client.is_via_collab() {
|
||||
client.request(update).map(|result| result.is_ok()).await
|
||||
client
|
||||
.request(update)
|
||||
.map(|result| result.log_err().is_some())
|
||||
.await
|
||||
} else {
|
||||
client.send(update).is_ok()
|
||||
client.send(update).log_err().is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -564,6 +564,48 @@ async fn test_canceling_buffer_opening(cx: &mut TestAppContext, server_cx: &mut
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_adding_then_removing_then_adding_worktrees(
|
||||
cx: &mut TestAppContext,
|
||||
server_cx: &mut TestAppContext,
|
||||
) {
|
||||
let (project, _headless, _fs) = init_test(cx, server_cx).await;
|
||||
let (_worktree, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_worktree("/code/project1", true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let (worktree_2, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_worktree("/code/project2", true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let worktree_id_2 = worktree_2.read_with(cx, |tree, _| tree.id());
|
||||
|
||||
project.update(cx, |project, cx| project.remove_worktree(worktree_id_2, cx));
|
||||
|
||||
let (worktree_2, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_worktree("/code/project2", true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
worktree_2.update(cx, |worktree, _cx| {
|
||||
assert!(worktree.is_visible());
|
||||
let entries = worktree.entries(true, 0).collect::<Vec<_>>();
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(
|
||||
entries[1].path.to_string_lossy().to_string(),
|
||||
"README.md".to_string()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
if std::env::var("RUST_LOG").is_ok() {
|
||||
env_logger::try_init().ok();
|
||||
|
|
|
@ -1826,10 +1826,13 @@ impl RemoteWorktree {
|
|||
let initial_update = self
|
||||
.snapshot
|
||||
.build_initial_update(project_id, self.id().to_proto());
|
||||
self.updates_tx = Some(tx);
|
||||
self.update_observer = Some(tx);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let mut update = initial_update;
|
||||
loop {
|
||||
// SSH projects use a special project ID of 0, and we need to
|
||||
// remap it to the correct one here.
|
||||
update.project_id = project_id;
|
||||
if !callback(update).await {
|
||||
break;
|
||||
}
|
||||
|
@ -1841,7 +1844,7 @@ impl RemoteWorktree {
|
|||
}
|
||||
this.update(&mut cx, |this, _| {
|
||||
let this = this.as_remote_mut().unwrap();
|
||||
this.updates_tx.take();
|
||||
this.update_observer.take();
|
||||
})
|
||||
})
|
||||
.detach();
|
||||
|
|
|
@ -9,12 +9,18 @@ SUMMARY
|
|||
Each instance of Zed will be signed in as a different user specified in
|
||||
either \`.admins.json\` or \`.admins.default.json\`.
|
||||
|
||||
All arguments after the initial options will be passed through to the first
|
||||
instance of Zed. This can be used to test SSH remoting along with collab, like
|
||||
so:
|
||||
|
||||
$ script/zed-local -2 ssh://your-ssh-uri-here
|
||||
|
||||
OPTIONS
|
||||
--help Print this help message
|
||||
--release Build Zed in release mode
|
||||
-2, -3, -4, ... Spawn multiple Zed instances, with their windows tiled.
|
||||
--top Arrange the Zed windows so they take up the top half of the screen.
|
||||
--stable Use stable Zed release installed on local machine for all instances (except for the first one).
|
||||
--help Print this help message
|
||||
--release Build Zed in release mode
|
||||
-2, -3, -4, ... Spawn multiple Zed instances, with their windows tiled.
|
||||
--top Arrange the Zed windows so they take up the top half of the screen.
|
||||
--stable Use stable Zed release installed on local machine for all instances (except for the first one).
|
||||
`.trim();
|
||||
|
||||
const { spawn, execSync, execFileSync } = require("child_process");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue