mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-13 00:05:01 +00:00

## Summary In preview mode on windows, register und un-register the managed python build standalone installations in the Windows registry following PEP 514. We write the values defined in the PEP plus the download URL and hash. We add an entry when installing a version, remove an entry when uninstalling and removing all values when uninstalling with `--all`. We update entries only by overwriting existing values, there is no "syncing" involved. Since they are not official builds, pbs gets a prefix. `py -V:Astral/CPython3.13.1` works, `py -3.13` doesn't. ``` $ py --list-paths -V:3.12 * C:\Users\Konsti\AppData\Local\Programs\Python\Python312\python.exe -V:3.11.9 C:\Users\Konsti\.pyenv\pyenv-win\versions\3.11.9\python.exe -V:3.11 C:\Users\micro\AppData\Local\Programs\Python\Python311\python.exe -V:3.8 C:\Users\micro\AppData\Local\Programs\Python\Python38\python.exe -V:Astral/CPython3.13.1 C:\Users\Konsti\AppData\Roaming\uv\data\python\cpython-3.13.1-windows-x86_64-none\python.exe ``` Registry errors are reported but not fatal, except for operations on the company key since it's not bound to any specific python interpreter. On uninstallation, we prune registry entries that have no matching Python installation (i.e. broken entries). The code uses the official `windows_registry` crate of the `winreg` crate. Best reviewed commit-by-commit. ## Test Plan We're reusing an existing system check to test different (un)installation scenarios.
63 lines
2 KiB
Rust
63 lines
2 KiB
Rust
use std::{io::ErrorKind, path::PathBuf};
|
|
|
|
use uv_fs::Simplified as _;
|
|
use uv_warnings::warn_user;
|
|
|
|
use crate::managed::ManagedPythonInstallation;
|
|
|
|
pub fn patch_dylib_install_name(dylib: PathBuf) -> Result<(), Error> {
|
|
let output = match std::process::Command::new("install_name_tool")
|
|
.arg("-id")
|
|
.arg(&dylib)
|
|
.arg(&dylib)
|
|
.output()
|
|
{
|
|
Ok(output) => output,
|
|
Err(e) => {
|
|
let e = if e.kind() == ErrorKind::NotFound {
|
|
Error::MissingInstallNameTool
|
|
} else {
|
|
e.into()
|
|
};
|
|
return Err(e);
|
|
}
|
|
};
|
|
|
|
if !output.status.success() {
|
|
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
|
|
return Err(Error::RenameError { dylib, stderr });
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum Error {
|
|
#[error(transparent)]
|
|
Io(#[from] std::io::Error),
|
|
#[error("`install_name_tool` is not available on this system.
|
|
This utility is part of macOS Developer Tools. Please ensure that the Xcode Command Line Tools are installed by running:
|
|
|
|
xcode-select --install
|
|
|
|
For more information, see: https://developer.apple.com/xcode/")]
|
|
MissingInstallNameTool,
|
|
#[error("Failed to update the install name of the Python dynamic library located at `{}`", dylib.user_display())]
|
|
RenameError { dylib: PathBuf, stderr: String },
|
|
}
|
|
|
|
impl Error {
|
|
/// Emit a user-friendly warning about the patching failure.
|
|
pub fn warn_user(&self, installation: &ManagedPythonInstallation) {
|
|
let error = if tracing::enabled!(tracing::Level::DEBUG) {
|
|
format!("\nUnderlying error: {self}")
|
|
} else {
|
|
String::new()
|
|
};
|
|
warn_user!(
|
|
"Failed to patch the install name of the dynamic library for {}. This may cause issues when building Python native extensions.{}",
|
|
installation.executable(false).simplified_display(),
|
|
error
|
|
);
|
|
}
|
|
}
|