Detailed changes
@@ -994,6 +994,7 @@ async fn test_ssh_remote_worktree_trust(cx_a: &mut TestAppContext, server_cx: &m
let remote_host = project_a.read_with(cx_a, |project, cx| {
project
.remote_connection_options(cx)
+ .map(|options| (0, options))
.map(RemoteHostLocation::from)
});
@@ -271,16 +271,24 @@ impl WorktreeListDelegate {
if let Some((parent_worktree, _)) =
project.read(cx).find_worktree(repo_path, cx)
{
+ let remote_host = project.read_with(cx, |project, cx| {
+ project
+ .lsp_store()
+ .read(cx)
+ .downstream_client()
+ .or_else(|| project.lsp_store().read(cx).upstream_client())
+ .map(|(_, project_id)| project_id)
+ .zip(project.remote_connection_options(cx))
+ .map(RemoteHostLocation::from)
+ });
+
trusted_worktrees.update(cx, |trusted_worktrees, cx| {
if trusted_worktrees.can_trust(parent_worktree.read(cx).id(), cx) {
trusted_worktrees.trust(
HashSet::from_iter([PathTrust::AbsPath(
new_worktree_path.clone(),
)]),
- project
- .read(cx)
- .remote_connection_options(cx)
- .map(RemoteHostLocation::from),
+ remote_host,
cx,
);
}
@@ -52,7 +52,9 @@ pub use project_search::Search;
use anyhow::{Context as _, Result, anyhow};
use buffer_store::{BufferStore, BufferStoreEvent};
-use client::{Client, Collaborator, PendingEntitySubscription, TypedEnvelope, UserStore, proto};
+use client::{
+ Client, Collaborator, PendingEntitySubscription, ProjectId, TypedEnvelope, UserStore, proto,
+};
use clock::ReplicaId;
use dap::client::DebugAdapterClient;
@@ -1295,9 +1297,12 @@ impl Project {
if init_worktree_trust {
trusted_worktrees::track_worktree_trust(
worktree_store.clone(),
- Some(RemoteHostLocation::from(connection_options)),
+ Some(RemoteHostLocation::from((
+ REMOTE_SERVER_PROJECT_ID,
+ connection_options,
+ ))),
None,
- Some((remote_proto.clone(), REMOTE_SERVER_PROJECT_ID)),
+ Some((remote_proto.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))),
cx,
);
}
@@ -4872,6 +4877,7 @@ impl Project {
let remote_host = this
.read(cx)
.remote_connection_options(cx)
+ .map(|options| (envelope.payload.project_id, options))
.map(RemoteHostLocation::from);
trusted_worktrees.trust(
envelope
@@ -4906,6 +4912,7 @@ impl Project {
let remote_host = this
.read(cx)
.remote_connection_options(cx)
+ .map(|options| (envelope.payload.project_id, options))
.map(RemoteHostLocation::from);
trusted_worktrees.restrict(restricted_paths, remote_host, cx);
})?;
@@ -39,6 +39,7 @@
//! To ease trusting multiple directory worktrees at once, it's possible to trust a parent directory of a certain directory worktree opened in Zed.
//! Trusting a directory means trusting all its subdirectories as well, including all current and potential directory worktrees.
+use client::ProjectId;
use collections::{HashMap, HashSet};
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Global, SharedString, WeakEntity};
use remote::RemoteConnectionOptions;
@@ -54,8 +55,8 @@ use crate::{project_settings::ProjectSettings, worktree_store::WorktreeStore};
pub fn init(
db_trusted_paths: TrustedPaths,
- downstream_client: Option<(AnyProtoClient, u64)>,
- upstream_client: Option<(AnyProtoClient, u64)>,
+ downstream_client: Option<(AnyProtoClient, ProjectId)>,
+ upstream_client: Option<(AnyProtoClient, ProjectId)>,
cx: &mut App,
) {
if TrustedWorktrees::try_get_global(cx).is_none() {
@@ -76,8 +77,8 @@ pub fn init(
pub fn track_worktree_trust(
worktree_store: Entity<WorktreeStore>,
remote_host: Option<RemoteHostLocation>,
- downstream_client: Option<(AnyProtoClient, u64)>,
- upstream_client: Option<(AnyProtoClient, u64)>,
+ downstream_client: Option<(AnyProtoClient, ProjectId)>,
+ upstream_client: Option<(AnyProtoClient, ProjectId)>,
cx: &mut App,
) {
match TrustedWorktrees::try_get_global(cx) {
@@ -103,7 +104,7 @@ pub fn track_worktree_trust(
if !trusted_paths.is_empty() {
upstream_client
.send(proto::TrustWorktrees {
- project_id: *upstream_project_id,
+ project_id: upstream_project_id.0,
trusted_paths,
})
.ok();
@@ -133,8 +134,8 @@ impl TrustedWorktrees {
/// Emits an event each time the worktree was checked and found not trusted,
/// or a certain worktree had been trusted.
pub struct TrustedWorktreesStore {
- downstream_client: Option<(AnyProtoClient, u64)>,
- upstream_client: Option<(AnyProtoClient, u64)>,
+ downstream_client: Option<(AnyProtoClient, ProjectId)>,
+ upstream_client: Option<(AnyProtoClient, ProjectId)>,
worktree_stores: HashMap<WeakEntity<WorktreeStore>, Option<RemoteHostLocation>>,
trusted_paths: TrustedPaths,
restricted: HashSet<WorktreeId>,
@@ -147,10 +148,11 @@ pub struct TrustedWorktreesStore {
pub struct RemoteHostLocation {
pub user_name: Option<SharedString>,
pub host_identifier: SharedString,
+ pub project_id: ProjectId,
}
-impl From<RemoteConnectionOptions> for RemoteHostLocation {
- fn from(options: RemoteConnectionOptions) -> Self {
+impl From<(u64, RemoteConnectionOptions)> for RemoteHostLocation {
+ fn from((project_id, options): (u64, RemoteConnectionOptions)) -> Self {
let (user_name, host_name) = match options {
RemoteConnectionOptions::Ssh(ssh) => (
ssh.username.map(SharedString::new),
@@ -165,9 +167,10 @@ impl From<RemoteConnectionOptions> for RemoteHostLocation {
SharedString::new(docker_connection_options.container_id),
),
};
- RemoteHostLocation {
+ Self {
user_name,
host_identifier: host_name,
+ project_id: ProjectId(project_id),
}
}
}
@@ -227,8 +230,8 @@ impl TrustedWorktreesStore {
trusted_paths: TrustedPaths,
worktree_store: Option<Entity<WorktreeStore>>,
remote_host: Option<RemoteHostLocation>,
- downstream_client: Option<(AnyProtoClient, u64)>,
- upstream_client: Option<(AnyProtoClient, u64)>,
+ downstream_client: Option<(AnyProtoClient, ProjectId)>,
+ upstream_client: Option<(AnyProtoClient, ProjectId)>,
) -> Self {
if let Some((upstream_client, upstream_project_id)) = &upstream_client {
let trusted_paths = trusted_paths
@@ -238,7 +241,7 @@ impl TrustedWorktreesStore {
if !trusted_paths.is_empty() {
upstream_client
.send(proto::TrustWorktrees {
- project_id: *upstream_project_id,
+ project_id: upstream_project_id.0,
trusted_paths,
})
.ok();
@@ -383,7 +386,7 @@ impl TrustedWorktreesStore {
if !trusted_paths.is_empty() {
upstream_client
.send(proto::TrustWorktrees {
- project_id: *upstream_project_id,
+ project_id: upstream_project_id.0,
trusted_paths,
})
.ok();
@@ -472,7 +475,7 @@ impl TrustedWorktreesStore {
if let Some((downstream_client, downstream_project_id)) = &self.downstream_client {
downstream_client
.send(proto::RestrictWorktrees {
- project_id: *downstream_project_id,
+ project_id: downstream_project_id.0,
worktree_ids: vec![worktree_id.to_proto()],
})
.ok();
@@ -480,7 +483,7 @@ impl TrustedWorktreesStore {
if let Some((upstream_client, upstream_project_id)) = &self.upstream_client {
upstream_client
.send(proto::RestrictWorktrees {
- project_id: *upstream_project_id,
+ project_id: upstream_project_id.0,
worktree_ids: vec![worktree_id.to_proto()],
})
.ok();
@@ -1440,8 +1443,6 @@ mod tests {
let trusted_worktrees = init_trust_global(worktree_store, cx);
- let host_a: Option<RemoteHostLocation> = None;
-
let can_trust_local =
trusted_worktrees.update(cx, |store, cx| store.can_trust(local_worktree, cx));
assert!(!can_trust_local, "local worktree restricted on host_a");
@@ -1449,7 +1450,7 @@ mod tests {
trusted_worktrees.update(cx, |store, cx| {
store.trust(
HashSet::from_iter([PathTrust::Worktree(local_worktree)]),
- host_a.clone(),
+ None,
cx,
);
});
@@ -1458,7 +1459,7 @@ mod tests {
trusted_worktrees.update(cx, |store, cx| store.can_trust(local_worktree, cx));
assert!(
can_trust_local_after,
- "local worktree should be trusted on host_a"
+ "local worktree should be trusted on local host"
);
}
}
@@ -1,4 +1,5 @@
use anyhow::{Context as _, Result, anyhow};
+use client::ProjectId;
use collections::HashSet;
use language::File;
use lsp::LanguageServerId;
@@ -104,7 +105,7 @@ impl HeadlessProject {
project::trusted_worktrees::track_worktree_trust(
worktree_store.clone(),
None::<RemoteHostLocation>,
- Some((session.clone(), REMOTE_SERVER_PROJECT_ID)),
+ Some((session.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))),
None,
cx,
);
@@ -1,7 +1,7 @@
use crate::HeadlessProject;
use crate::headless_project::HeadlessAppState;
use anyhow::{Context as _, Result, anyhow};
-use client::ProxySettings;
+use client::{ProjectId, ProxySettings};
use collections::HashMap;
use project::trusted_worktrees;
use util::ResultExt;
@@ -419,7 +419,7 @@ pub fn execute_run(
log::info!("gpui app started, initializing server");
let session = start_server(listeners, log_rx, cx, is_wsl_interop);
- trusted_worktrees::init(HashMap::default(), Some((session.clone(), REMOTE_SERVER_PROJECT_ID)), None, cx);
+ trusted_worktrees::init(HashMap::default(), Some((session.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))), None, cx);
GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
git_hosting_providers::init(cx);
@@ -9,6 +9,7 @@ use std::{
};
use anyhow::{Context as _, Result, bail};
+use client::ProjectId;
use collections::{HashMap, HashSet, IndexSet};
use db::{
kvp::KEY_VALUE_STORE,
@@ -844,6 +845,9 @@ impl Domain for WorkspaceDb {
host_name TEXT
) STRICT;
),
+ sql!(
+ ALTER TABLE trusted_worktrees ADD COLUMN project_id INTEGER;
+ ),
sql!(CREATE TABLE toolchains2 (
workspace_id INTEGER,
worktree_root_path TEXT NOT NULL,
@@ -1977,10 +1981,10 @@ impl WorkspaceDb {
.collect::<Vec<_>>();
let mut first_worktree;
let mut last_worktree = 0_usize;
- for (count, placeholders) in std::iter::once("(?, ?, ?)")
+ for (count, placeholders) in std::iter::once("(?, ?, ?, ?)")
.cycle()
.take(trusted_worktrees.len())
- .chunks(MAX_QUERY_PLACEHOLDERS / 3)
+ .chunks(MAX_QUERY_PLACEHOLDERS / 4)
.into_iter()
.map(|chunk| {
let mut count = 0;
@@ -1996,7 +2000,7 @@ impl WorkspaceDb {
first_worktree = last_worktree;
last_worktree = last_worktree + count;
let query = format!(
- r#"INSERT INTO trusted_worktrees(absolute_path, user_name, host_name)
+ r#"INSERT INTO trusted_worktrees(absolute_path, user_name, host_name, project_id)
VALUES {placeholders};"#
);
@@ -2020,6 +2024,8 @@ VALUES {placeholders};"#
&host.as_ref().map(|host| host.host_identifier.as_str()),
next_index,
)?;
+ next_index =
+ statement.bind(&host.as_ref().map(|host| host.project_id.0), next_index)?;
}
statement.exec()
})
@@ -2038,17 +2044,21 @@ VALUES {placeholders};"#
let trusted_worktrees = DB.trusted_worktrees()?;
Ok(trusted_worktrees
.into_iter()
- .filter_map(|(abs_path, user_name, host_name)| {
- let db_host = match (user_name, host_name) {
- (_, None) => None,
- (None, Some(host_name)) => Some(RemoteHostLocation {
+ .filter_map(|(abs_path, user_name, host_name, project_id)| {
+ let db_host = match (user_name, host_name, project_id) {
+ (None, Some(host_name), Some(project_id)) => Some(RemoteHostLocation {
user_name: None,
host_identifier: SharedString::new(host_name),
+ project_id: ProjectId(project_id),
}),
- (Some(user_name), Some(host_name)) => Some(RemoteHostLocation {
- user_name: Some(SharedString::new(user_name)),
- host_identifier: SharedString::new(host_name),
- }),
+ (Some(user_name), Some(host_name), Some(project_id)) => {
+ Some(RemoteHostLocation {
+ user_name: Some(SharedString::new(user_name)),
+ host_identifier: SharedString::new(host_name),
+ project_id: ProjectId(project_id),
+ })
+ }
+ _ => None,
};
let abs_path = abs_path?;
@@ -2072,8 +2082,8 @@ VALUES {placeholders};"#
}
query! {
- fn trusted_worktrees() -> Result<Vec<(Option<PathBuf>, Option<String>, Option<String>)>> {
- SELECT absolute_path, user_name, host_name
+ fn trusted_worktrees() -> Result<Vec<(Option<PathBuf>, Option<String>, Option<String>, Option<u64>)>> {
+ SELECT absolute_path, user_name, host_name, project_id
FROM trusted_worktrees
}
}
@@ -80,7 +80,7 @@ use project::{
debugger::{breakpoint_store::BreakpointStoreEvent, session::ThreadStatus},
project_settings::ProjectSettings,
toolchain_store::ToolchainStoreEvent,
- trusted_worktrees::{TrustedWorktrees, TrustedWorktreesEvent},
+ trusted_worktrees::{RemoteHostLocation, TrustedWorktrees, TrustedWorktreesEvent},
};
use remote::{
RemoteClientDelegate, RemoteConnection, RemoteConnectionOptions,
@@ -6620,7 +6620,15 @@ impl Workspace {
.unwrap_or(false);
if has_restricted_worktrees {
let project = self.project().read(cx);
- let remote_host = project.remote_connection_options(cx);
+ let project_id = project
+ .lsp_store()
+ .read(cx)
+ .downstream_client()
+ .or_else(|| project.lsp_store().read(cx).upstream_client())
+ .map(|(_, project_id)| project_id);
+ let remote_host = project_id
+ .zip(project.remote_connection_options(cx))
+ .map(RemoteHostLocation::from);
let worktree_store = project.worktree_store().downgrade();
self.toggle_modal(window, cx, |_, cx| {
SecurityModal::new(worktree_store, remote_host, cx)