mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-15 06:55:14 +00:00
Allow apostrophe in venv name (#8984)
Escape an apostrophe in the venv path name. Fixes #8947
This commit is contained in:
parent
0abb2a4595
commit
997ff9d57a
4 changed files with 62 additions and 9 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -5575,6 +5575,7 @@ dependencies = [
|
||||||
"uv-platform-tags",
|
"uv-platform-tags",
|
||||||
"uv-pypi-types",
|
"uv-pypi-types",
|
||||||
"uv-python",
|
"uv-python",
|
||||||
|
"uv-shell",
|
||||||
"uv-version",
|
"uv-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ uv-platform-tags = { workspace = true }
|
||||||
uv-pypi-types = { workspace = true }
|
uv-pypi-types = { workspace = true }
|
||||||
uv-python = { workspace = true }
|
uv-python = { workspace = true }
|
||||||
uv-version = { workspace = true }
|
uv-version = { workspace = true }
|
||||||
|
uv-shell = { workspace = true }
|
||||||
|
|
||||||
fs-err = { workspace = true }
|
fs-err = { workspace = true }
|
||||||
itertools = { workspace = true }
|
itertools = { workspace = true }
|
||||||
|
|
|
@ -13,6 +13,7 @@ use tracing::debug;
|
||||||
use uv_fs::{cachedir, Simplified, CWD};
|
use uv_fs::{cachedir, Simplified, CWD};
|
||||||
use uv_pypi_types::Scheme;
|
use uv_pypi_types::Scheme;
|
||||||
use uv_python::{Interpreter, VirtualEnvironment};
|
use uv_python::{Interpreter, VirtualEnvironment};
|
||||||
|
use uv_shell::escape_posix_for_single_quotes;
|
||||||
use uv_version::version;
|
use uv_version::version;
|
||||||
|
|
||||||
use crate::{Error, Prompt};
|
use crate::{Error, Prompt};
|
||||||
|
@ -287,23 +288,20 @@ pub(crate) fn create(
|
||||||
|
|
||||||
let virtual_env_dir = match (relocatable, name.to_owned()) {
|
let virtual_env_dir = match (relocatable, name.to_owned()) {
|
||||||
(true, "activate") => {
|
(true, "activate") => {
|
||||||
r#"'"$(dirname -- "$(dirname -- "$(realpath -- "$SCRIPT_PATH")")")"'"#
|
r#"'"$(dirname -- "$(dirname -- "$(realpath -- "$SCRIPT_PATH")")")"'"#.to_string()
|
||||||
}
|
}
|
||||||
(true, "activate.bat") => r"%~dp0..",
|
(true, "activate.bat") => r"%~dp0..".to_string(),
|
||||||
(true, "activate.fish") => {
|
(true, "activate.fish") => {
|
||||||
r#"'"$(dirname -- "$(cd "$(dirname -- "$(status -f)")"; and pwd)")"'"#
|
r#"'"$(dirname -- "$(cd "$(dirname -- "$(status -f)")"; and pwd)")"'"#.to_string()
|
||||||
}
|
}
|
||||||
// Note:
|
// Note:
|
||||||
// * relocatable activate scripts appear not to be possible in csh and nu shell
|
// * relocatable activate scripts appear not to be possible in csh and nu shell
|
||||||
// * `activate.ps1` is already relocatable by default.
|
// * `activate.ps1` is already relocatable by default.
|
||||||
_ => {
|
_ => escape_posix_for_single_quotes(location.simplified().to_str().unwrap()),
|
||||||
// SAFETY: `unwrap` is guaranteed to succeed because `location` is an `Utf8PathBuf`.
|
|
||||||
location.simplified().to_str().unwrap()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let activator = template
|
let activator = template
|
||||||
.replace("{{ VIRTUAL_ENV_DIR }}", virtual_env_dir)
|
.replace("{{ VIRTUAL_ENV_DIR }}", &virtual_env_dir)
|
||||||
.replace("{{ BIN_NAME }}", bin_name)
|
.replace("{{ BIN_NAME }}", bin_name)
|
||||||
.replace(
|
.replace(
|
||||||
"{{ VIRTUAL_PROMPT }}",
|
"{{ VIRTUAL_PROMPT }}",
|
||||||
|
|
|
@ -3,7 +3,6 @@ use assert_cmd::prelude::*;
|
||||||
use assert_fs::prelude::*;
|
use assert_fs::prelude::*;
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use predicates::prelude::*;
|
use predicates::prelude::*;
|
||||||
|
|
||||||
use uv_python::{PYTHON_VERSIONS_FILENAME, PYTHON_VERSION_FILENAME};
|
use uv_python::{PYTHON_VERSIONS_FILENAME, PYTHON_VERSION_FILENAME};
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
@ -1087,3 +1086,57 @@ fn path_with_trailing_space_gives_proper_error() {
|
||||||
);
|
);
|
||||||
// Note the extra trailing `/` in the snapshot is due to the filters, not the actual output.
|
// Note the extra trailing `/` in the snapshot is due to the filters, not the actual output.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the activate script still works with the path contains an apostrophe.
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn create_venv_apostrophe() {
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::process::Stdio;
|
||||||
|
|
||||||
|
let context = TestContext::new_with_versions(&["3.12"]);
|
||||||
|
|
||||||
|
let venv_dir = context.temp_dir.join("Testing's");
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg(&venv_dir)
|
||||||
|
.arg("--python")
|
||||||
|
.arg("3.12"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtual environment at: Testing's
|
||||||
|
Activate with: source Testing's/[BIN]/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
// One of them should be commonly available on a linux developer machine, if not, we have to
|
||||||
|
// extend the fallbacks.
|
||||||
|
let shell = env::var_os("SHELL").unwrap_or(OsString::from("bash"));
|
||||||
|
let mut child = Command::new(shell)
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.current_dir(&venv_dir)
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to spawn shell script");
|
||||||
|
|
||||||
|
let mut stdin = child.stdin.take().expect("Failed to open stdin");
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
stdin
|
||||||
|
.write_all(". bin/activate && python -c 'import sys; print(sys.prefix)'".as_bytes())
|
||||||
|
.expect("Failed to write to stdin");
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = child.wait_with_output().expect("Failed to read stdout");
|
||||||
|
|
||||||
|
assert!(output.status.success(), "{output:?}");
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert_eq!(stdout.trim(), venv_dir.to_string_lossy());
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue