Rebuild SSH installation (#20220)

Closes #ISSUE

This refactors SSH installation to require less shell stuff. We'd like
to
support arbitrary remote hosts, and unfortunately csh/tcsh have quoting
rules
that make it impossible to run multi-line scripts.

The primary changes are:
* The target path now contains the version:
`./zed_server/zed-remote-server-{release_channel}-{version}`
* We do all our processing in a temporary file and `mv` it into place.
* We do fewer calls to `ssh_command` overall. With the previous two
changes we can avoid lock files, and fuser calls. Instead cleanup of old
binaries now happens in `execute_run`.
* We only try to install the remote server when the connection is
established, not on each project open.

This should also put us in a good position if we want to pre-emptively
install new versions when the auto-updater detects an update for the
running version of zed (but that's not wired up yet)

Release Notes:

- Remoting: Fixed remoting when the remote runs `tcsh`
- Remoting: Improved latency of connecting
This commit is contained in:
Conrad Irwin 2024-11-05 13:37:54 -07:00 committed by GitHub
parent 7c72929f0b
commit 87ba5fd7bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 287 additions and 585 deletions

View file

@ -7,7 +7,7 @@ use fs::{Fs, RealFs};
use futures::channel::mpsc;
use futures::{select, select_biased, AsyncRead, AsyncWrite, AsyncWriteExt, FutureExt, SinkExt};
use git::GitHostingProviderRegistry;
use gpui::{AppContext, Context as _, Model, ModelContext, UpdateGlobal as _};
use gpui::{AppContext, Context as _, Model, ModelContext, SemanticVersion, UpdateGlobal as _};
use http_client::{read_proxy_from_env, Uri};
use language::LanguageRegistry;
use node_runtime::{NodeBinaryOptions, NodeRuntime};
@ -31,6 +31,7 @@ use smol::Async;
use smol::{net::unix::UnixListener, stream::StreamExt as _};
use std::ffi::OsStr;
use std::ops::ControlFlow;
use std::str::FromStr;
use std::{env, thread};
use std::{
io::Write,
@ -466,6 +467,10 @@ pub fn execute_run(
handle_panic_requests(&project, &session);
cx.background_executor()
.spawn(async move { cleanup_old_binaries() })
.detach();
mem::forget(project);
});
log::info!("gpui app is shut down. quitting.");
@ -874,3 +879,49 @@ unsafe fn redirect_standard_streams() -> Result<()> {
Ok(())
}
fn cleanup_old_binaries() -> Result<()> {
let server_dir = paths::remote_server_dir_relative();
let release_channel = release_channel::RELEASE_CHANNEL.dev_name();
let prefix = format!("zed-remote-server-{}-", release_channel);
for entry in std::fs::read_dir(server_dir)? {
let path = entry?.path();
if let Some(file_name) = path.file_name() {
if let Some(version) = file_name.to_string_lossy().strip_prefix(&prefix) {
if !is_new_version(version) && !is_file_in_use(file_name) {
log::info!("removing old remote server binary: {:?}", path);
std::fs::remove_file(&path)?;
}
}
}
}
Ok(())
}
fn is_new_version(version: &str) -> bool {
SemanticVersion::from_str(version)
.ok()
.zip(SemanticVersion::from_str(env!("ZED_PKG_VERSION")).ok())
.is_some_and(|(version, current_version)| version >= current_version)
}
fn is_file_in_use(file_name: &OsStr) -> bool {
let info =
sysinfo::System::new_with_specifics(sysinfo::RefreshKind::new().with_processes(
sysinfo::ProcessRefreshKind::new().with_exe(sysinfo::UpdateKind::Always),
));
for process in info.processes().values() {
if process
.exe()
.is_some_and(|exe| exe.file_name().is_some_and(|name| name == file_name))
{
return true;
}
}
false
}