remote: Bring back docker exit status mapping (#47206)

Lukas Wirth created

cc https://github.com/zed-industries/zed/pull/45584, was removed in
#47200 fully due to breaking ssh
Also makes ZED_BUILD_REMOTE_SERVER a bit easier to use

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/remote/src/transport.rs        |  8 +++
crates/remote/src/transport/docker.rs | 52 ++++++++++++++++++----------
crates/remote/src/transport/ssh.rs    | 33 ++++++++++-------
crates/remote/src/transport/wsl.rs    | 20 +++++++---
4 files changed, 72 insertions(+), 41 deletions(-)

Detailed changes

crates/remote/src/transport.rs 🔗

@@ -178,6 +178,7 @@ fn handle_rpc_messages_over_child_process_stdio(
 async fn build_remote_server_from_source(
     platform: &crate::RemotePlatform,
     delegate: &dyn crate::RemoteClientDelegate,
+    binary_exists_on_server: bool,
     cx: &mut AsyncApp,
 ) -> Result<Option<std::path::PathBuf>> {
     use smol::process::{Command, Stdio};
@@ -202,8 +203,13 @@ async fn build_remote_server_from_source(
     let build_remote_server =
         std::env::var("ZED_BUILD_REMOTE_SERVER").unwrap_or("nocompress".into());
 
-    if let "false" | "no" | "off" | "0" = &*build_remote_server {
+    if let "never" = &*build_remote_server {
         return Ok(None);
+    } else if let "false" | "no" | "off" | "0" = &*build_remote_server {
+        if binary_exists_on_server {
+            return Ok(None);
+        }
+        log::warn!("ZED_BUILD_REMOTE_SERVER is disabled, but no server binary exists on the server")
     }
 
     async fn run_cmd(command: &mut Command) -> Result<()> {

crates/remote/src/transport/docker.rs 🔗

@@ -165,9 +165,23 @@ impl DockerExecConnection {
         let dst_path =
             paths::remote_server_dir_relative().join(RelPath::unix(&binary_name).unwrap());
 
+        let binary_exists_on_server = self
+            .run_docker_exec(
+                &dst_path.display(self.path_style()),
+                Some(&remote_dir_for_server),
+                &Default::default(),
+                &["version"],
+            )
+            .await
+            .is_ok();
         #[cfg(any(debug_assertions, feature = "build-remote-server-binary"))]
-        if let Some(remote_server_path) =
-            super::build_remote_server_from_source(&remote_platform, delegate.as_ref(), cx).await?
+        if let Some(remote_server_path) = super::build_remote_server_from_source(
+            &remote_platform,
+            delegate.as_ref(),
+            binary_exists_on_server,
+            cx,
+        )
+        .await?
         {
             let tmp_path = paths::remote_server_dir_relative().join(
                 RelPath::unix(&format!(
@@ -190,16 +204,7 @@ impl DockerExecConnection {
             return Ok(dst_path);
         }
 
-        if self
-            .run_docker_exec(
-                &dst_path.display(self.path_style()),
-                Some(&remote_dir_for_server),
-                &Default::default(),
-                &["version"],
-            )
-            .await
-            .is_ok()
-        {
+        if binary_exists_on_server {
             return Ok(dst_path);
         }
 
@@ -611,13 +616,22 @@ impl RemoteConnection for DockerExecConnection {
         let mut proxy_process = self.proxy_process.lock();
         *proxy_process = Some(child.id());
 
-        super::handle_rpc_messages_over_child_process_stdio(
-            child,
-            incoming_tx,
-            outgoing_rx,
-            connection_activity_tx,
-            cx,
-        )
+        cx.spawn(async move |cx| {
+            super::handle_rpc_messages_over_child_process_stdio(
+                child,
+                incoming_tx,
+                outgoing_rx,
+                connection_activity_tx,
+                cx,
+            )
+            .await
+            .and_then(|status| {
+                if status != 0 {
+                    anyhow::bail!("Remote server exited with status {status}");
+                }
+                Ok(0)
+            })
+        })
     }
 
     fn upload_directory(

crates/remote/src/transport/ssh.rs 🔗

@@ -628,10 +628,25 @@ impl SshRemoteConnection {
         let dst_path =
             paths::remote_server_dir_relative().join(RelPath::unix(&binary_name).unwrap());
 
+        let binary_exists_on_server = self
+            .socket
+            .run_command(
+                self.ssh_shell_kind,
+                &dst_path.display(self.path_style()),
+                &["version"],
+                true,
+            )
+            .await
+            .is_ok();
+
         #[cfg(any(debug_assertions, feature = "build-remote-server-binary"))]
-        if let Some(remote_server_path) =
-            super::build_remote_server_from_source(&self.ssh_platform, delegate.as_ref(), cx)
-                .await?
+        if let Some(remote_server_path) = super::build_remote_server_from_source(
+            &self.ssh_platform,
+            delegate.as_ref(),
+            binary_exists_on_server,
+            cx,
+        )
+        .await?
         {
             let tmp_path = paths::remote_server_dir_relative().join(
                 RelPath::unix(&format!(
@@ -648,17 +663,7 @@ impl SshRemoteConnection {
             return Ok(dst_path);
         }
 
-        if self
-            .socket
-            .run_command(
-                self.ssh_shell_kind,
-                &dst_path.display(self.path_style()),
-                &["version"],
-                true,
-            )
-            .await
-            .is_ok()
-        {
+        if binary_exists_on_server {
             return Ok(dst_path);
         }
 

crates/remote/src/transport/wsl.rs 🔗

@@ -186,9 +186,19 @@ impl WslRemoteConnection {
                 .map_err(|e| anyhow!("Failed to create directory: {}", e))?;
         }
 
+        let binary_exists_on_server = self
+            .run_wsl_command(&dst_path.display(PathStyle::Posix), &["version"])
+            .await
+            .is_ok();
+
         #[cfg(any(debug_assertions, feature = "build-remote-server-binary"))]
-        if let Some(remote_server_path) =
-            super::build_remote_server_from_source(&self.platform, delegate.as_ref(), cx).await?
+        if let Some(remote_server_path) = super::build_remote_server_from_source(
+            &self.platform,
+            delegate.as_ref(),
+            binary_exists_on_server,
+            cx,
+        )
+        .await?
         {
             let tmp_path = paths::remote_wsl_server_dir_relative().join(
                 &RelPath::unix(&format!(
@@ -205,11 +215,7 @@ impl WslRemoteConnection {
             return Ok(dst_path);
         }
 
-        if self
-            .run_wsl_command(&dst_path.display(PathStyle::Posix), &["version"])
-            .await
-            .is_ok()
-        {
+        if binary_exists_on_server {
             return Ok(dst_path);
         }