Use the windows crate facade consistently (#15737)

The initial motivation for this change was that we were using both the
`windows`, the `window_sys` and the `windows_core` crate in various
places. These crates have slightly unconventional versioning scheme
where there is a large workspace with the same version in general, but
only some crates get breaking releases when a new breaking release
happens, the others stay on the previous breaking version. The `windows`
crate is a shim for all three of them, with a single version. This
simplifies handling the versions.

Using `windows` over `windows_sys` has the advantage of a higher level
error interface, we now get a `Result` for all windows API calls instead
of C-style int-returns and get-last-error calls. This makes the
uv-keyring crate more resilient.

We keep using the `windows_registry` crate, which provides a higher
level interface to windows registry access.
This commit is contained in:
konsti
2025-09-09 17:07:14 +02:00
committed by GitHub
parent 12764df8b2
commit cd49e1d11f
15 changed files with 123 additions and 130 deletions
+11 -14
View File
@@ -12,13 +12,10 @@ use thiserror::Error;
use tracing::debug;
use uv_platform::Arch;
use uv_warnings::{warn_user, warn_user_once};
use windows::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows::Win32::System::Registry::{KEY_WOW64_32KEY, KEY_WOW64_64KEY};
use windows::core::HRESULT;
use windows_registry::{CURRENT_USER, HSTRING, Key, LOCAL_MACHINE, Value};
use windows_result::HRESULT;
use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows_sys::Win32::System::Registry::{KEY_WOW64_32KEY, KEY_WOW64_64KEY};
/// Code returned when the registry key doesn't exist.
const ERROR_NOT_FOUND: HRESULT = HRESULT::from_win32(ERROR_FILE_NOT_FOUND);
/// A Python interpreter found in the Windows registry through PEP 514 or from a known Microsoft
/// Store path.
@@ -32,7 +29,7 @@ pub(crate) struct WindowsPython {
}
/// Find all Pythons registered in the Windows registry following PEP 514.
pub(crate) fn registry_pythons() -> Result<Vec<WindowsPython>, windows_result::Error> {
pub(crate) fn registry_pythons() -> Result<Vec<WindowsPython>, windows::core::Error> {
let mut registry_pythons = Vec::new();
// Prefer `HKEY_CURRENT_USER` over `HKEY_LOCAL_MACHINE`.
// By default, a 64-bit program does not see a 32-bit global (HKLM) installation of Python in
@@ -47,7 +44,7 @@ pub(crate) fn registry_pythons() -> Result<Vec<WindowsPython>, windows_result::E
let mut open_options = root_key.options();
open_options.read();
if let Some(access_modifier) = access_modifier {
open_options.access(access_modifier);
open_options.access(access_modifier.0);
}
let Ok(key_python) = open_options.open(r"Software\Python") else {
continue;
@@ -131,7 +128,7 @@ pub enum ManagedPep514Error {
#[error("Windows has an unknown pointer width for arch: `{_0}`")]
InvalidPointerSize(Arch),
#[error("Failed to write registry entry: {0}")]
WriteError(#[from] windows_result::Error),
WriteError(#[from] windows::core::Error),
}
/// Register a managed Python installation in the Windows registry following PEP 514.
@@ -216,7 +213,7 @@ pub fn remove_registry_entry<'a>(
if all {
debug!("Removing registry key HKCU:\\{}", astral_key);
if let Err(err) = CURRENT_USER.remove_tree(&astral_key) {
if err.code() == ERROR_NOT_FOUND {
if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) {
debug!("No registry entries to remove, no registry key {astral_key}");
} else {
warn_user!("Failed to clear registry entries under {astral_key}: {err}");
@@ -230,7 +227,7 @@ pub fn remove_registry_entry<'a>(
let python_entry = format!("{astral_key}\\{python_tag}");
debug!("Removing registry key HKCU:\\{}", python_entry);
if let Err(err) = CURRENT_USER.remove_tree(&python_entry) {
if err.code() == ERROR_NOT_FOUND {
if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) {
debug!(
"No registry entries to remove for {}, no registry key {}",
installation.key(),
@@ -256,7 +253,7 @@ pub fn remove_orphan_registry_entries(installations: &[ManagedPythonInstallation
let astral_key = format!("Software\\Python\\{COMPANY_KEY}");
let key = match CURRENT_USER.open(&astral_key) {
Ok(subkeys) => subkeys,
Err(err) if err.code() == ERROR_NOT_FOUND => {
Err(err) if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) => {
return;
}
Err(err) => {
@@ -268,7 +265,7 @@ 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 => {
Err(err) if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) => {
return;
}
Err(err) => {
@@ -284,7 +281,7 @@ 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 {
if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) {
continue;
}
// TODO(konsti): We don't have an installation key here.