From 097024d46ffc12756c6451517f55d41c14849866 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 18 Nov 2025 15:31:39 +0100 Subject: [PATCH] util: Use process spawn helpers in more places (#42976) Release Notes: - N/A *or* Added/Fixed/Improved ... --- 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(-) diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index accda1b1ce4b09db0bc4cc0fb5824290725cb8ee..010e011526ffc6d0332a5c22da107f380ff37c91 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/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> { - let output = Command::new(downloaded_installer) + let output = new_smol_command(downloaded_installer) .arg("/verysilent") .arg("/update=true") .arg("!desktopicon") diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index 6c2d13d2e78f003a950e5c1dc135b503ae6d4087..21468370c499058af207a7e7b02ca1bbd7563ec1 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/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 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 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") diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index cc6390cdb887a6c08fbb4520c9ab9fac4b50f9cf..46477045722e132a275f926140915dbb9bd6cd5c 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/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") diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index c2b0845940d1639629d59b634e9ece73c9e4cf3a..0b29ee93f3d4d1f1bc79e9ff93d99f80a24f473b 100644 --- a/crates/languages/src/rust.rs +++ b/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 { - 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") { diff --git a/crates/project/src/debugger/locators/cargo.rs b/crates/project/src/debugger/locators/cargo.rs index 72aafff51609c8e55ac15f671a7b7f553b34d44f..0633f4881b33c096da1dddb59f1cfa11a39e4849 100644 --- a/crates/project/src/debugger/locators/cargo.rs +++ b/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() diff --git a/crates/project/src/environment.rs b/crates/project/src/environment.rs index 478ba6dd17f2ac0dfcedbd5f42ed12856b413ea3..32ed2f87668979802a44dcc233a1e87dc3c2e958 100644 --- a/crates/project/src/environment.rs +++ b/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") diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 769e75de3e8a001bf140708dd7443a48c55ed280..ef21c97f8178181493968c984e6534772eac9beb 100644 --- a/crates/project/src/terminals.rs +++ b/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 { diff --git a/crates/remote/src/transport.rs b/crates/remote/src/transport.rs index 14a23257ce0bffbe138567f7aa27fc6a6d63d817..211851c0629c13f1f79ce425cafc582899d1b58f 100644 --- a/crates/remote/src/transport.rs +++ b/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, diff --git a/crates/remote_server/src/unix.rs b/crates/remote_server/src/unix.rs index c51b93d4554aca86d13cefeb9dd4aaadacda399c..29e5ef735f5a001c23e3215c1a3fc5d291830282 100644 --- a/crates/remote_server/src/unix.rs +++ b/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, 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() diff --git a/crates/util/src/shell_env.rs b/crates/util/src/shell_env.rs index 7b8239007980158bb7e5d5956bebb4c5bfb576dd..02b262298795f8a50d9612f65479c0299e7e6a3e 100644 --- a/crates/util/src/shell_env.rs +++ b/crates/util/src/shell_env.rs @@ -34,11 +34,13 @@ async fn capture_unix( ) -> Result> { 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.