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:
Mikayla Maki 2024-10-24 11:14:03 -07:00 committed by GitHub
parent b5f816dde5
commit 02718284ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 391 additions and 5024 deletions

View file

@ -24,9 +24,7 @@ use model::{
SerializedSshProject, SerializedWorkspace,
};
use self::model::{
DockStructure, LocalPathsOrder, SerializedDevServerProject, SerializedWorkspaceLocation,
};
use self::model::{DockStructure, LocalPathsOrder, SerializedWorkspaceLocation};
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) struct SerializedAxis(pub(crate) gpui::Axis);
@ -460,89 +458,6 @@ impl WorkspaceDb {
})
}
pub(crate) fn workspace_for_dev_server_project(
&self,
dev_server_project_id: DevServerProjectId,
) -> Option<SerializedWorkspace> {
// Note that we re-assign the workspace_id here in case it's empty
// and we've grabbed the most recent workspace
let (
workspace_id,
dev_server_project_id,
window_bounds,
display,
centered_layout,
docks,
window_id,
): (
WorkspaceId,
Option<u64>,
Option<SerializedWindowBounds>,
Option<Uuid>,
Option<bool>,
DockStructure,
Option<u64>,
) = self
.select_row_bound(sql! {
SELECT
workspace_id,
dev_server_project_id,
window_state,
window_x,
window_y,
window_width,
window_height,
display,
centered_layout,
left_dock_visible,
left_dock_active_panel,
left_dock_zoom,
right_dock_visible,
right_dock_active_panel,
right_dock_zoom,
bottom_dock_visible,
bottom_dock_active_panel,
bottom_dock_zoom,
window_id
FROM workspaces
WHERE dev_server_project_id = ?
})
.and_then(|mut prepared_statement| (prepared_statement)(dev_server_project_id.0))
.context("No workspaces found")
.warn_on_err()
.flatten()?;
let dev_server_project_id = dev_server_project_id?;
let dev_server_project: SerializedDevServerProject = self
.select_row_bound(sql! {
SELECT id, path, dev_server_name
FROM dev_server_projects
WHERE id = ?
})
.and_then(|mut prepared_statement| (prepared_statement)(dev_server_project_id))
.context("No remote project found")
.warn_on_err()
.flatten()?;
let location = SerializedWorkspaceLocation::DevServer(dev_server_project);
Some(SerializedWorkspace {
id: workspace_id,
location,
center_group: self
.get_center_pane_group(workspace_id)
.context("Getting center group")
.log_err()?,
window_bounds,
centered_layout: centered_layout.unwrap_or(false),
display,
docks,
session_id: None,
window_id,
})
}
pub(crate) fn workspace_for_ssh_project(
&self,
ssh_project: &SerializedSshProject,
@ -659,61 +574,6 @@ impl WorkspaceDb {
prepared_query(args).context("Updating workspace")?;
}
SerializedWorkspaceLocation::DevServer(dev_server_project) => {
conn.exec_bound(sql!(
DELETE FROM workspaces WHERE dev_server_project_id = ? AND workspace_id != ?
))?((dev_server_project.id.0, workspace.id))
.context("clearing out old locations")?;
conn.exec_bound(sql!(
INSERT INTO dev_server_projects(
id,
path,
dev_server_name
) VALUES (?1, ?2, ?3)
ON CONFLICT DO
UPDATE SET
path = ?2,
dev_server_name = ?3
))?(&dev_server_project)?;
// Upsert
conn.exec_bound(sql!(
INSERT INTO workspaces(
workspace_id,
dev_server_project_id,
left_dock_visible,
left_dock_active_panel,
left_dock_zoom,
right_dock_visible,
right_dock_active_panel,
right_dock_zoom,
bottom_dock_visible,
bottom_dock_active_panel,
bottom_dock_zoom,
timestamp
)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, CURRENT_TIMESTAMP)
ON CONFLICT DO
UPDATE SET
dev_server_project_id = ?2,
left_dock_visible = ?3,
left_dock_active_panel = ?4,
left_dock_zoom = ?5,
right_dock_visible = ?6,
right_dock_active_panel = ?7,
right_dock_zoom = ?8,
bottom_dock_visible = ?9,
bottom_dock_active_panel = ?10,
bottom_dock_zoom = ?11,
timestamp = CURRENT_TIMESTAMP
))?((
workspace.id,
dev_server_project.id.0,
workspace.docks,
))
.context("Updating workspace")?;
},
SerializedWorkspaceLocation::Ssh(ssh_project) => {
conn.exec_bound(sql!(
DELETE FROM workspaces WHERE ssh_project_id = ? AND workspace_id != ?
@ -824,11 +684,10 @@ impl WorkspaceDb {
}
query! {
fn recent_workspaces() -> Result<Vec<(WorkspaceId, LocalPaths, LocalPathsOrder, Option<u64>, Option<u64>)>> {
SELECT workspace_id, local_paths, local_paths_order, dev_server_project_id, ssh_project_id
fn recent_workspaces() -> Result<Vec<(WorkspaceId, LocalPaths, LocalPathsOrder, Option<u64>)>> {
SELECT workspace_id, local_paths, local_paths_order, ssh_project_id
FROM workspaces
WHERE local_paths IS NOT NULL
OR dev_server_project_id IS NOT NULL
OR ssh_project_id IS NOT NULL
ORDER BY timestamp DESC
}
@ -843,13 +702,6 @@ impl WorkspaceDb {
}
}
query! {
fn dev_server_projects() -> Result<Vec<SerializedDevServerProject>> {
SELECT id, path, dev_server_name
FROM dev_server_projects
}
}
query! {
fn ssh_projects() -> Result<Vec<SerializedSshProject>> {
SELECT id, host, port, paths, user
@ -913,24 +765,9 @@ impl WorkspaceDb {
) -> Result<Vec<(WorkspaceId, SerializedWorkspaceLocation)>> {
let mut result = Vec::new();
let mut delete_tasks = Vec::new();
let dev_server_projects = self.dev_server_projects()?;
let ssh_projects = self.ssh_projects()?;
for (id, location, order, dev_server_project_id, ssh_project_id) in
self.recent_workspaces()?
{
if let Some(dev_server_project_id) = dev_server_project_id.map(DevServerProjectId) {
if let Some(dev_server_project) = dev_server_projects
.iter()
.find(|rp| rp.id == dev_server_project_id)
{
result.push((id, dev_server_project.clone().into()));
} else {
delete_tasks.push(self.delete_workspace_by_id(id));
}
continue;
}
for (id, location, order, ssh_project_id) in self.recent_workspaces()? {
if let Some(ssh_project_id) = ssh_project_id.map(SshProjectId) {
if let Some(ssh_project) = ssh_projects.iter().find(|rp| rp.id == ssh_project_id) {
result.push((id, SerializedWorkspaceLocation::Ssh(ssh_project.clone())));

View file

@ -4,7 +4,6 @@ use crate::{
};
use anyhow::{Context, Result};
use async_recursion::async_recursion;
use client::DevServerProjectId;
use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
@ -17,7 +16,6 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
use ui::SharedString;
use util::ResultExt;
use uuid::Uuid;
@ -92,13 +90,6 @@ impl Column for SerializedSshProject {
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct SerializedDevServerProject {
pub id: DevServerProjectId,
pub dev_server_name: String,
pub paths: Vec<SharedString>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct LocalPaths(Arc<Vec<PathBuf>>);
@ -176,49 +167,10 @@ impl Column for LocalPathsOrder {
}
}
impl From<SerializedDevServerProject> for SerializedWorkspaceLocation {
fn from(dev_server_project: SerializedDevServerProject) -> Self {
Self::DevServer(dev_server_project)
}
}
impl StaticColumnCount for SerializedDevServerProject {}
impl Bind for &SerializedDevServerProject {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let next_index = statement.bind(&self.id.0, start_index)?;
let next_index = statement.bind(&self.dev_server_name, next_index)?;
let paths = serde_json::to_string(&self.paths)?;
statement.bind(&paths, next_index)
}
}
impl Column for SerializedDevServerProject {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let id = statement.column_int64(start_index)?;
let dev_server_name = statement.column_text(start_index + 1)?.to_string();
let paths = statement.column_text(start_index + 2)?.to_string();
let paths: Vec<SharedString> = if paths.starts_with('[') {
serde_json::from_str(&paths).context("JSON deserialization of paths failed")?
} else {
vec![paths.into()]
};
Ok((
Self {
id: DevServerProjectId(id as u64),
dev_server_name,
paths,
},
start_index + 3,
))
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum SerializedWorkspaceLocation {
Local(LocalPaths, LocalPathsOrder),
Ssh(SerializedSshProject),
DevServer(SerializedDevServerProject),
}
impl SerializedWorkspaceLocation {

View file

@ -16,7 +16,7 @@ use anyhow::{anyhow, Context as _, Result};
use call::{call_settings::CallSettings, ActiveCall};
use client::{
proto::{self, ErrorCode, PanelId, PeerId},
ChannelId, Client, DevServerProjectId, ErrorExt, ProjectId, Status, TypedEnvelope, UserStore,
ChannelId, Client, ErrorExt, ProjectId, Status, TypedEnvelope, UserStore,
};
use collections::{hash_map, HashMap, HashSet};
use derive_more::{Deref, DerefMut};
@ -52,7 +52,7 @@ use notifications::{
pub use pane::*;
pub use pane_group::*;
pub use persistence::{
model::{ItemId, LocalPaths, SerializedDevServerProject, SerializedWorkspaceLocation},
model::{ItemId, LocalPaths, SerializedWorkspaceLocation},
WorkspaceDb, DB as WORKSPACE_DB,
};
use persistence::{
@ -97,7 +97,7 @@ use ui::{
IntoElement, ParentElement as _, Pixels, SharedString, Styled as _, ViewContext,
VisualContext as _, WindowContext,
};
use util::{maybe, ResultExt, TryFutureExt};
use util::{ResultExt, TryFutureExt};
use uuid::Uuid;
pub use workspace_settings::{
AutosaveSetting, RestoreOnStartupBehavior, TabBarSettings, WorkspaceSettings,
@ -2057,7 +2057,7 @@ impl Workspace {
fn add_folder_to_project(&mut self, _: &AddFolderToProject, cx: &mut ViewContext<Self>) {
let project = self.project.read(cx);
if project.is_via_collab() && project.dev_server_project_id().is_none() {
if project.is_via_collab() {
self.show_error(
&anyhow!("You cannot add folders to someone else's project"),
cx,
@ -4133,20 +4133,6 @@ impl Workspace {
} else {
None
}
} else if let Some(dev_server_project_id) = self.project().read(cx).dev_server_project_id()
{
let store = dev_server_projects::Store::global(cx).read(cx);
maybe!({
let project = store.dev_server_project(dev_server_project_id)?;
let dev_server = store.dev_server(project.dev_server_id)?;
let dev_server_project = SerializedDevServerProject {
id: dev_server_project_id,
dev_server_name: dev_server.name.to_string(),
paths: project.paths.to_vec(),
};
Some(SerializedWorkspaceLocation::DevServer(dev_server_project))
})
} else {
None
};
@ -5180,13 +5166,12 @@ async fn join_channel_internal(
if let Some(workspace) = requesting_window {
let project = workspace.update(cx, |workspace, cx| {
let project = workspace.project.read(cx);
let is_dev_server = project.dev_server_project_id().is_some();
if !is_dev_server && !CallSettings::get_global(cx).share_on_join {
if !CallSettings::get_global(cx).share_on_join {
return None;
}
if (project.is_local() || project.is_via_ssh() || is_dev_server)
if (project.is_local() || project.is_via_ssh())
&& project.visible_worktrees(cx).any(|tree| {
tree.read(cx)
.root_entry()
@ -5685,84 +5670,6 @@ fn serialize_ssh_project(
})
}
pub fn join_dev_server_project(
dev_server_project_id: DevServerProjectId,
project_id: ProjectId,
app_state: Arc<AppState>,
window_to_replace: Option<WindowHandle<Workspace>>,
cx: &mut AppContext,
) -> Task<Result<WindowHandle<Workspace>>> {
let windows = cx.windows();
cx.spawn(|mut cx| async move {
let existing_workspace = windows.into_iter().find_map(|window| {
window.downcast::<Workspace>().and_then(|window| {
window
.update(&mut cx, |workspace, cx| {
if workspace.project().read(cx).remote_id() == Some(project_id.0) {
Some(window)
} else {
None
}
})
.unwrap_or(None)
})
});
let serialized_workspace: Option<SerializedWorkspace> =
persistence::DB.workspace_for_dev_server_project(dev_server_project_id);
let workspace = if let Some(existing_workspace) = existing_workspace {
existing_workspace
} else {
let project = Project::remote(
project_id.0,
app_state.client.clone(),
app_state.user_store.clone(),
app_state.languages.clone(),
app_state.fs.clone(),
cx.clone(),
)
.await?;
let workspace_id = if let Some(ref serialized_workspace) = serialized_workspace {
serialized_workspace.id
} else {
persistence::DB.next_id().await?
};
if let Some(window_to_replace) = window_to_replace {
cx.update_window(window_to_replace.into(), |_, cx| {
cx.replace_root_view(|cx| {
Workspace::new(Some(workspace_id), project, app_state.clone(), cx)
});
})?;
window_to_replace
} else {
let window_bounds_override = window_bounds_env_override();
cx.update(|cx| {
let mut options = (app_state.build_window_options)(None, cx);
options.window_bounds = window_bounds_override.map(WindowBounds::Windowed);
cx.open_window(options, |cx| {
cx.new_view(|cx| {
Workspace::new(Some(workspace_id), project, app_state.clone(), cx)
})
})
})??
}
};
workspace
.update(&mut cx, |_, cx| {
cx.activate(true);
cx.activate_window();
open_items(serialized_workspace, vec![], app_state, cx)
})?
.await?;
anyhow::Ok(workspace)
})
}
pub fn join_in_room_project(
project_id: u64,
follow_user_id: u64,