mirror of https://github.com/astral-sh/uv
Add shell detection and venv discovery to 'uv activate' error message
- Detect user's current shell (Bash, Zsh, Fish, Nushell, Csh, PowerShell, Cmd) - Search for virtual environment in current and parent directories - Provide shell-specific activation command with correct path - Show helpful hint when no venv is found Addresses feedback from @zanieb to use shell detection logic and discover the virtual environment.
This commit is contained in:
parent
827627ea60
commit
8fc58a6dca
|
|
@ -6,7 +6,7 @@ use std::fmt::Write;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
@ -45,6 +45,7 @@ use uv_requirements::{GroupsSpecification, RequirementsSource};
|
||||||
use uv_requirements_txt::RequirementsTxtRequirement;
|
use uv_requirements_txt::RequirementsTxtRequirement;
|
||||||
use uv_scripts::{Pep723Error, Pep723Item, Pep723Metadata, Pep723Script};
|
use uv_scripts::{Pep723Error, Pep723Item, Pep723Metadata, Pep723Script};
|
||||||
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
|
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
|
||||||
|
use uv_shell::{Shell, shlex_posix, shlex_windows};
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
use uv_warnings::{warn_user, warn_user_once};
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
|
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
|
||||||
|
|
@ -2490,8 +2491,95 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"activate" => {
|
"activate" => {
|
||||||
// Handle "activate" with a helpful error message
|
let current_dir = match std::env::current_dir() {
|
||||||
// instead of the generic unknown command error
|
Ok(dir) => dir,
|
||||||
|
Err(_) => PathBuf::from("."),
|
||||||
|
};
|
||||||
|
let mut venv_path = None;
|
||||||
|
|
||||||
|
for dir in current_dir.ancestors() {
|
||||||
|
// If we're _within_ a virtualenv, use it.
|
||||||
|
if uv_fs::is_virtualenv_base(dir) {
|
||||||
|
venv_path = Some(dir.to_path_buf());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, search for a `.venv` directory.
|
||||||
|
let dot_venv = dir.join(".venv");
|
||||||
|
if dot_venv.is_dir() && uv_fs::is_virtualenv_base(&dot_venv) {
|
||||||
|
venv_path = Some(dot_venv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = venv_path {
|
||||||
|
// Determine the appropriate activation command based on the shell.
|
||||||
|
let activation = match Shell::from_env() {
|
||||||
|
None => {
|
||||||
|
// If we can't detect the shell, provide a generic message with common commands.
|
||||||
|
eprintln!(
|
||||||
|
"{} `uv activate` is not supported. To activate a virtual environment, use:",
|
||||||
|
"error".red().bold()
|
||||||
|
);
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
" {}",
|
||||||
|
format!(
|
||||||
|
"source {}",
|
||||||
|
path.join("bin/activate").display()
|
||||||
|
)
|
||||||
|
.green()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
" {}",
|
||||||
|
format!("{}\\Scripts\\activate", path.display())
|
||||||
|
.green()
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
" {}",
|
||||||
|
format!("{}\\Scripts\\Activate.ps1", path.display())
|
||||||
|
.green()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ExitStatus::Error.into();
|
||||||
|
}
|
||||||
|
Some(Shell::Bash | Shell::Zsh | Shell::Ksh) => Some(format!(
|
||||||
|
"source {}",
|
||||||
|
shlex_posix(path.join("bin/activate"))
|
||||||
|
)),
|
||||||
|
Some(Shell::Fish) => Some(format!(
|
||||||
|
"source {}",
|
||||||
|
shlex_posix(path.join("bin/activate.fish"))
|
||||||
|
)),
|
||||||
|
Some(Shell::Nushell) => Some(format!(
|
||||||
|
"overlay use {}",
|
||||||
|
shlex_posix(path.join("bin/activate.nu"))
|
||||||
|
)),
|
||||||
|
Some(Shell::Csh) => Some(format!(
|
||||||
|
"source {}",
|
||||||
|
shlex_posix(path.join("bin/activate.csh"))
|
||||||
|
)),
|
||||||
|
Some(Shell::Powershell) => Some(shlex_windows(
|
||||||
|
path.join("Scripts/activate"),
|
||||||
|
Shell::Powershell,
|
||||||
|
)),
|
||||||
|
Some(Shell::Cmd) => {
|
||||||
|
Some(shlex_windows(path.join("Scripts/activate"), Shell::Cmd))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(act) = activation {
|
||||||
|
eprintln!(
|
||||||
|
"{} `uv activate` is not supported. To activate a virtual environment, use:",
|
||||||
|
"error".red().bold()
|
||||||
|
);
|
||||||
|
eprintln!(" {}", act.green());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{} `uv activate` is not supported. To activate a virtual environment, use:",
|
"{} `uv activate` is not supported. To activate a virtual environment, use:",
|
||||||
"error".red().bold()
|
"error".red().bold()
|
||||||
|
|
@ -2510,6 +2598,7 @@ where
|
||||||
"hint".bold().cyan(),
|
"hint".bold().cyan(),
|
||||||
"uv venv".green()
|
"uv venv".green()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
return ExitStatus::Error.into();
|
return ExitStatus::Error.into();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue