mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-11-03 21:23:54 +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.
 | 
					    // Separate assignment since `keys()` creates a borrow.
 | 
				
			||||||
    let subkeys = match key.keys() {
 | 
					    let subkeys = match key.keys() {
 | 
				
			||||||
        Ok(subkeys) => subkeys,
 | 
					        Ok(subkeys) => subkeys,
 | 
				
			||||||
 | 
					        Err(err) if err.code() == ERROR_NOT_FOUND => {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        Err(err) => {
 | 
					        Err(err) => {
 | 
				
			||||||
            // TODO(konsti): We don't have an installation key here.
 | 
					            // TODO(konsti): We don't have an installation key here.
 | 
				
			||||||
            warn_user_once!("Failed to list subkeys of HKCU:\\{astral_key}: {err}");
 | 
					            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}");
 | 
					        let python_entry = format!("{astral_key}\\{subkey}");
 | 
				
			||||||
        debug!("Removing orphan registry key HKCU:\\{}", python_entry);
 | 
					        debug!("Removing orphan registry key HKCU:\\{}", python_entry);
 | 
				
			||||||
        if let Err(err) = CURRENT_USER.remove_tree(&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.
 | 
					            // TODO(konsti): We don't have an installation key here.
 | 
				
			||||||
            warn_user_once!("Failed to remove orphan registry key HKCU:\\{python_entry}: {err}");
 | 
					            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);
 | 
					        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
 | 
					    // Find and remove all relevant Python executables
 | 
				
			||||||
    let mut uninstalled_executables: FxHashMap<PythonInstallationKey, FxHashSet<PathBuf>> =
 | 
					    let mut uninstalled_executables: FxHashMap<PythonInstallationKey, FxHashSet<PathBuf>> =
 | 
				
			||||||
        FxHashMap::default();
 | 
					        FxHashMap::default();
 | 
				
			||||||
| 
						 | 
					@ -201,7 +214,6 @@ async fn do_uninstall(
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut uninstalled = IndexSet::<PythonInstallationKey>::default();
 | 
					    let mut uninstalled = IndexSet::<PythonInstallationKey>::default();
 | 
				
			||||||
    let mut errors = vec![];
 | 
					 | 
				
			||||||
    while let Some((key, result)) = tasks.next().await {
 | 
					    while let Some((key, result)) = tasks.next().await {
 | 
				
			||||||
        if let Err(err) = result {
 | 
					        if let Err(err) = result {
 | 
				
			||||||
            errors.push((key.clone(), anyhow::Error::new(err)));
 | 
					            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
 | 
					    // Read all existing managed installations and find the highest installed patch
 | 
				
			||||||
    // for each installed minor version. Ensure the minor version link directory
 | 
					    // for each installed minor version. Ensure the minor version link directory
 | 
				
			||||||
    // is still valid.
 | 
					    // is still valid.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue