mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-17 22:07:47 +00:00
Fix Python executable installation when multiple patch versions are requested (#9607)
Closes https://github.com/astral-sh/uv/issues/9601
This commit is contained in:
parent
8b02d7191d
commit
9262d44f1d
2 changed files with 64 additions and 7 deletions
|
@ -300,9 +300,11 @@ pub(crate) async fn install(
|
|||
None
|
||||
};
|
||||
|
||||
let installations: Vec<_> = downloaded.iter().chain(satisfied.iter().copied()).collect();
|
||||
|
||||
// Ensure that the installations are _complete_ for both downloaded installations and existing
|
||||
// installations that match the request
|
||||
for installation in downloaded.iter().chain(satisfied.iter().copied()) {
|
||||
for installation in &installations {
|
||||
installation.ensure_externally_managed()?;
|
||||
installation.ensure_canonical_executables()?;
|
||||
|
||||
|
@ -353,7 +355,13 @@ pub(crate) async fn install(
|
|||
);
|
||||
|
||||
// Figure out what installation it references, if any
|
||||
let existing = find_matching_bin_link(&existing_installations, &target);
|
||||
let existing = find_matching_bin_link(
|
||||
installations
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(existing_installations.iter()),
|
||||
&target,
|
||||
);
|
||||
|
||||
match existing {
|
||||
None => {
|
||||
|
@ -373,7 +381,7 @@ pub(crate) async fn install(
|
|||
target.simplified_display()
|
||||
);
|
||||
}
|
||||
Some(existing) if existing == installation => {
|
||||
Some(existing) if existing == *installation => {
|
||||
// The existing link points to the same installation, so we're done unless
|
||||
// they requested we reinstall
|
||||
if !(reinstall || force) {
|
||||
|
@ -429,6 +437,17 @@ pub(crate) async fn install(
|
|||
|
||||
// Replace the existing link
|
||||
fs_err::remove_file(&to)?;
|
||||
|
||||
if let Some(existing) = existing {
|
||||
// Ensure we do not report installation of this executable for an existing
|
||||
// key if we undo it
|
||||
changelog
|
||||
.installed_executables
|
||||
.entry(existing.key().clone())
|
||||
.or_default()
|
||||
.remove(&target);
|
||||
}
|
||||
|
||||
installation.create_bin_link(&target)?;
|
||||
debug!(
|
||||
"Updated executable at `{}` to {}",
|
||||
|
@ -562,6 +581,10 @@ pub(crate) fn format_executables(
|
|||
return String::new();
|
||||
};
|
||||
|
||||
if installed.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let names = installed
|
||||
.iter()
|
||||
.filter_map(|path| path.file_name())
|
||||
|
@ -612,7 +635,7 @@ fn warn_if_not_on_path(bin: &Path) {
|
|||
/// Like [`ManagedPythonInstallation::is_bin_link`], but this method will only resolve the
|
||||
/// given path one time.
|
||||
fn find_matching_bin_link<'a>(
|
||||
installations: &'a [ManagedPythonInstallation],
|
||||
mut installations: impl Iterator<Item = &'a ManagedPythonInstallation>,
|
||||
path: &Path,
|
||||
) -> Option<&'a ManagedPythonInstallation> {
|
||||
let target = if cfg!(unix) {
|
||||
|
@ -630,7 +653,5 @@ fn find_matching_bin_link<'a>(
|
|||
unreachable!("Only Windows and Unix are supported")
|
||||
};
|
||||
|
||||
installations
|
||||
.iter()
|
||||
.find(|installation| installation.executable() == target)
|
||||
installations.find(|installation| installation.executable() == target)
|
||||
}
|
||||
|
|
|
@ -227,6 +227,42 @@ fn python_install_preview() {
|
|||
|
||||
// The executable should be removed
|
||||
bin_python.assert(predicate::path::missing());
|
||||
|
||||
// Install multiple patch versions
|
||||
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.7").arg("3.12.6"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Installed 2 versions in [TIME]
|
||||
+ cpython-3.12.6-[PLATFORM]
|
||||
+ cpython-3.12.7-[PLATFORM] (python3.12)
|
||||
"###);
|
||||
|
||||
let bin_python = context
|
||||
.temp_dir
|
||||
.child("bin")
|
||||
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
|
||||
|
||||
// The link should be for the newer patch version
|
||||
if cfg!(unix) {
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
insta::assert_snapshot!(
|
||||
read_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.7-[PLATFORM]/bin/python3.12"
|
||||
);
|
||||
});
|
||||
} else {
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
insta::assert_snapshot!(
|
||||
read_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.7-[PLATFORM]/python"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue