Remove dev servers (#19638)
TODO: - [ ] Check that workspace migration worked - [ ] Add server migrations and make sure SeaORM files are in sync (maybe?) Release Notes: - N/A --------- Co-authored-by: Conrad <conrad@zed.dev> Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
co-authored by
Conrad
Conrad Irwin
parent
b5f816dde5
commit
02718284ef
@@ -25,8 +25,7 @@ mod yarn;
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use buffer_store::{BufferStore, BufferStoreEvent};
|
||||
use client::{
|
||||
proto, Client, Collaborator, DevServerProjectId, PendingEntitySubscription, ProjectId,
|
||||
TypedEnvelope, UserStore,
|
||||
proto, Client, Collaborator, PendingEntitySubscription, ProjectId, TypedEnvelope, UserStore,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeSet, HashMap, HashSet};
|
||||
@@ -156,7 +155,6 @@ pub struct Project {
|
||||
terminals: Terminals,
|
||||
node: Option<NodeRuntime>,
|
||||
hosted_project_id: Option<ProjectId>,
|
||||
dev_server_project_id: Option<client::DevServerProjectId>,
|
||||
search_history: SearchHistory,
|
||||
search_included_history: SearchHistory,
|
||||
search_excluded_history: SearchHistory,
|
||||
@@ -217,7 +215,6 @@ enum ProjectClientState {
|
||||
capability: Capability,
|
||||
remote_id: u64,
|
||||
replica_id: ReplicaId,
|
||||
in_room: bool,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -675,7 +672,6 @@ impl Project {
|
||||
},
|
||||
node: Some(node),
|
||||
hosted_project_id: None,
|
||||
dev_server_project_id: None,
|
||||
search_history: Self::new_search_history(),
|
||||
environment,
|
||||
remotely_created_models: Default::default(),
|
||||
@@ -705,7 +701,7 @@ impl Project {
|
||||
|
||||
let ssh_proto = ssh.read(cx).proto_client();
|
||||
let worktree_store =
|
||||
cx.new_model(|_| WorktreeStore::remote(false, ssh_proto.clone(), 0, None));
|
||||
cx.new_model(|_| WorktreeStore::remote(false, ssh_proto.clone(), 0));
|
||||
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
||||
.detach();
|
||||
|
||||
@@ -794,7 +790,6 @@ impl Project {
|
||||
},
|
||||
node: Some(node),
|
||||
hosted_project_id: None,
|
||||
dev_server_project_id: None,
|
||||
search_history: Self::new_search_history(),
|
||||
environment,
|
||||
remotely_created_models: Default::default(),
|
||||
@@ -898,15 +893,7 @@ impl Project {
|
||||
let role = response.payload.role();
|
||||
|
||||
let worktree_store = cx.new_model(|_| {
|
||||
WorktreeStore::remote(
|
||||
true,
|
||||
client.clone().into(),
|
||||
response.payload.project_id,
|
||||
response
|
||||
.payload
|
||||
.dev_server_project_id
|
||||
.map(DevServerProjectId),
|
||||
)
|
||||
WorktreeStore::remote(true, client.clone().into(), response.payload.project_id)
|
||||
})?;
|
||||
let buffer_store = cx.new_model(|cx| {
|
||||
BufferStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
|
||||
@@ -992,7 +979,6 @@ impl Project {
|
||||
capability: Capability::ReadWrite,
|
||||
remote_id,
|
||||
replica_id,
|
||||
in_room: response.payload.dev_server_project_id.is_none(),
|
||||
},
|
||||
buffers_needing_diff: Default::default(),
|
||||
git_diff_debouncer: DebouncedDelay::new(),
|
||||
@@ -1001,10 +987,6 @@ impl Project {
|
||||
},
|
||||
node: None,
|
||||
hosted_project_id: None,
|
||||
dev_server_project_id: response
|
||||
.payload
|
||||
.dev_server_project_id
|
||||
.map(DevServerProjectId),
|
||||
search_history: Self::new_search_history(),
|
||||
search_included_history: Self::new_search_history(),
|
||||
search_excluded_history: Self::new_search_history(),
|
||||
@@ -1305,39 +1287,23 @@ impl Project {
|
||||
self.hosted_project_id
|
||||
}
|
||||
|
||||
pub fn dev_server_project_id(&self) -> Option<DevServerProjectId> {
|
||||
self.dev_server_project_id
|
||||
}
|
||||
|
||||
pub fn supports_terminal(&self, cx: &AppContext) -> bool {
|
||||
pub fn supports_terminal(&self, _cx: &AppContext) -> bool {
|
||||
if self.is_local() {
|
||||
return true;
|
||||
}
|
||||
if self.is_via_ssh() {
|
||||
return true;
|
||||
}
|
||||
let Some(id) = self.dev_server_project_id else {
|
||||
return false;
|
||||
};
|
||||
let Some(server) = dev_server_projects::Store::global(cx)
|
||||
.read(cx)
|
||||
.dev_server_for_project(id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
server.ssh_connection_string.is_some()
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn ssh_connection_string(&self, cx: &AppContext) -> Option<SharedString> {
|
||||
if let Some(ssh_state) = &self.ssh_client {
|
||||
return Some(ssh_state.read(cx).connection_string().into());
|
||||
}
|
||||
let dev_server_id = self.dev_server_project_id()?;
|
||||
dev_server_projects::Store::global(cx)
|
||||
.read(cx)
|
||||
.dev_server_for_project(dev_server_id)?
|
||||
.ssh_connection_string
|
||||
.clone()
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn ssh_connection_state(&self, cx: &AppContext) -> Option<remote::ConnectionState> {
|
||||
@@ -1549,17 +1515,9 @@ impl Project {
|
||||
|
||||
pub fn shared(&mut self, project_id: u64, cx: &mut ModelContext<Self>) -> Result<()> {
|
||||
if !matches!(self.client_state, ProjectClientState::Local) {
|
||||
if let ProjectClientState::Remote { in_room, .. } = &mut self.client_state {
|
||||
if *in_room || self.dev_server_project_id.is_none() {
|
||||
return Err(anyhow!("project was already shared"));
|
||||
} else {
|
||||
*in_room = true;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow!("project was already shared"));
|
||||
}
|
||||
return Err(anyhow!("project was already shared"));
|
||||
}
|
||||
|
||||
self.client_subscriptions.extend([
|
||||
self.client
|
||||
.subscribe_to_entity(project_id)?
|
||||
@@ -1657,14 +1615,7 @@ impl Project {
|
||||
|
||||
fn unshare_internal(&mut self, cx: &mut AppContext) -> Result<()> {
|
||||
if self.is_via_collab() {
|
||||
if self.dev_server_project_id().is_some() {
|
||||
if let ProjectClientState::Remote { in_room, .. } = &mut self.client_state {
|
||||
*in_room = false
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(anyhow!("attempted to unshare a remote project"));
|
||||
}
|
||||
return Err(anyhow!("attempted to unshare a remote project"));
|
||||
}
|
||||
|
||||
if let ProjectClientState::Shared { remote_id, .. } = self.client_state {
|
||||
@@ -2265,29 +2216,6 @@ impl Project {
|
||||
}
|
||||
|
||||
fn on_worktree_released(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
||||
if let Some(dev_server_project_id) = self.dev_server_project_id {
|
||||
let paths: Vec<String> = self
|
||||
.visible_worktrees(cx)
|
||||
.filter_map(|worktree| {
|
||||
if worktree.read(cx).id() == id_to_remove {
|
||||
None
|
||||
} else {
|
||||
Some(worktree.read(cx).abs_path().to_string_lossy().to_string())
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if !paths.is_empty() {
|
||||
let request = self.client.request(proto::UpdateDevServerProject {
|
||||
dev_server_project_id: dev_server_project_id.0,
|
||||
paths,
|
||||
});
|
||||
cx.background_executor()
|
||||
.spawn(request)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ssh) = &self.ssh_client {
|
||||
ssh.read(cx)
|
||||
.proto_client()
|
||||
@@ -3152,7 +3080,7 @@ impl Project {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Shared { .. } => true,
|
||||
ProjectClientState::Local => false,
|
||||
ProjectClientState::Remote { in_room, .. } => *in_room,
|
||||
ProjectClientState::Remote { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3279,20 +3207,6 @@ impl Project {
|
||||
let response = response.await?;
|
||||
Ok(response.entries.into_iter().map(PathBuf::from).collect())
|
||||
})
|
||||
} else if let Some(dev_server) = self.dev_server_project_id().and_then(|id| {
|
||||
dev_server_projects::Store::global(cx)
|
||||
.read(cx)
|
||||
.dev_server_for_project(id)
|
||||
}) {
|
||||
let request = proto::ListRemoteDirectory {
|
||||
dev_server_id: dev_server.id.0,
|
||||
path: query,
|
||||
};
|
||||
let response = self.client.request(request);
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = response.await?;
|
||||
Ok(response.entries.into_iter().map(PathBuf::from).collect())
|
||||
})
|
||||
} else {
|
||||
Task::ready(Err(anyhow!("cannot list directory in remote project")))
|
||||
}
|
||||
|
||||
@@ -37,11 +37,8 @@ pub enum TerminalKind {
|
||||
|
||||
/// SshCommand describes how to connect to a remote server
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SshCommand {
|
||||
/// DevServers give a string from the user
|
||||
DevServer(String),
|
||||
/// Direct ssh has a list of arguments to pass to ssh
|
||||
Direct(Vec<String>),
|
||||
pub struct SshCommand {
|
||||
arguments: Vec<String>,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
@@ -73,19 +70,12 @@ impl Project {
|
||||
if let Some(args) = ssh_client.ssh_args() {
|
||||
return Some((
|
||||
ssh_client.connection_options().host.clone(),
|
||||
SshCommand::Direct(args),
|
||||
SshCommand { arguments: args },
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let dev_server_project_id = self.dev_server_project_id()?;
|
||||
let projects_store = dev_server_projects::Store::global(cx).read(cx);
|
||||
let ssh_command = projects_store
|
||||
.dev_server_for_project(dev_server_project_id)?
|
||||
.ssh_connection_string
|
||||
.as_ref()?
|
||||
.to_string();
|
||||
Some(("".to_string(), SshCommand::DevServer(ssh_command)))
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn create_terminal(
|
||||
@@ -399,14 +389,8 @@ pub fn wrap_for_ssh(
|
||||
};
|
||||
let shell_invocation = format!("sh -c {}", shlex::try_quote(&commands).unwrap());
|
||||
|
||||
let (program, mut args) = match ssh_command {
|
||||
SshCommand::DevServer(ssh_command) => {
|
||||
let mut args = shlex::split(ssh_command).unwrap_or_default();
|
||||
let program = args.drain(0..1).next().unwrap_or("ssh".to_string());
|
||||
(program, args)
|
||||
}
|
||||
SshCommand::Direct(ssh_args) => ("ssh".to_string(), ssh_args.clone()),
|
||||
};
|
||||
let program = "ssh".to_string();
|
||||
let mut args = ssh_command.arguments.clone();
|
||||
|
||||
args.push("-t".to_string());
|
||||
args.push(shell_invocation);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
path::{Path, PathBuf},
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use client::DevServerProjectId;
|
||||
use collections::{HashMap, HashSet};
|
||||
use fs::Fs;
|
||||
use futures::{
|
||||
@@ -41,7 +39,6 @@ enum WorktreeStoreState {
|
||||
fs: Arc<dyn Fs>,
|
||||
},
|
||||
Remote {
|
||||
dev_server_project_id: Option<DevServerProjectId>,
|
||||
upstream_client: AnyProtoClient,
|
||||
upstream_project_id: u64,
|
||||
},
|
||||
@@ -94,7 +91,6 @@ impl WorktreeStore {
|
||||
retain_worktrees: bool,
|
||||
upstream_client: AnyProtoClient,
|
||||
upstream_project_id: u64,
|
||||
dev_server_project_id: Option<DevServerProjectId>,
|
||||
) -> Self {
|
||||
Self {
|
||||
next_entry_id: Default::default(),
|
||||
@@ -106,7 +102,6 @@ impl WorktreeStore {
|
||||
state: WorktreeStoreState::Remote {
|
||||
upstream_client,
|
||||
upstream_project_id,
|
||||
dev_server_project_id,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -196,18 +191,9 @@ impl WorktreeStore {
|
||||
if !self.loading_worktrees.contains_key(&path) {
|
||||
let task = match &self.state {
|
||||
WorktreeStoreState::Remote {
|
||||
upstream_client,
|
||||
dev_server_project_id,
|
||||
..
|
||||
upstream_client, ..
|
||||
} => {
|
||||
if let Some(dev_server_project_id) = dev_server_project_id {
|
||||
self.create_dev_server_worktree(
|
||||
upstream_client.clone(),
|
||||
*dev_server_project_id,
|
||||
abs_path,
|
||||
cx,
|
||||
)
|
||||
} else if upstream_client.is_via_collab() {
|
||||
if upstream_client.is_via_collab() {
|
||||
Task::ready(Err(Arc::new(anyhow!("cannot create worktrees via collab"))))
|
||||
} else {
|
||||
self.create_ssh_worktree(upstream_client.clone(), abs_path, visible, cx)
|
||||
@@ -322,51 +308,6 @@ impl WorktreeStore {
|
||||
})
|
||||
}
|
||||
|
||||
fn create_dev_server_worktree(
|
||||
&mut self,
|
||||
client: AnyProtoClient,
|
||||
dev_server_project_id: DevServerProjectId,
|
||||
abs_path: impl AsRef<Path>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<Worktree>, Arc<anyhow::Error>>> {
|
||||
let path: Arc<Path> = abs_path.as_ref().into();
|
||||
let mut paths: Vec<String> = self
|
||||
.visible_worktrees(cx)
|
||||
.map(|worktree| worktree.read(cx).abs_path().to_string_lossy().to_string())
|
||||
.collect();
|
||||
paths.push(path.to_string_lossy().to_string());
|
||||
let request = client.request(proto::UpdateDevServerProject {
|
||||
dev_server_project_id: dev_server_project_id.0,
|
||||
paths,
|
||||
});
|
||||
|
||||
let abs_path = abs_path.as_ref().to_path_buf();
|
||||
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 {
|
||||
return Err(anyhow!("project dropped"))?;
|
||||
};
|
||||
let observer = cx.update(|cx| {
|
||||
cx.observe(&project, move |project, cx| {
|
||||
let abs_path = abs_path.clone();
|
||||
project.update(cx, |project, cx| {
|
||||
if let Some((worktree, _)) = project.find_worktree(&abs_path, cx) {
|
||||
if let Some(tx) = tx.borrow_mut().take() {
|
||||
tx.send(worktree).ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})?;
|
||||
|
||||
request.await?;
|
||||
let worktree = rx.await.map_err(|e| anyhow!(e))?;
|
||||
drop(observer);
|
||||
Ok(worktree)
|
||||
})
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user