util: Use process spawn helpers in more places (#42976)

Lukas Wirth created

Release Notes:

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

Change summary

crates/auto_update/src/auto_update.rs         | 15 ++++++++-------
crates/gpui/src/platform/linux/platform.rs    |  6 +++---
crates/gpui/src/platform/mac/platform.rs      | 10 ++++++----
crates/languages/src/rust.rs                  |  9 +++++++--
crates/project/src/debugger/locators/cargo.rs |  9 +++------
crates/project/src/environment.rs             |  4 ++--
crates/project/src/terminals.rs               |  6 +++---
crates/remote/src/transport.rs                | 20 ++++++++++++++------
crates/remote_server/src/unix.rs              |  7 ++++---
crates/util/src/shell_env.rs                  |  4 +++-
10 files changed, 53 insertions(+), 37 deletions(-)

Detailed changes

crates/auto_update/src/auto_update.rs 🔗

@@ -10,8 +10,8 @@ use paths::remote_servers_dir;
 use release_channel::{AppCommitSha, ReleaseChannel};
 use serde::{Deserialize, Serialize};
 use settings::{RegisterSetting, Settings, SettingsStore};
+use smol::fs::File;
 use smol::{fs, io::AsyncReadExt};
-use smol::{fs::File, process::Command};
 use std::mem;
 use std::{
     env::{
@@ -23,6 +23,7 @@ use std::{
     sync::Arc,
     time::Duration,
 };
+use util::command::new_smol_command;
 use workspace::Workspace;
 
 const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification";
@@ -121,7 +122,7 @@ impl Drop for MacOsUnmounter<'_> {
         let mount_path = mem::take(&mut self.mount_path);
         self.background_executor
             .spawn(async move {
-                let unmount_output = Command::new("hdiutil")
+                let unmount_output = new_smol_command("hdiutil")
                     .args(["detach", "-force"])
                     .arg(&mount_path)
                     .output()
@@ -799,7 +800,7 @@ async fn install_release_linux(
         .await
         .context("failed to create directory into which to extract update")?;
 
-    let output = Command::new("tar")
+    let output = new_smol_command("tar")
         .arg("-xzf")
         .arg(&downloaded_tar_gz)
         .arg("-C")
@@ -834,7 +835,7 @@ async fn install_release_linux(
         to = PathBuf::from(prefix);
     }
 
-    let output = Command::new("rsync")
+    let output = new_smol_command("rsync")
         .args(["-av", "--delete"])
         .arg(&from)
         .arg(&to)
@@ -866,7 +867,7 @@ async fn install_release_macos(
     let mut mounted_app_path: OsString = mount_path.join(running_app_filename).into();
 
     mounted_app_path.push("/");
-    let output = Command::new("hdiutil")
+    let output = new_smol_command("hdiutil")
         .args(["attach", "-nobrowse"])
         .arg(&downloaded_dmg)
         .arg("-mountroot")
@@ -886,7 +887,7 @@ async fn install_release_macos(
         background_executor: cx.background_executor(),
     };
 
-    let output = Command::new("rsync")
+    let output = new_smol_command("rsync")
         .args(["-av", "--delete"])
         .arg(&mounted_app_path)
         .arg(&running_app_path)
@@ -917,7 +918,7 @@ async fn cleanup_windows() -> Result<()> {
 }
 
 async fn install_release_windows(downloaded_installer: PathBuf) -> Result<Option<PathBuf>> {
-    let output = Command::new(downloaded_installer)
+    let output = new_smol_command(downloaded_installer)
         .arg("/verysilent")
         .arg("/update=true")
         .arg("!desktopicon")

crates/gpui/src/platform/linux/platform.rs 🔗

@@ -1,7 +1,6 @@
 use std::{
     env,
     path::{Path, PathBuf},
-    process::Command,
     rc::Rc,
     sync::Arc,
 };
@@ -18,6 +17,7 @@ use anyhow::{Context as _, anyhow};
 use calloop::{LoopSignal, channel::Channel};
 use futures::channel::oneshot;
 use util::ResultExt as _;
+use util::command::{new_smol_command, new_std_command};
 #[cfg(any(feature = "wayland", feature = "x11"))]
 use xkbcommon::xkb::{self, Keycode, Keysym, State};
 
@@ -215,7 +215,7 @@ impl<P: LinuxClient + 'static> Platform for P {
             clippy::disallowed_methods,
             reason = "We are restarting ourselves, using std command thus is fine"
         )]
-        let restart_process = Command::new("/usr/bin/env")
+        let restart_process = new_std_command("/usr/bin/env")
             .arg("bash")
             .arg("-c")
             .arg(script)
@@ -422,7 +422,7 @@ impl<P: LinuxClient + 'static> Platform for P {
         let path = path.to_owned();
         self.background_executor()
             .spawn(async move {
-                let _ = smol::process::Command::new("xdg-open")
+                let _ = new_smol_command("xdg-open")
                     .arg(path)
                     .spawn()
                     .context("invoking xdg-open")

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -53,14 +53,16 @@ use std::{
     ffi::{CStr, OsStr, c_void},
     os::{raw::c_char, unix::ffi::OsStrExt},
     path::{Path, PathBuf},
-    process::Command,
     ptr,
     rc::Rc,
     slice, str,
     sync::{Arc, OnceLock},
 };
 use strum::IntoEnumIterator;
-use util::ResultExt;
+use util::{
+    ResultExt,
+    command::{new_smol_command, new_std_command},
+};
 
 #[allow(non_upper_case_globals)]
 const NSUTF8StringEncoding: NSUInteger = 4;
@@ -552,7 +554,7 @@ impl Platform for MacPlatform {
             clippy::disallowed_methods,
             reason = "We are restarting ourselves, using std command thus is fine"
         )]
-        let restart_process = Command::new("/bin/bash")
+        let restart_process = new_std_command("/bin/bash")
             .arg("-c")
             .arg(script)
             .arg(app_pid)
@@ -867,7 +869,7 @@ impl Platform for MacPlatform {
             .lock()
             .background_executor
             .spawn(async move {
-                if let Some(mut child) = smol::process::Command::new("open")
+                if let Some(mut child) = new_smol_command("open")
                     .arg(path)
                     .spawn()
                     .context("invoking open command")

crates/languages/src/rust.rs 🔗

@@ -67,10 +67,15 @@ impl RustLspAdapter {
     #[cfg(target_os = "linux")]
     async fn determine_libc_type() -> LibcType {
         use futures::pin_mut;
-        use smol::process::Command;
 
         async fn from_ldd_version() -> Option<LibcType> {
-            let ldd_output = Command::new("ldd").arg("--version").output().await.ok()?;
+            use util::command::new_smol_command;
+
+            let ldd_output = new_smol_command("ldd")
+                .arg("--version")
+                .output()
+                .await
+                .ok()?;
             let ldd_version = String::from_utf8_lossy(&ldd_output.stdout);
 
             if ldd_version.contains("GNU libc") || ldd_version.contains("GLIBC") {

crates/project/src/debugger/locators/cargo.rs 🔗

@@ -3,13 +3,10 @@ use async_trait::async_trait;
 use dap::{DapLocator, DebugRequest, adapters::DebugAdapterName};
 use gpui::SharedString;
 use serde_json::{Value, json};
-use smol::{
-    Timer,
-    io::AsyncReadExt,
-    process::{Command, Stdio},
-};
+use smol::{Timer, io::AsyncReadExt, process::Stdio};
 use std::time::Duration;
 use task::{BuildTaskDefinition, DebugScenario, ShellBuilder, SpawnInTerminal, TaskTemplate};
+use util::command::new_smol_command;
 
 pub(crate) struct CargoLocator;
 
@@ -18,7 +15,7 @@ async fn find_best_executable(executables: &[String], test_name: &str) -> Option
         return executables.first().cloned();
     }
     for executable in executables {
-        let Some(mut child) = Command::new(&executable)
+        let Some(mut child) = new_smol_command(&executable)
             .arg("--list")
             .stdout(Stdio::piped())
             .spawn()

crates/project/src/environment.rs 🔗

@@ -6,7 +6,7 @@ use rpc::proto::{self, REMOTE_SERVER_PROJECT_ID};
 use std::{collections::VecDeque, path::Path, sync::Arc};
 use task::{Shell, shell_to_proto};
 use terminal::terminal_settings::TerminalSettings;
-use util::{ResultExt, rel_path::RelPath};
+use util::{ResultExt, command::new_smol_command, rel_path::RelPath};
 use worktree::Worktree;
 
 use collections::HashMap;
@@ -389,7 +389,7 @@ async fn load_direnv_environment(
     };
 
     let args = &["export", "json"];
-    let direnv_output = smol::process::Command::new(&direnv_path)
+    let direnv_output = new_smol_command(&direnv_path)
         .args(args)
         .envs(env)
         .env("TERM", "dumb")

crates/project/src/terminals.rs 🔗

@@ -16,7 +16,7 @@ use task::{Shell, ShellBuilder, ShellKind, SpawnInTerminal};
 use terminal::{
     TaskState, TaskStatus, Terminal, TerminalBuilder, terminal_settings::TerminalSettings,
 };
-use util::{get_default_system_shell, maybe, rel_path::RelPath};
+use util::{command::new_std_command, get_default_system_shell, maybe, rel_path::RelPath};
 
 use crate::{Project, ProjectPath};
 
@@ -505,13 +505,13 @@ impl Project {
                             None,
                             None,
                         )?;
-                        let mut command = std::process::Command::new(command_template.program);
+                        let mut command = new_std_command(command_template.program);
                         command.args(command_template.args);
                         command.envs(command_template.env);
                         Ok(command)
                     }
                     None => {
-                        let mut command = std::process::Command::new(command);
+                        let mut command = new_std_command(command);
                         command.args(args);
                         command.envs(env);
                         if let Some(path) = path {

crates/remote/src/transport.rs 🔗

@@ -124,6 +124,7 @@ async fn build_remote_server_from_source(
     use smol::process::{Command, Stdio};
     use std::env::VarError;
     use std::path::Path;
+    use util::command::new_smol_command;
 
     // By default, we make building remote server from source opt-out and we do not force artifact compression
     // for quicker builds.
@@ -189,7 +190,7 @@ async fn build_remote_server_from_source(
         delegate.set_status(Some("Building remote server binary from source"), cx);
         log::info!("building remote server binary from source");
         run_cmd(
-            Command::new("cargo")
+            new_smol_command("cargo")
                 .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/../.."))
                 .args([
                     "build",
@@ -219,12 +220,18 @@ async fn build_remote_server_from_source(
             .context("rustup not found on $PATH, install rustup (see https://rustup.rs/)")?;
         delegate.set_status(Some("Adding rustup target for cross-compilation"), cx);
         log::info!("adding rustup target");
-        run_cmd(Command::new(rustup).args(["target", "add"]).arg(&triple)).await?;
+        run_cmd(
+            new_smol_command(rustup)
+                .args(["target", "add"])
+                .arg(&triple),
+        )
+        .await?;
 
         if which("cargo-zigbuild", cx).await?.is_none() {
             delegate.set_status(Some("Installing cargo-zigbuild for cross-compilation"), cx);
             log::info!("installing cargo-zigbuild");
-            run_cmd(Command::new("cargo").args(["install", "--locked", "cargo-zigbuild"])).await?;
+            run_cmd(new_smol_command("cargo").args(["install", "--locked", "cargo-zigbuild"]))
+                .await?;
         }
 
         delegate.set_status(
@@ -235,7 +242,7 @@ async fn build_remote_server_from_source(
         );
         log::info!("building remote binary from source for {triple} with Zig");
         run_cmd(
-            Command::new("cargo")
+            new_smol_command("cargo")
                 .args([
                     "zigbuild",
                     "--package",
@@ -262,12 +269,13 @@ async fn build_remote_server_from_source(
 
         #[cfg(not(target_os = "windows"))]
         {
-            run_cmd(Command::new("gzip").args(["-f", &bin_path.to_string_lossy()])).await?;
+            run_cmd(new_smol_command("gzip").args(["-f", &bin_path.to_string_lossy()])).await?;
         }
 
         #[cfg(target_os = "windows")]
         {
             // On Windows, we use 7z to compress the binary
+
             let seven_zip = which("7z.exe",cx)
                 .await?
                 .context("7z.exe not found on $PATH, install it (e.g. with `winget install -e --id 7zip.7zip`) or, if you don't want this behaviour, set $env:ZED_BUILD_REMOTE_SERVER=\"nocompress\"")?;
@@ -275,7 +283,7 @@ async fn build_remote_server_from_source(
             if smol::fs::metadata(&gz_path).await.is_ok() {
                 smol::fs::remove_file(&gz_path).await?;
             }
-            run_cmd(Command::new(seven_zip).args([
+            run_cmd(new_smol_command(seven_zip).args([
                 "a",
                 "-tgzip",
                 &gz_path,

crates/remote_server/src/unix.rs 🔗

@@ -16,6 +16,7 @@ use language::LanguageRegistry;
 use node_runtime::{NodeBinaryOptions, NodeRuntime};
 use paths::logs_dir;
 use project::project_settings::ProjectSettings;
+use util::command::new_smol_command;
 
 use proto::CrashReport;
 use release_channel::{AppVersion, RELEASE_CHANNEL, ReleaseChannel};
@@ -656,7 +657,7 @@ pub(crate) fn execute_proxy(
 
 async fn kill_running_server(pid: u32, paths: &ServerPaths) -> Result<(), ExecuteProxyError> {
     log::info!("killing existing server with PID {}", pid);
-    smol::process::Command::new("kill")
+    new_smol_command("kill")
         .arg(pid.to_string())
         .output()
         .await
@@ -707,7 +708,7 @@ async fn spawn_server(paths: &ServerPaths) -> Result<(), SpawnServerError> {
     }
 
     let binary_name = std::env::current_exe().map_err(SpawnServerError::CurrentExe)?;
-    let mut server_process = smol::process::Command::new(binary_name);
+    let mut server_process = new_smol_command(binary_name);
     server_process
         .arg("run")
         .arg("--log-file")
@@ -772,7 +773,7 @@ async fn check_pid_file(path: &Path) -> Result<Option<u32>, CheckPidError> {
     };
 
     log::debug!("Checking if process with PID {} exists...", pid);
-    match smol::process::Command::new("kill")
+    match new_smol_command("kill")
         .arg("-0")
         .arg(pid.to_string())
         .output()

crates/util/src/shell_env.rs 🔗

@@ -34,11 +34,13 @@ async fn capture_unix(
 ) -> Result<collections::HashMap<String, String>> {
     use std::os::unix::process::CommandExt;
 
+    use crate::command::new_std_command;
+
     let shell_kind = ShellKind::new(shell_path, false);
     let zed_path = super::get_shell_safe_zed_path(shell_kind)?;
 
     let mut command_string = String::new();
-    let mut command = std::process::Command::new(shell_path);
+    let mut command = new_std_command(shell_path);
     command.args(args);
     // In some shells, file descriptors greater than 2 cannot be used in interactive mode,
     // so file descriptor 0 (stdin) is used instead. This impacts zsh, old bash; perhaps others.