diff --git a/Cargo.lock b/Cargo.lock index 86855115f..486f5e160 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5097,7 +5097,6 @@ dependencies = [ "which", "whoami", "windows 0.59.0", - "windows-result", "wiremock", "zip", ] @@ -5711,7 +5710,6 @@ dependencies = [ "tokio", "tracing", "windows 0.59.0", - "windows-core 0.59.0", ] [[package]] @@ -5858,7 +5856,7 @@ dependencies = [ "security-framework", "thiserror 2.0.16", "tokio", - "windows-sys 0.59.0", + "windows 0.59.0", "zeroize", ] @@ -6144,9 +6142,8 @@ dependencies = [ "uv-trampoline-builder", "uv-warnings", "which", + "windows 0.59.0", "windows-registry", - "windows-result", - "windows-sys 0.59.0", ] [[package]] @@ -6357,9 +6354,8 @@ dependencies = [ "tracing", "uv-fs", "uv-static", + "windows 0.59.0", "windows-registry", - "windows-result", - "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 75ebd6a5e..d52099ae0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -195,11 +195,8 @@ uuid = { version = "1.16.0" } version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "06ec5a5f59ffaeb6cf5079c6cb184467da06c9db" } walkdir = { version = "2.5.0" } which = { version = "8.0.0", features = ["regex"] } -windows = { version = "0.59.0", features = ["Win32_Globalization", "Win32_System_Console", "Win32_System_Kernel", "Win32_System_Diagnostics_Debug", "Win32_Storage_FileSystem"] } -windows-core = { version = "0.59.0" } +windows = { version = "0.59.0", features = ["Win32_Globalization", "Win32_Security", "Win32_System_Console", "Win32_System_Kernel", "Win32_System_Diagnostics_Debug", "Win32_Storage_FileSystem", "Win32_System_Registry", "Win32_System_IO", "Win32_System_Ioctl"] } windows-registry = { version = "0.5.0" } -windows-result = { version = "0.3.0" } -windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Ioctl", "Win32_System_IO", "Win32_System_Registry"] } wiremock = { version = "0.6.4" } xz2 = { version = "0.1.7" } zeroize = { version = "1.8.1" } diff --git a/crates/uv-fs/Cargo.toml b/crates/uv-fs/Cargo.toml index fba4910e6..a9ac2126d 100644 --- a/crates/uv-fs/Cargo.toml +++ b/crates/uv-fs/Cargo.toml @@ -37,7 +37,6 @@ rustix = { workspace = true } backon = { workspace = true } junction = { workspace = true } windows = { workspace = true } -windows-core = { workspace = true } [features] default = [] diff --git a/crates/uv-fs/src/which.rs b/crates/uv-fs/src/which.rs index e63174a17..403f17a3e 100644 --- a/crates/uv-fs/src/which.rs +++ b/crates/uv-fs/src/which.rs @@ -5,7 +5,7 @@ use std::path::Path; fn get_binary_type(path: &Path) -> windows::core::Result { use std::os::windows::ffi::OsStrExt; use windows::Win32::Storage::FileSystem::GetBinaryTypeW; - use windows_core::PCWSTR; + use windows::core::PCWSTR; // References: // https://github.com/denoland/deno/blob/01a6379505712be34ebf2cdc874fa7f54a6e9408/runtime/permissions/which.rs#L131-L154 diff --git a/crates/uv-keyring/Cargo.toml b/crates/uv-keyring/Cargo.toml index 27d333891..90b5ef35d 100644 --- a/crates/uv-keyring/Cargo.toml +++ b/crates/uv-keyring/Cargo.toml @@ -18,7 +18,7 @@ apple-native = ["dep:security-framework"] ## Use the secret-service on *nix. secret-service = ["dep:secret-service"] ## Use the built-in credential store on Windows -windows-native = ["dep:windows-sys", "dep:byteorder"] +windows-native = ["dep:windows", "dep:byteorder"] [dependencies] async-trait = { workspace = true } @@ -33,7 +33,7 @@ secret-service = { workspace = true, features = ["rt-tokio-crypto-rust"], option [target.'cfg(target_os = "windows")'.dependencies] byteorder = { workspace = true, optional = true } -windows-sys = { workspace = true, features = ["Win32_Foundation", "Win32_Security_Credentials"], optional = true } +windows = { workspace = true, features = ["Win32_Foundation", "Win32_Security_Credentials"], optional = true } zeroize = { workspace = true } [dev-dependencies] diff --git a/crates/uv-keyring/src/windows.rs b/crates/uv-keyring/src/windows.rs index eb644f650..30c8d918a 100644 --- a/crates/uv-keyring/src/windows.rs +++ b/crates/uv-keyring/src/windows.rs @@ -44,15 +44,16 @@ use byteorder::{ByteOrder, LittleEndian}; use std::collections::HashMap; use std::iter::once; use std::str; -use windows_sys::Win32::Foundation::{ +use windows::Win32::Foundation::{ ERROR_BAD_USERNAME, ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER, ERROR_NO_SUCH_LOGON_SESSION, - ERROR_NOT_FOUND, FILETIME, GetLastError, + ERROR_NOT_FOUND, FILETIME, WIN32_ERROR, }; -use windows_sys::Win32::Security::Credentials::{ +use windows::Win32::Security::Credentials::{ CRED_FLAGS, CRED_MAX_CREDENTIAL_BLOB_SIZE, CRED_MAX_GENERIC_TARGET_NAME_LENGTH, CRED_MAX_STRING_LENGTH, CRED_MAX_USERNAME_LENGTH, CRED_PERSIST_ENTERPRISE, CRED_TYPE_GENERIC, CREDENTIAL_ATTRIBUTEW, CREDENTIALW, CredDeleteW, CredFree, CredReadW, CredWriteW, }; +use windows::core::PWSTR; use zeroize::Zeroize; /// The representation of a Windows Generic credential. @@ -160,15 +161,13 @@ impl CredentialApi for WinCredential { /// credential in the store. async fn delete_credential(&self) -> Result<()> { self.validate_attributes(None, None)?; - let target_name = to_wstr(&self.target_name); + let mut target_name = to_wstr(&self.target_name); let cred_type = CRED_TYPE_GENERIC; crate::blocking::spawn_blocking(move || { // SAFETY: Calling Windows API - if unsafe { CredDeleteW(target_name.as_ptr(), cred_type, 0) } != 0 { - Ok(()) - } else { - // SAFETY: Calling Windows API - Err(Error::from_win32_code(unsafe { GetLastError() }).into()) + unsafe { + CredDeleteW(PWSTR(target_name.as_mut_ptr()), cred_type, None) + .map_err(|err| Error(err).into()) } }) .await @@ -264,22 +263,20 @@ impl WinCredential { let credential = CREDENTIALW { Flags: flags, Type: cred_type, - TargetName: target_name.as_mut_ptr(), - Comment: comment.as_mut_ptr(), + TargetName: PWSTR(target_name.as_mut_ptr()), + Comment: PWSTR(comment.as_mut_ptr()), LastWritten: last_written, CredentialBlobSize: blob_len, CredentialBlob: blob.as_mut_ptr(), Persist: persist, AttributeCount: attribute_count, Attributes: attributes, - TargetAlias: target_alias.as_mut_ptr(), - UserName: username.as_mut_ptr(), + TargetAlias: PWSTR(target_alias.as_mut_ptr()), + UserName: PWSTR(username.as_mut_ptr()), }; // SAFETY: Calling Windows API - let result = match unsafe { CredWriteW(&raw const credential, 0) } { - 0 => Err(Error::from_win32_code(unsafe { GetLastError() }).into()), - _ => Ok(()), - }; + let result = + unsafe { CredWriteW(&raw const credential, 0) }.map_err(|err| Error(err).into()); // erase the copy of the secret blob.zeroize(); result @@ -300,31 +297,33 @@ impl WinCredential { T: Send + 'static, { self.validate_attributes(None, None)?; - let target_name = to_wstr(&self.target_name); + let mut target_name = to_wstr(&self.target_name); crate::blocking::spawn_blocking(move || { let mut p_credential = std::ptr::null_mut(); // at this point, p_credential is just a pointer to nowhere. // The allocation happens in the `CredReadW` call below. let cred_type = CRED_TYPE_GENERIC; // SAFETY: Calling windows API - let result = - unsafe { CredReadW(target_name.as_ptr(), cred_type, 0, &raw mut p_credential) }; - if result == 0 { - // `CredReadW` failed, so no allocation has been done, so no free needs to be done - Err(Error::from_win32_code(unsafe { GetLastError() }).into()) - } else { - // SAFETY: `CredReadW` succeeded, so p_credential points at an allocated credential. Apply - // the passed extractor function to it. - let ref_cred: &mut CREDENTIALW = unsafe { &mut *p_credential }; - let result = f(ref_cred); - // Finally, we erase the secret and free the allocated credential. - erase_secret(ref_cred); - let p_credential = p_credential; - // SAFETY: `CredReadW` succeeded, so p_credential points at an allocated credential. - // Free the allocation. - unsafe { CredFree(p_credential.cast()) } - result + unsafe { + CredReadW( + PWSTR(target_name.as_mut_ptr()), + cred_type, + None, + &raw mut p_credential, + ) } + .map_err(Error)?; + // SAFETY: `CredReadW` succeeded, so p_credential points at an allocated credential. Apply + // the passed extractor function to it. + let ref_cred: &mut CREDENTIALW = unsafe { &mut *p_credential }; + let result = f(ref_cred); + // Finally, we erase the secret and free the allocated credential. + erase_secret(ref_cred); + let p_credential = p_credential; + // SAFETY: `CredReadW` succeeded, so p_credential points at an allocated credential. + // Free the allocation. + unsafe { CredFree(p_credential.cast()) } + result }) .await } @@ -332,10 +331,10 @@ impl WinCredential { #[allow(clippy::unnecessary_wraps)] fn extract_credential(w_credential: &CREDENTIALW) -> Result { Ok(Self { - username: unsafe { from_wstr(w_credential.UserName) }, - target_name: unsafe { from_wstr(w_credential.TargetName) }, - target_alias: unsafe { from_wstr(w_credential.TargetAlias) }, - comment: unsafe { from_wstr(w_credential.Comment) }, + username: unsafe { from_wstr(w_credential.UserName.as_ptr()) }, + target_name: unsafe { from_wstr(w_credential.TargetName.as_ptr()) }, + target_alias: unsafe { from_wstr(w_credential.TargetAlias.as_ptr()) }, + comment: unsafe { from_wstr(w_credential.Comment.as_ptr()) }, }) } @@ -475,34 +474,40 @@ unsafe fn from_wstr(ws: *const u16) -> String { /// Windows error codes are `DWORDS` which are 32-bit unsigned ints. #[derive(Debug)] -pub struct Error(pub u32); +pub struct Error(windows::core::Error); -impl Error { - /// Create a Windows error from a Win32 error code. - pub fn from_win32_code(code: u32) -> Self { - Self(code) +impl From for Error { + fn from(error: WIN32_ERROR) -> Self { + Self(windows::core::Error::from(error)) } } impl From for ErrorCode { fn from(err: Error) -> Self { - match err.0 { - ERROR_NOT_FOUND => Self::NoEntry, - ERROR_NO_SUCH_LOGON_SESSION => Self::NoStorageAccess(Box::new(err)), - _ => Self::PlatformFailure(Box::new(err)), + if err.0 == ERROR_NOT_FOUND.into() { + Self::NoEntry + } else if err.0 == ERROR_NO_SUCH_LOGON_SESSION.into() { + Self::NoStorageAccess(Box::new(err)) + } else { + Self::PlatformFailure(Box::new(err)) } } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self.0 { - ERROR_NO_SUCH_LOGON_SESSION => write!(f, "Windows ERROR_NO_SUCH_LOGON_SESSION"), - ERROR_NOT_FOUND => write!(f, "Windows ERROR_NOT_FOUND"), - ERROR_BAD_USERNAME => write!(f, "Windows ERROR_BAD_USERNAME"), - ERROR_INVALID_FLAGS => write!(f, "Windows ERROR_INVALID_FLAGS"), - ERROR_INVALID_PARAMETER => write!(f, "Windows ERROR_INVALID_PARAMETER"), - err => write!(f, "Windows error code {err}"), + if self.0 == ERROR_NO_SUCH_LOGON_SESSION.into() { + write!(f, "Windows ERROR_NO_SUCH_LOGON_SESSION") + } else if self.0 == ERROR_NOT_FOUND.into() { + write!(f, "Windows ERROR_NOT_FOUND") + } else if self.0 == ERROR_BAD_USERNAME.into() { + write!(f, "Windows ERROR_BAD_USERNAME") + } else if self.0 == ERROR_INVALID_FLAGS.into() { + write!(f, "Windows ERROR_INVALID_FLAGS") + } else if self.0 == ERROR_INVALID_PARAMETER.into() { + write!(f, "Windows ERROR_INVALID_PARAMETER") + } else { + write!(f, "Windows error code {}", self.0) } } } @@ -545,18 +550,18 @@ mod tests { let attribute_count = 0; let attributes: *mut CREDENTIAL_ATTRIBUTEW = std::ptr::null_mut(); CREDENTIALW { - Flags: 0, + Flags: CRED_FLAGS(0), Type: CRED_TYPE_GENERIC, - TargetName: std::ptr::null_mut(), - Comment: std::ptr::null_mut(), + TargetName: PWSTR::null(), + Comment: PWSTR::null(), LastWritten: last_written, CredentialBlobSize: password.len() as u32, CredentialBlob: password.as_mut_ptr(), Persist: CRED_PERSIST_ENTERPRISE, AttributeCount: attribute_count, Attributes: attributes, - TargetAlias: std::ptr::null_mut(), - UserName: std::ptr::null_mut(), + TargetAlias: PWSTR::null(), + UserName: PWSTR::null(), } } // the first malformed sequence can't be UTF-16 because it has an odd number of bytes. diff --git a/crates/uv-python/Cargo.toml b/crates/uv-python/Cargo.toml index 4e18d5337..7e48421b8 100644 --- a/crates/uv-python/Cargo.toml +++ b/crates/uv-python/Cargo.toml @@ -70,8 +70,7 @@ once_cell = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies] windows-registry = { workspace = true } -windows-result = { workspace = true } -windows-sys = { workspace = true } +windows = { workspace = true } [dev-dependencies] anyhow = { workspace = true } diff --git a/crates/uv-python/src/discovery.rs b/crates/uv-python/src/discovery.rs index 217606ae1..218631c75 100644 --- a/crates/uv-python/src/discovery.rs +++ b/crates/uv-python/src/discovery.rs @@ -8,9 +8,6 @@ use std::{env, io, iter}; use std::{path::Path, path::PathBuf, str::FromStr}; use thiserror::Error; use tracing::{debug, instrument, trace}; -use uv_preview::Preview; -use which::{which, which_all}; - use uv_cache::Cache; use uv_fs::Simplified; use uv_fs::which::is_executable; @@ -18,8 +15,10 @@ use uv_pep440::{ LowerBound, Prerelease, UpperBound, Version, VersionSpecifier, VersionSpecifiers, release_specifiers_to_ranges, }; +use uv_preview::Preview; use uv_static::EnvVars; use uv_warnings::warn_user_once; +use which::{which, which_all}; use crate::downloads::{PlatformRequest, PythonDownloadRequest}; use crate::implementation::ImplementationName; @@ -251,7 +250,7 @@ pub enum Error { #[cfg(windows)] #[error("Failed to query installed Python versions from the Windows registry")] - RegistryError(#[from] windows_result::Error), + RegistryError(#[from] windows::core::Error), /// An invalid version request was given #[error("Invalid version request: {0}")] @@ -1502,13 +1501,15 @@ fn warn_on_unsupported_python(interpreter: &Interpreter) { pub(crate) fn is_windows_store_shim(path: &Path) -> bool { use std::os::windows::fs::MetadataExt; use std::os::windows::prelude::OsStrExt; - use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE}; - use windows_sys::Win32::Storage::FileSystem::{ + use windows::Win32::Foundation::CloseHandle; + use windows::Win32::Storage::FileSystem::{ CreateFileW, FILE_ATTRIBUTE_REPARSE_POINT, FILE_FLAG_BACKUP_SEMANTICS, - FILE_FLAG_OPEN_REPARSE_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_MODE, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + OPEN_EXISTING, }; - use windows_sys::Win32::System::IO::DeviceIoControl; - use windows_sys::Win32::System::Ioctl::FSCTL_GET_REPARSE_POINT; + use windows::Win32::System::IO::DeviceIoControl; + use windows::Win32::System::Ioctl::FSCTL_GET_REPARSE_POINT; + use windows::core::PCWSTR; // The path must be absolute. if !path.is_absolute() { @@ -1553,7 +1554,7 @@ pub(crate) fn is_windows_store_shim(path: &Path) -> bool { let Ok(md) = fs_err::symlink_metadata(path) else { return false; }; - if md.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT == 0 { + if md.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT.0 == 0 { return false; } @@ -1567,19 +1568,19 @@ pub(crate) fn is_windows_store_shim(path: &Path) -> bool { #[allow(unsafe_code)] let reparse_handle = unsafe { CreateFileW( - path_encoded.as_mut_ptr(), + PCWSTR(path_encoded.as_mut_ptr()), 0, - 0, - std::ptr::null_mut(), + FILE_SHARE_MODE(0), + None, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - std::ptr::null_mut(), + None, ) }; - if reparse_handle == INVALID_HANDLE_VALUE { + let Ok(reparse_handle) = reparse_handle else { return false; - } + }; let mut buf = [0u16; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]; let mut bytes_returned = 0; @@ -1590,19 +1591,20 @@ pub(crate) fn is_windows_store_shim(path: &Path) -> bool { DeviceIoControl( reparse_handle, FSCTL_GET_REPARSE_POINT, - std::ptr::null_mut(), + None, 0, - buf.as_mut_ptr().cast(), + Some(buf.as_mut_ptr().cast()), buf.len() as u32 * 2, - &raw mut bytes_returned, - std::ptr::null_mut(), - ) != 0 + Some(&raw mut bytes_returned), + None, + ) + .is_ok() }; // SAFETY: The handle is valid. #[allow(unsafe_code)] unsafe { - CloseHandle(reparse_handle); + let _ = CloseHandle(reparse_handle); } // If the operation failed, assume it's not a reparse point. diff --git a/crates/uv-python/src/interpreter.rs b/crates/uv-python/src/interpreter.rs index 8469f05f1..310bf682a 100644 --- a/crates/uv-python/src/interpreter.rs +++ b/crates/uv-python/src/interpreter.rs @@ -34,7 +34,7 @@ use crate::{ }; #[cfg(windows)] -use windows_sys::Win32::Foundation::{APPMODEL_ERROR_NO_PACKAGE, ERROR_CANT_ACCESS_FILE}; +use windows::Win32::Foundation::{APPMODEL_ERROR_NO_PACKAGE, ERROR_CANT_ACCESS_FILE, WIN32_ERROR}; /// A Python executable and its associated platform markers. #[derive(Debug, Clone)] @@ -928,8 +928,10 @@ impl InterpreterInfo { _ => {} } #[cfg(windows)] - if let Some(APPMODEL_ERROR_NO_PACKAGE | ERROR_CANT_ACCESS_FILE) = - err.raw_os_error().and_then(|code| u32::try_from(code).ok()) + if let Some(APPMODEL_ERROR_NO_PACKAGE | ERROR_CANT_ACCESS_FILE) = err + .raw_os_error() + .and_then(|code| u32::try_from(code).ok()) + .map(WIN32_ERROR) { // These error codes are returned if the Python interpreter is a corrupt MSIX // package, which we want to differentiate from a typical spawn failure. diff --git a/crates/uv-python/src/managed.rs b/crates/uv-python/src/managed.rs index 6ccba8f45..23dba54fe 100644 --- a/crates/uv-python/src/managed.rs +++ b/crates/uv-python/src/managed.rs @@ -15,7 +15,7 @@ use thiserror::Error; use tracing::{debug, warn}; use uv_preview::{Preview, PreviewFeatures}; #[cfg(windows)] -use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT; +use windows::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT; use uv_fs::{LockedFile, Simplified, replace_symlink, symlink_or_copy_file}; use uv_platform::{Error as PlatformError, Os}; @@ -857,7 +857,7 @@ impl PythonMinorVersionLink { .is_ok_and(|metadata| { // Check that this is a reparse point, which indicates this // is a symlink or junction. - (metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT) != 0 + (metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT.0) != 0 }) } } diff --git a/crates/uv-python/src/windows_registry.rs b/crates/uv-python/src/windows_registry.rs index cd6393aec..359555153 100644 --- a/crates/uv-python/src/windows_registry.rs +++ b/crates/uv-python/src/windows_registry.rs @@ -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, windows_result::Error> { +pub(crate) fn registry_pythons() -> Result, 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, 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. diff --git a/crates/uv-shell/Cargo.toml b/crates/uv-shell/Cargo.toml index f70fffa00..bba5976b9 100644 --- a/crates/uv-shell/Cargo.toml +++ b/crates/uv-shell/Cargo.toml @@ -24,9 +24,8 @@ tracing = { workspace = true } nix = { workspace = true } [target.'cfg(windows)'.dependencies] +windows = { workspace = true } windows-registry = { workspace = true } -windows-result = { workspace = true } -windows-sys = { workspace = true } [dev-dependencies] fs-err = { workspace = true } diff --git a/crates/uv-shell/src/windows.rs b/crates/uv-shell/src/windows.rs index 00c46eb79..818d5b999 100644 --- a/crates/uv-shell/src/windows.rs +++ b/crates/uv-shell/src/windows.rs @@ -8,9 +8,9 @@ use std::path::Path; use anyhow::Context; use tracing::warn; +use windows::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA}; +use windows::core::HRESULT; use windows_registry::{CURRENT_USER, HSTRING}; -use windows_result::HRESULT; -use windows_sys::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA}; use uv_static::EnvVars; @@ -60,13 +60,11 @@ fn get_windows_path_var() -> anyhow::Result> { let reg_value = environment.get_hstring(EnvVars::PATH); match reg_value { Ok(reg_value) => Ok(Some(reg_value)), - Err(err) if err.code() == HRESULT::from_win32(ERROR_INVALID_DATA) => { + Err(err) if err.code() == HRESULT::from(ERROR_INVALID_DATA) => { warn!("`HKEY_CURRENT_USER\\Environment\\PATH` is a non-string"); Ok(None) } - Err(err) if err.code() == HRESULT::from_win32(ERROR_FILE_NOT_FOUND) => { - Ok(Some(HSTRING::new())) - } + Err(err) if err.code() == HRESULT::from(ERROR_FILE_NOT_FOUND) => Ok(Some(HSTRING::new())), Err(err) => Err(err.into()), } } diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index 0a83fa176..e0b145d22 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -119,7 +119,6 @@ zip = { workspace = true } arrayvec = { workspace = true } self-replace = { workspace = true } windows = { workspace = true } -windows-result = { workspace = true } [dev-dependencies] assert_cmd = { workspace = true } diff --git a/crates/uv/src/windows_exception.rs b/crates/uv/src/windows_exception.rs index 048eaa1ba..8784793c1 100644 --- a/crates/uv/src/windows_exception.rs +++ b/crates/uv/src/windows_exception.rs @@ -54,11 +54,11 @@ enum ExceptionSafeStderr { } impl ExceptionSafeStderr { - fn new() -> Result { + fn new() -> Result { // SAFETY: winapi call, no interesting parameters let handle = unsafe { GetStdHandle(STD_ERROR_HANDLE) }?; if handle.is_invalid() { - return Err(windows_result::Error::empty()); + return Err(windows::core::Error::empty()); } let mut mode = CONSOLE_MODE::default(); // SAFETY: winapi calls, no interesting parameters @@ -73,7 +73,7 @@ impl ExceptionSafeStderr { } } - fn write_winerror(&mut self, s: &str) -> Result<(), windows_result::Error> { + fn write_winerror(&mut self, s: &str) -> Result<(), windows::core::Error> { match self { Self::WriteConsole(handle) => { // According to comments in the ReactOS source, NT's behavior is that writes of 80