From 14c68c144002fa5ed5387c878b3da6a3a178bb11 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 18 Aug 2025 09:37:21 -0500 Subject: [PATCH 1/4] Add fallback approach to shell detection for unix-like systems --- Cargo.lock | 1 + crates/uv-shell/Cargo.toml | 3 +++ crates/uv-shell/src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 001055e458ecf..29afe86999259 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6272,6 +6272,7 @@ dependencies = [ "anyhow", "fs-err", "home", + "nix 0.30.1", "same-file", "tempfile", "tracing", diff --git a/crates/uv-shell/Cargo.toml b/crates/uv-shell/Cargo.toml index e0c75f8e45641..658526a18842c 100644 --- a/crates/uv-shell/Cargo.toml +++ b/crates/uv-shell/Cargo.toml @@ -19,6 +19,9 @@ home = { workspace = true } same-file = { workspace = true } tracing = { workspace = true } +[target.'cfg(unix)'.dependencies] +nix = { workspace = true } + [target.'cfg(windows)'.dependencies] windows-registry = { workspace = true } windows-result = { workspace = true } diff --git a/crates/uv-shell/src/lib.rs b/crates/uv-shell/src/lib.rs index 5593a49477d4c..cd9a756e1cf8f 100644 --- a/crates/uv-shell/src/lib.rs +++ b/crates/uv-shell/src/lib.rs @@ -5,6 +5,7 @@ pub mod windows; pub use shlex::{escape_posix_for_single_quotes, shlex_posix, shlex_windows}; use std::path::{Path, PathBuf}; +use tracing::debug; use uv_fs::Simplified; use uv_static::EnvVars; @@ -64,6 +65,52 @@ impl Shell { Some(Self::Powershell) } } else { + // Fallback to detecting the shell from the parent process + Self::from_parent_process() + } + } + + /// Attempt to determine the shell from the parent process. + /// + /// This is a fallback method for when environment variables don't provide + /// enough information about the current shell. It looks at the parent process + /// to try to identify which shell is running. + /// + /// This method currently only works on Unix-like systems. On other platforms, + /// it returns `None`. + fn from_parent_process() -> Option { + #[cfg(unix)] + { + + // Get the parent process ID + let ppid = nix::unistd::getppid(); + debug!("Detected parent process ID: {ppid}"); + + // Try to read the parent process executable path + let proc_exe_path = format!("/proc/{ppid}/exe"); + if let Ok(exe_path) = std::fs::read_link(&proc_exe_path) { + debug!("Parent process executable: {}", exe_path.display()); + if let Some(shell) = Self::from_shell_path(&exe_path) { + return Some(shell); + } + } + + // If reading exe fails, try reading the comm file + let proc_comm_path = format!("/proc/{ppid}/comm"); + if let Ok(comm) = std::fs::read_to_string(&proc_comm_path) { + let comm = comm.trim(); + debug!("Parent process comm: {comm}"); + if let Some(shell) = parse_shell_from_path(Path::new(comm)) { + return Some(shell); + } + } + + debug!("Could not determine shell from parent process"); + None + } + + #[cfg(not(unix))] + { None } } From 2ee77ad918497df976a107aac0a693c0e5193ffc Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 18 Aug 2025 11:37:55 -0500 Subject: [PATCH 2/4] Fix linter error --- crates/uv-shell/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/uv-shell/src/lib.rs b/crates/uv-shell/src/lib.rs index cd9a756e1cf8f..1f6d0466b9f0e 100644 --- a/crates/uv-shell/src/lib.rs +++ b/crates/uv-shell/src/lib.rs @@ -81,7 +81,6 @@ impl Shell { fn from_parent_process() -> Option { #[cfg(unix)] { - // Get the parent process ID let ppid = nix::unistd::getppid(); debug!("Detected parent process ID: {ppid}"); From 93128684ecf960f39138c630af0b6d8c54eca75c Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 18 Aug 2025 11:56:36 -0500 Subject: [PATCH 3/4] Replace std::fs with fs-err in Shell::from_parent_process --- crates/uv-shell/Cargo.toml | 1 + crates/uv-shell/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/uv-shell/Cargo.toml b/crates/uv-shell/Cargo.toml index 658526a18842c..f70fffa00b450 100644 --- a/crates/uv-shell/Cargo.toml +++ b/crates/uv-shell/Cargo.toml @@ -15,6 +15,7 @@ uv-fs = { workspace = true } uv-static = { workspace = true } anyhow = { workspace = true } +fs-err = { workspace = true } home = { workspace = true } same-file = { workspace = true } tracing = { workspace = true } diff --git a/crates/uv-shell/src/lib.rs b/crates/uv-shell/src/lib.rs index 1f6d0466b9f0e..f8a38f97f9810 100644 --- a/crates/uv-shell/src/lib.rs +++ b/crates/uv-shell/src/lib.rs @@ -87,7 +87,7 @@ impl Shell { // Try to read the parent process executable path let proc_exe_path = format!("/proc/{ppid}/exe"); - if let Ok(exe_path) = std::fs::read_link(&proc_exe_path) { + if let Ok(exe_path) = fs_err::read_link(&proc_exe_path) { debug!("Parent process executable: {}", exe_path.display()); if let Some(shell) = Self::from_shell_path(&exe_path) { return Some(shell); @@ -96,7 +96,7 @@ impl Shell { // If reading exe fails, try reading the comm file let proc_comm_path = format!("/proc/{ppid}/comm"); - if let Ok(comm) = std::fs::read_to_string(&proc_comm_path) { + if let Ok(comm) = fs_err::read_to_string(&proc_comm_path) { let comm = comm.trim(); debug!("Parent process comm: {comm}"); if let Some(shell) = parse_shell_from_path(Path::new(comm)) { From 4782bda1d319f7be781706e4b976b643f4d387ca Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 18 Aug 2025 12:48:58 -0500 Subject: [PATCH 4/4] Add conditional import for tracing::debug on Unix only --- crates/uv-shell/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/uv-shell/src/lib.rs b/crates/uv-shell/src/lib.rs index f8a38f97f9810..a18e04b0369d2 100644 --- a/crates/uv-shell/src/lib.rs +++ b/crates/uv-shell/src/lib.rs @@ -5,10 +5,12 @@ pub mod windows; pub use shlex::{escape_posix_for_single_quotes, shlex_posix, shlex_windows}; use std::path::{Path, PathBuf}; -use tracing::debug; use uv_fs::Simplified; use uv_static::EnvVars; +#[cfg(unix)] +use tracing::debug; + /// Shells for which virtualenv activation scripts are available. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[allow(clippy::doc_markdown)]