Fix handling of `sys.base_prefix` collision in interpreter identity check during tool installs (#7596)

Closes https://github.com/astral-sh/uv/issues/7586

Extends https://github.com/astral-sh/uv/pull/7593 (thanks @lucab!)

---------

Co-authored-by: Luca BRUNO <lucab@lucabruno.net>
This commit is contained in:
Zanie Blue 2024-09-20 14:01:14 -05:00 committed by GitHub
parent e93b54e240
commit d6c9603594
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 19 additions and 7 deletions

1
Cargo.lock generated
View File

@ -4482,6 +4482,7 @@ dependencies = [
"regex", "regex",
"reqwest", "reqwest",
"rustc-hash", "rustc-hash",
"same-file",
"serde", "serde",
"serde_json", "serde_json",
"similar", "similar",

View File

@ -66,6 +66,7 @@ owo-colors = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
regex = { workspace = true } regex = { workspace = true }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
same-file = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }

View File

@ -276,13 +276,23 @@ pub(crate) async fn install(
installed_tools installed_tools
.get_environment(&from.name, &cache)? .get_environment(&from.name, &cache)?
.filter(|environment| { .filter(|environment| {
// NOTE(lucab): this compares `base_prefix` paths as a proxy for // TODO(zanieb): Consider using `sysconfig.get_path("stdlib")` instead, which
// detecting interpreters mismatches. Directly comparing interpreters // should be generally robust.
// (by paths or binaries on-disk) would result in several false // TODO(zanieb): Move this into a utility on `Interpreter` since it's non-trivial.
// positives on Windows due to file-copying and shims. let same_interpreter = if cfg!(windows) {
// On Windows, we can't canonicalize an interpreter based on its executable path
// because the executables are separate shim files (not links). Instead, we
// compare the `sys.base_prefix`.
let old_base_prefix = environment.interpreter().sys_base_prefix(); let old_base_prefix = environment.interpreter().sys_base_prefix();
let selected_base_prefix = interpreter.sys_base_prefix(); let selected_base_prefix = interpreter.sys_base_prefix();
if old_base_prefix == selected_base_prefix { old_base_prefix == selected_base_prefix
} else {
// On Unix, we can see if the canonicalized executable is the same file.
environment.interpreter().sys_executable() == interpreter.sys_executable()
|| same_file::is_same_file(environment.interpreter().sys_executable(), interpreter.sys_executable()).unwrap_or(false)
};
if same_interpreter {
trace!( trace!(
"Existing interpreter matches the requested interpreter for `{}`: {}", "Existing interpreter matches the requested interpreter for `{}`: {}",
from.name, from.name,