Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/uv-shell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ 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 }

[target.'cfg(unix)'.dependencies]
nix = { workspace = true }

[target.'cfg(windows)'.dependencies]
windows-registry = { workspace = true }
windows-result = { workspace = true }
Expand Down
48 changes: 48 additions & 0 deletions crates/uv-shell/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use std::path::{Path, PathBuf};
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)]
Expand Down Expand Up @@ -64,6 +67,51 @@ 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<Self> {
#[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) = 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);
}
}

// If reading exe fails, try reading the comm file
let proc_comm_path = format!("/proc/{ppid}/comm");
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)) {
return Some(shell);
}
}

debug!("Could not determine shell from parent process");
None
}

#[cfg(not(unix))]
{
None
}
}
Expand Down
Loading