mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-02 21:02:37 +00:00
More resilient registry removal (#14717)
With the previous order of operations, there could be warnings from race conditions between two process A and B removing and installing Python versions. * A removes the files for CPython3.9.18 * B sees the key CPython3.9.18 * B sees that CPython3.9.18 has no files * A removes the key for CPython3.9.18 * B try to removes the key for CPython3.9.18, gets and error that it's already gone, issues a warning We make the more resilient in two ways: * We remove the registry key first, avoiding dangling registry keys in the removal process * We ignore not found errors in registry removal operations: If we try to remove something that's already gone, that's fine. Fixes #14714 (hopefully)
This commit is contained in:
parent
8f2f43c561
commit
d1f4f8a358
2 changed files with 19 additions and 11 deletions
|
|
@ -268,6 +268,9 @@ pub fn remove_orphan_registry_entries(installations: &[ManagedPythonInstallation
|
|||
// Separate assignment since `keys()` creates a borrow.
|
||||
let subkeys = match key.keys() {
|
||||
Ok(subkeys) => subkeys,
|
||||
Err(err) if err.code() == ERROR_NOT_FOUND => {
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
// TODO(konsti): We don't have an installation key here.
|
||||
warn_user_once!("Failed to list subkeys of HKCU:\\{astral_key}: {err}");
|
||||
|
|
@ -281,6 +284,9 @@ pub fn remove_orphan_registry_entries(installations: &[ManagedPythonInstallation
|
|||
let python_entry = format!("{astral_key}\\{subkey}");
|
||||
debug!("Removing orphan registry key HKCU:\\{}", python_entry);
|
||||
if let Err(err) = CURRENT_USER.remove_tree(&python_entry) {
|
||||
if err.code() == ERROR_NOT_FOUND {
|
||||
continue;
|
||||
}
|
||||
// TODO(konsti): We don't have an installation key here.
|
||||
warn_user_once!("Failed to remove orphan registry key HKCU:\\{python_entry}: {err}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,19 @@ async fn do_uninstall(
|
|||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
||||
// Remove registry entries first, so we don't have dangling entries between the file removal
|
||||
// and the registry removal.
|
||||
let mut errors = vec![];
|
||||
#[cfg(windows)]
|
||||
{
|
||||
uv_python::windows_registry::remove_registry_entry(
|
||||
&matching_installations,
|
||||
all,
|
||||
&mut errors,
|
||||
);
|
||||
uv_python::windows_registry::remove_orphan_registry_entries(&installed_installations);
|
||||
}
|
||||
|
||||
// Find and remove all relevant Python executables
|
||||
let mut uninstalled_executables: FxHashMap<PythonInstallationKey, FxHashSet<PathBuf>> =
|
||||
FxHashMap::default();
|
||||
|
|
@ -201,7 +214,6 @@ async fn do_uninstall(
|
|||
}
|
||||
|
||||
let mut uninstalled = IndexSet::<PythonInstallationKey>::default();
|
||||
let mut errors = vec![];
|
||||
while let Some((key, result)) = tasks.next().await {
|
||||
if let Err(err) = result {
|
||||
errors.push((key.clone(), anyhow::Error::new(err)));
|
||||
|
|
@ -210,16 +222,6 @@ async fn do_uninstall(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
uv_python::windows_registry::remove_registry_entry(
|
||||
&matching_installations,
|
||||
all,
|
||||
&mut errors,
|
||||
);
|
||||
uv_python::windows_registry::remove_orphan_registry_entries(&installed_installations);
|
||||
}
|
||||
|
||||
// Read all existing managed installations and find the highest installed patch
|
||||
// for each installed minor version. Ensure the minor version link directory
|
||||
// is still valid.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue