Split platform detection code into a dedicated uv-platform crate (#14918)
Some checks are pending
CI / check system | alpine (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux aarch64 (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / build binary | msrv (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / smoke test | linux aarch64 (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | aarch64 windows implicit (push) Blocked by required conditions
CI / integration test | aarch64 windows explicit (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | registries (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions

In service of some subsequent work...
This commit is contained in:
Zanie Blue 2025-07-28 14:12:04 -05:00 committed by GitHub
parent 5686771464
commit 00efde06b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 530 additions and 469 deletions

21
Cargo.lock generated
View file

@ -4732,6 +4732,7 @@ dependencies = [
"uv-pep440", "uv-pep440",
"uv-pep508", "uv-pep508",
"uv-performance-memory-allocator", "uv-performance-memory-allocator",
"uv-platform",
"uv-platform-tags", "uv-platform-tags",
"uv-publish", "uv-publish",
"uv-pypi-types", "uv-pypi-types",
@ -5553,6 +5554,23 @@ dependencies = [
"tikv-jemallocator", "tikv-jemallocator",
] ]
[[package]]
name = "uv-platform"
version = "0.0.1"
dependencies = [
"fs-err",
"goblin",
"indoc",
"procfs",
"regex",
"target-lexicon",
"thiserror 2.0.12",
"tracing",
"uv-fs",
"uv-platform-tags",
"uv-static",
]
[[package]] [[package]]
name = "uv-platform-tags" name = "uv-platform-tags"
version = "0.0.1" version = "0.0.1"
@ -5646,14 +5664,12 @@ dependencies = [
"dunce", "dunce",
"fs-err", "fs-err",
"futures", "futures",
"goblin",
"indexmap", "indexmap",
"indoc", "indoc",
"insta", "insta",
"itertools 0.14.0", "itertools 0.14.0",
"once_cell", "once_cell",
"owo-colors", "owo-colors",
"procfs",
"ref-cast", "ref-cast",
"regex", "regex",
"reqwest", "reqwest",
@ -5687,6 +5703,7 @@ dependencies = [
"uv-install-wheel", "uv-install-wheel",
"uv-pep440", "uv-pep440",
"uv-pep508", "uv-pep508",
"uv-platform",
"uv-platform-tags", "uv-platform-tags",
"uv-pypi-types", "uv-pypi-types",
"uv-redacted", "uv-redacted",

View file

@ -49,6 +49,7 @@ uv-once-map = { path = "crates/uv-once-map" }
uv-options-metadata = { path = "crates/uv-options-metadata" } uv-options-metadata = { path = "crates/uv-options-metadata" }
uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] } uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] } uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
uv-platform = { path = "crates/uv-platform" }
uv-platform-tags = { path = "crates/uv-platform-tags" } uv-platform-tags = { path = "crates/uv-platform-tags" }
uv-publish = { path = "crates/uv-publish" } uv-publish = { path = "crates/uv-publish" }
uv-pypi-types = { path = "crates/uv-pypi-types" } uv-pypi-types = { path = "crates/uv-pypi-types" }

View file

@ -0,0 +1,34 @@
[package]
name = "uv-platform"
version = "0.0.1"
edition = { workspace = true }
rust-version = { workspace = true }
homepage = { workspace = true }
documentation = { workspace = true }
repository = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
[lib]
doctest = false
[lints]
workspace = true
[dependencies]
uv-static = { workspace = true }
uv-fs = { workspace = true }
uv-platform-tags = { workspace = true }
fs-err = { workspace = true }
goblin = { workspace = true }
regex = { workspace = true }
target-lexicon = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
procfs = { workspace = true }
[dev-dependencies]
indoc = { workspace = true }

View file

@ -0,0 +1,249 @@
use crate::Error;
use std::fmt::Display;
use std::str::FromStr;
use std::{cmp, fmt};
/// Architecture variants, e.g., with support for different instruction sets
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum ArchVariant {
/// Targets 64-bit Intel/AMD CPUs newer than Nehalem (2008).
/// Includes SSE3, SSE4 and other post-2003 CPU instructions.
V2,
/// Targets 64-bit Intel/AMD CPUs newer than Haswell (2013) and Excavator (2015).
/// Includes AVX, AVX2, MOVBE and other newer CPU instructions.
V3,
/// Targets 64-bit Intel/AMD CPUs with AVX-512 instructions (post-2017 Intel CPUs).
/// Many post-2017 Intel CPUs do not support AVX-512.
V4,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct Arch {
pub(crate) family: target_lexicon::Architecture,
pub(crate) variant: Option<ArchVariant>,
}
impl Ord for Arch {
fn cmp(&self, other: &Self) -> cmp::Ordering {
if self.family == other.family {
return self.variant.cmp(&other.variant);
}
// For the time being, manually make aarch64 windows disfavored
// on its own host platform, because most packages don't have wheels for
// aarch64 windows, making emulation more useful than native execution!
//
// The reason we do this in "sorting" and not "supports" is so that we don't
// *refuse* to use an aarch64 windows pythons if they happen to be installed
// and nothing else is available.
//
// Similarly if someone manually requests an aarch64 windows install, we
// should respect that request (this is the way users should "override"
// this behaviour).
let preferred = if cfg!(all(windows, target_arch = "aarch64")) {
Arch {
family: target_lexicon::Architecture::X86_64,
variant: None,
}
} else {
// Prefer native architectures
Arch::from_env()
};
match (
self.family == preferred.family,
other.family == preferred.family,
) {
(true, true) => unreachable!(),
(true, false) => cmp::Ordering::Less,
(false, true) => cmp::Ordering::Greater,
(false, false) => {
// Both non-preferred, fallback to lexicographic order
self.family.to_string().cmp(&other.family.to_string())
}
}
}
}
impl PartialOrd for Arch {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Arch {
pub fn new(family: target_lexicon::Architecture, variant: Option<ArchVariant>) -> Self {
Self { family, variant }
}
pub fn from_env() -> Self {
Self {
family: target_lexicon::HOST.architecture,
variant: None,
}
}
/// Does the current architecture support running the other?
///
/// When the architecture is equal, this is always true. Otherwise, this is true if the
/// architecture is transparently emulated or is a microarchitecture with worse performance
/// characteristics.
pub fn supports(self, other: Self) -> bool {
if self == other {
return true;
}
// TODO: Implement `variant` support checks
// Windows ARM64 runs emulated x86_64 binaries transparently
// Similarly, macOS aarch64 runs emulated x86_64 binaries transparently if you have Rosetta
// installed. We don't try to be clever and check if that's the case here, we just assume
// that if x86_64 distributions are available, they're usable.
if (cfg!(windows) || cfg!(target_os = "macos"))
&& matches!(self.family, target_lexicon::Architecture::Aarch64(_))
{
return other.family == target_lexicon::Architecture::X86_64;
}
false
}
pub fn family(&self) -> target_lexicon::Architecture {
self.family
}
pub fn is_arm(&self) -> bool {
matches!(self.family, target_lexicon::Architecture::Arm(_))
}
}
impl Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.family {
target_lexicon::Architecture::X86_32(target_lexicon::X86_32Architecture::I686) => {
write!(f, "x86")?;
}
inner => write!(f, "{inner}")?,
}
if let Some(variant) = self.variant {
write!(f, "_{variant}")?;
}
Ok(())
}
}
impl FromStr for Arch {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
fn parse_family(s: &str) -> Result<target_lexicon::Architecture, Error> {
let inner = match s {
// Allow users to specify "x86" as a shorthand for the "i686" variant, they should not need
// to specify the exact architecture and this variant is what we have downloads for.
"x86" => {
target_lexicon::Architecture::X86_32(target_lexicon::X86_32Architecture::I686)
}
_ => target_lexicon::Architecture::from_str(s)
.map_err(|()| Error::UnknownArch(s.to_string()))?,
};
if matches!(inner, target_lexicon::Architecture::Unknown) {
return Err(Error::UnknownArch(s.to_string()));
}
Ok(inner)
}
// First check for a variant
if let Some((Ok(family), Ok(variant))) = s
.rsplit_once('_')
.map(|(family, variant)| (parse_family(family), ArchVariant::from_str(variant)))
{
// We only support variants for `x86_64` right now
if !matches!(family, target_lexicon::Architecture::X86_64) {
return Err(Error::UnsupportedVariant(
variant.to_string(),
family.to_string(),
));
}
return Ok(Self {
family,
variant: Some(variant),
});
}
let family = parse_family(s)?;
Ok(Self {
family,
variant: None,
})
}
}
impl FromStr for ArchVariant {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"v2" => Ok(Self::V2),
"v3" => Ok(Self::V3),
"v4" => Ok(Self::V4),
_ => Err(()),
}
}
}
impl Display for ArchVariant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::V2 => write!(f, "v2"),
Self::V3 => write!(f, "v3"),
Self::V4 => write!(f, "v4"),
}
}
}
impl From<&uv_platform_tags::Arch> for Arch {
fn from(value: &uv_platform_tags::Arch) -> Self {
match value {
uv_platform_tags::Arch::Aarch64 => Arch::new(
target_lexicon::Architecture::Aarch64(target_lexicon::Aarch64Architecture::Aarch64),
None,
),
uv_platform_tags::Arch::Armv5TEL => Arch::new(
target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv5te),
None,
),
uv_platform_tags::Arch::Armv6L => Arch::new(
target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv6),
None,
),
uv_platform_tags::Arch::Armv7L => Arch::new(
target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv7),
None,
),
uv_platform_tags::Arch::S390X => Arch::new(target_lexicon::Architecture::S390x, None),
uv_platform_tags::Arch::Powerpc => {
Arch::new(target_lexicon::Architecture::Powerpc, None)
}
uv_platform_tags::Arch::Powerpc64 => {
Arch::new(target_lexicon::Architecture::Powerpc64, None)
}
uv_platform_tags::Arch::Powerpc64Le => {
Arch::new(target_lexicon::Architecture::Powerpc64le, None)
}
uv_platform_tags::Arch::X86 => Arch::new(
target_lexicon::Architecture::X86_32(target_lexicon::X86_32Architecture::I686),
None,
),
uv_platform_tags::Arch::X86_64 => Arch::new(target_lexicon::Architecture::X86_64, None),
uv_platform_tags::Arch::LoongArch64 => {
Arch::new(target_lexicon::Architecture::LoongArch64, None)
}
uv_platform_tags::Arch::Riscv64 => Arch::new(
target_lexicon::Architecture::Riscv64(target_lexicon::Riscv64Architecture::Riscv64),
None,
),
uv_platform_tags::Arch::Wasm32 => Arch::new(target_lexicon::Architecture::Wasm32, None),
}
}
}

View file

@ -1,6 +1,6 @@
//! Fetches CPU information. //! Fetches CPU information.
use anyhow::Error; use std::io::Error;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use procfs::{CpuInfo, Current}; use procfs::{CpuInfo, Current};
@ -14,7 +14,7 @@ use procfs::{CpuInfo, Current};
/// More information on this can be found in the [Debian ARM Hard Float Port documentation](https://wiki.debian.org/ArmHardFloatPort#VFP). /// More information on this can be found in the [Debian ARM Hard Float Port documentation](https://wiki.debian.org/ArmHardFloatPort#VFP).
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub(crate) fn detect_hardware_floating_point_support() -> Result<bool, Error> { pub(crate) fn detect_hardware_floating_point_support() -> Result<bool, Error> {
let cpu_info = CpuInfo::current()?; let cpu_info = CpuInfo::current().map_err(Error::other)?;
if let Some(features) = cpu_info.fields.get("Features") { if let Some(features) = cpu_info.fields.get("Features") {
if features.contains("vfp") { if features.contains("vfp") {
return Ok(true); // "vfp" found: hard-float (gnueabihf) detected return Ok(true); // "vfp" found: hard-float (gnueabihf) detected

View file

@ -0,0 +1,26 @@
//! Platform detection for operating system, architecture, and libc.
use thiserror::Error;
pub use crate::arch::{Arch, ArchVariant};
pub use crate::libc::{Libc, LibcDetectionError, LibcVersion};
pub use crate::os::Os;
mod arch;
mod cpuinfo;
mod libc;
mod os;
#[derive(Error, Debug)]
pub enum Error {
#[error("Unknown operating system: {0}")]
UnknownOs(String),
#[error("Unknown architecture: {0}")]
UnknownArch(String),
#[error("Unknown libc environment: {0}")]
UnknownLibc(String),
#[error("Unsupported variant `{0}` for architecture `{1}`")]
UnsupportedVariant(String, String),
#[error(transparent)]
LibcDetectionError(#[from] crate::libc::LibcDetectionError),
}

View file

@ -3,18 +3,22 @@
//! Taken from `glibc_version` (<https://github.com/delta-incubator/glibc-version-rs>), //! Taken from `glibc_version` (<https://github.com/delta-incubator/glibc-version-rs>),
//! which used the Apache 2.0 license (but not the MIT license) //! which used the Apache 2.0 license (but not the MIT license)
use crate::cpuinfo::detect_hardware_floating_point_support;
use fs_err as fs; use fs_err as fs;
use goblin::elf::Elf; use goblin::elf::Elf;
use regex::Regex; use regex::Regex;
use std::fmt::Display;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::str::FromStr;
use std::sync::LazyLock; use std::sync::LazyLock;
use thiserror::Error; use std::{env, fmt};
use tracing::trace; use tracing::trace;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_static::EnvVars;
#[derive(Debug, Error)] #[derive(Debug, thiserror::Error)]
pub enum LibcDetectionError { pub enum LibcDetectionError {
#[error( #[error(
"Could not detect either glibc version nor musl libc version, at least one of which is required" "Could not detect either glibc version nor musl libc version, at least one of which is required"
@ -45,11 +49,89 @@ pub enum LibcDetectionError {
/// We support glibc (manylinux) and musl (musllinux) on linux. /// We support glibc (manylinux) and musl (musllinux) on linux.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub(crate) enum LibcVersion { pub enum LibcVersion {
Manylinux { major: u32, minor: u32 }, Manylinux { major: u32, minor: u32 },
Musllinux { major: u32, minor: u32 }, Musllinux { major: u32, minor: u32 },
} }
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum Libc {
Some(target_lexicon::Environment),
None,
}
impl Libc {
pub fn from_env() -> Result<Self, crate::Error> {
match env::consts::OS {
"linux" => {
if let Ok(libc) = env::var(EnvVars::UV_LIBC) {
if !libc.is_empty() {
return Self::from_str(&libc);
}
}
Ok(Self::Some(match detect_linux_libc()? {
LibcVersion::Manylinux { .. } => match env::consts::ARCH {
// Checks if the CPU supports hardware floating-point operations.
// Depending on the result, it selects either the `gnueabihf` (hard-float) or `gnueabi` (soft-float) environment.
// download-metadata.json only includes armv7.
"arm" | "armv5te" | "armv7" => {
match detect_hardware_floating_point_support() {
Ok(true) => target_lexicon::Environment::Gnueabihf,
Ok(false) => target_lexicon::Environment::Gnueabi,
Err(_) => target_lexicon::Environment::Gnu,
}
}
_ => target_lexicon::Environment::Gnu,
},
LibcVersion::Musllinux { .. } => target_lexicon::Environment::Musl,
}))
}
"windows" | "macos" => Ok(Self::None),
// Use `None` on platforms without explicit support.
_ => Ok(Self::None),
}
}
pub fn is_musl(&self) -> bool {
matches!(self, Self::Some(target_lexicon::Environment::Musl))
}
}
impl FromStr for Libc {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"gnu" => Ok(Self::Some(target_lexicon::Environment::Gnu)),
"gnueabi" => Ok(Self::Some(target_lexicon::Environment::Gnueabi)),
"gnueabihf" => Ok(Self::Some(target_lexicon::Environment::Gnueabihf)),
"musl" => Ok(Self::Some(target_lexicon::Environment::Musl)),
"none" => Ok(Self::None),
_ => Err(crate::Error::UnknownLibc(s.to_string())),
}
}
}
impl Display for Libc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Some(env) => write!(f, "{env}"),
Self::None => write!(f, "none"),
}
}
}
impl From<&uv_platform_tags::Os> for Libc {
fn from(value: &uv_platform_tags::Os) -> Self {
match value {
uv_platform_tags::Os::Manylinux { .. } => Libc::Some(target_lexicon::Environment::Gnu),
uv_platform_tags::Os::Musllinux { .. } => Libc::Some(target_lexicon::Environment::Musl),
_ => Libc::None,
}
}
}
/// Determine whether we're running glibc or musl and in which version, given we are on linux. /// Determine whether we're running glibc or musl and in which version, given we are on linux.
/// ///
/// Normally, we determine this from the python interpreter, which is more accurate, but when /// Normally, we determine this from the python interpreter, which is more accurate, but when

View file

@ -0,0 +1,88 @@
use crate::Error;
use std::fmt;
use std::fmt::Display;
use std::ops::Deref;
use std::str::FromStr;
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct Os(pub(crate) target_lexicon::OperatingSystem);
impl Os {
pub fn new(os: target_lexicon::OperatingSystem) -> Self {
Self(os)
}
pub fn from_env() -> Self {
Self(target_lexicon::HOST.operating_system)
}
pub fn is_windows(&self) -> bool {
matches!(self.0, target_lexicon::OperatingSystem::Windows)
}
}
impl Display for Os {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &**self {
target_lexicon::OperatingSystem::Darwin(_) => write!(f, "macos"),
inner => write!(f, "{inner}"),
}
}
}
impl FromStr for Os {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let inner = match s {
"macos" => target_lexicon::OperatingSystem::Darwin(None),
_ => target_lexicon::OperatingSystem::from_str(s)
.map_err(|()| Error::UnknownOs(s.to_string()))?,
};
if matches!(inner, target_lexicon::OperatingSystem::Unknown) {
return Err(Error::UnknownOs(s.to_string()));
}
Ok(Self(inner))
}
}
impl Deref for Os {
type Target = target_lexicon::OperatingSystem;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<&uv_platform_tags::Os> for Os {
fn from(value: &uv_platform_tags::Os) -> Self {
match value {
uv_platform_tags::Os::Dragonfly { .. } => {
Os::new(target_lexicon::OperatingSystem::Dragonfly)
}
uv_platform_tags::Os::FreeBsd { .. } => {
Os::new(target_lexicon::OperatingSystem::Freebsd)
}
uv_platform_tags::Os::Haiku { .. } => Os::new(target_lexicon::OperatingSystem::Haiku),
uv_platform_tags::Os::Illumos { .. } => {
Os::new(target_lexicon::OperatingSystem::Illumos)
}
uv_platform_tags::Os::Macos { .. } => {
Os::new(target_lexicon::OperatingSystem::Darwin(None))
}
uv_platform_tags::Os::Manylinux { .. }
| uv_platform_tags::Os::Musllinux { .. }
| uv_platform_tags::Os::Android { .. } => {
Os::new(target_lexicon::OperatingSystem::Linux)
}
uv_platform_tags::Os::NetBsd { .. } => Os::new(target_lexicon::OperatingSystem::Netbsd),
uv_platform_tags::Os::OpenBsd { .. } => {
Os::new(target_lexicon::OperatingSystem::Openbsd)
}
uv_platform_tags::Os::Windows => Os::new(target_lexicon::OperatingSystem::Windows),
uv_platform_tags::Os::Pyodide { .. } => {
Os::new(target_lexicon::OperatingSystem::Emscripten)
}
}
}
}

View file

@ -28,6 +28,7 @@ uv-fs = { workspace = true }
uv-install-wheel = { workspace = true } uv-install-wheel = { workspace = true }
uv-pep440 = { workspace = true } uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true } uv-pep508 = { workspace = true }
uv-platform = { workspace = true }
uv-platform-tags = { workspace = true } uv-platform-tags = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-redacted = { workspace = true } uv-redacted = { workspace = true }
@ -42,7 +43,6 @@ configparser = { workspace = true }
dunce = { workspace = true } dunce = { workspace = true }
fs-err = { workspace = true, features = ["tokio"] } fs-err = { workspace = true, features = ["tokio"] }
futures = { workspace = true } futures = { workspace = true }
goblin = { workspace = true, default-features = false }
indexmap = { workspace = true } indexmap = { workspace = true }
itertools = { workspace = true } itertools = { workspace = true }
owo-colors = { workspace = true } owo-colors = { workspace = true }
@ -68,9 +68,6 @@ url = { workspace = true }
which = { workspace = true } which = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
procfs = { workspace = true }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
windows-registry = { workspace = true } windows-registry = { workspace = true }
windows-result = { workspace = true } windows-result = { workspace = true }

View file

@ -3066,8 +3066,8 @@ mod tests {
discovery::{PythonRequest, VersionRequest}, discovery::{PythonRequest, VersionRequest},
downloads::{ArchRequest, PythonDownloadRequest}, downloads::{ArchRequest, PythonDownloadRequest},
implementation::ImplementationName, implementation::ImplementationName,
platform::{Arch, Libc, Os},
}; };
use uv_platform::{Arch, Libc, Os};
use super::{Error, PythonVariant}; use super::{Error, PythonVariant};
@ -3154,11 +3154,11 @@ mod tests {
PythonVariant::Default PythonVariant::Default
)), )),
implementation: Some(ImplementationName::CPython), implementation: Some(ImplementationName::CPython),
arch: Some(ArchRequest::Explicit(Arch { arch: Some(ArchRequest::Explicit(Arch::new(
family: Architecture::Aarch64(Aarch64Architecture::Aarch64), Architecture::Aarch64(Aarch64Architecture::Aarch64),
variant: None None
})), ))),
os: Some(Os(target_lexicon::OperatingSystem::Darwin(None))), os: Some(Os::new(target_lexicon::OperatingSystem::Darwin(None))),
libc: Some(Libc::None), libc: Some(Libc::None),
prereleases: None prereleases: None
}) })
@ -3189,10 +3189,10 @@ mod tests {
PythonVariant::Default PythonVariant::Default
)), )),
implementation: None, implementation: None,
arch: Some(ArchRequest::Explicit(Arch { arch: Some(ArchRequest::Explicit(Arch::new(
family: Architecture::Aarch64(Aarch64Architecture::Aarch64), Architecture::Aarch64(Aarch64Architecture::Aarch64),
variant: None None
})), ))),
os: None, os: None,
libc: None, libc: None,
prereleases: None prereleases: None

View file

@ -25,6 +25,7 @@ use uv_client::{BaseClient, WrappedReqwestError, is_extended_transient_error};
use uv_distribution_filename::{ExtensionError, SourceDistExtension}; use uv_distribution_filename::{ExtensionError, SourceDistExtension};
use uv_extract::hash::Hasher; use uv_extract::hash::Hasher;
use uv_fs::{Simplified, rename_with_retry}; use uv_fs::{Simplified, rename_with_retry};
use uv_platform::{self as platform, Arch, Libc, Os};
use uv_pypi_types::{HashAlgorithm, HashDigest}; use uv_pypi_types::{HashAlgorithm, HashDigest};
use uv_redacted::DisplaySafeUrl; use uv_redacted::DisplaySafeUrl;
use uv_static::EnvVars; use uv_static::EnvVars;
@ -34,9 +35,7 @@ use crate::implementation::{
Error as ImplementationError, ImplementationName, LenientImplementationName, Error as ImplementationError, ImplementationName, LenientImplementationName,
}; };
use crate::installation::PythonInstallationKey; use crate::installation::PythonInstallationKey;
use crate::libc::LibcDetectionError;
use crate::managed::ManagedPythonInstallation; use crate::managed::ManagedPythonInstallation;
use crate::platform::{self, Arch, Libc, Os};
use crate::{Interpreter, PythonRequest, PythonVersion, VersionRequest}; use crate::{Interpreter, PythonRequest, PythonVersion, VersionRequest};
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -98,7 +97,7 @@ pub enum Error {
#[error("A mirror was provided via `{0}`, but the URL does not match the expected format: {0}")] #[error("A mirror was provided via `{0}`, but the URL does not match the expected format: {0}")]
Mirror(&'static str, &'static str), Mirror(&'static str, &'static str),
#[error("Failed to determine the libc used on the current platform")] #[error("Failed to determine the libc used on the current platform")]
LibcDetection(#[from] LibcDetectionError), LibcDetection(#[from] platform::LibcDetectionError),
#[error("Remote Python downloads JSON is not yet supported, please use a local path")] #[error("Remote Python downloads JSON is not yet supported, please use a local path")]
RemoteJSONNotSupported, RemoteJSONNotSupported,
#[error("The JSON of the python downloads is invalid: {0}")] #[error("The JSON of the python downloads is invalid: {0}")]

View file

@ -10,6 +10,7 @@ use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::Preview; use uv_configuration::Preview;
use uv_pep440::{Prerelease, Version}; use uv_pep440::{Prerelease, Version};
use uv_platform::{Arch, Libc, Os};
use crate::discovery::{ use crate::discovery::{
EnvironmentPreference, PythonRequest, find_best_python_installation, find_python_installation, EnvironmentPreference, PythonRequest, find_best_python_installation, find_python_installation,
@ -17,7 +18,6 @@ use crate::discovery::{
use crate::downloads::{DownloadResult, ManagedPythonDownload, PythonDownloadRequest, Reporter}; use crate::downloads::{DownloadResult, ManagedPythonDownload, PythonDownloadRequest, Reporter};
use crate::implementation::LenientImplementationName; use crate::implementation::LenientImplementationName;
use crate::managed::{ManagedPythonInstallation, ManagedPythonInstallations}; use crate::managed::{ManagedPythonInstallation, ManagedPythonInstallations};
use crate::platform::{Arch, Libc, Os};
use crate::{ use crate::{
Error, ImplementationName, Interpreter, PythonDownloads, PythonPreference, PythonSource, Error, ImplementationName, Interpreter, PythonDownloads, PythonPreference, PythonSource,
PythonVariant, PythonVersion, downloads, PythonVariant, PythonVersion, downloads,

View file

@ -21,13 +21,13 @@ use uv_fs::{LockedFile, PythonExt, Simplified, write_atomic_sync};
use uv_install_wheel::Layout; use uv_install_wheel::Layout;
use uv_pep440::Version; use uv_pep440::Version;
use uv_pep508::{MarkerEnvironment, StringVersion}; use uv_pep508::{MarkerEnvironment, StringVersion};
use uv_platform::{Arch, Libc, Os};
use uv_platform_tags::Platform; use uv_platform_tags::Platform;
use uv_platform_tags::{Tags, TagsError}; use uv_platform_tags::{Tags, TagsError};
use uv_pypi_types::{ResolverMarkerEnvironment, Scheme}; use uv_pypi_types::{ResolverMarkerEnvironment, Scheme};
use crate::implementation::LenientImplementationName; use crate::implementation::LenientImplementationName;
use crate::managed::ManagedPythonInstallations; use crate::managed::ManagedPythonInstallations;
use crate::platform::{Arch, Libc, Os};
use crate::pointer_size::PointerSize; use crate::pointer_size::PointerSize;
use crate::{ use crate::{
Prefix, PythonInstallationKey, PythonVariant, PythonVersion, Target, VersionRequest, Prefix, PythonInstallationKey, PythonVariant, PythonVersion, Target, VersionRequest,

View file

@ -29,19 +29,16 @@ pub use crate::version_files::{
}; };
pub use crate::virtualenv::{Error as VirtualEnvError, PyVenvConfiguration, VirtualEnvironment}; pub use crate::virtualenv::{Error as VirtualEnvError, PyVenvConfiguration, VirtualEnvironment};
mod cpuinfo;
mod discovery; mod discovery;
pub mod downloads; pub mod downloads;
mod environment; mod environment;
mod implementation; mod implementation;
mod installation; mod installation;
mod interpreter; mod interpreter;
mod libc;
pub mod macos_dylib; pub mod macos_dylib;
pub mod managed; pub mod managed;
#[cfg(windows)] #[cfg(windows)]
mod microsoft_store; mod microsoft_store;
pub mod platform;
mod pointer_size; mod pointer_size;
mod prefix; mod prefix;
mod python_version; mod python_version;

View file

@ -17,6 +17,8 @@ use uv_configuration::{Preview, PreviewFeatures};
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT; use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;
use uv_fs::{LockedFile, Simplified, replace_symlink, symlink_or_copy_file}; use uv_fs::{LockedFile, Simplified, replace_symlink, symlink_or_copy_file};
use uv_platform::Error as PlatformError;
use uv_platform::{Arch, Libc, LibcDetectionError, Os};
use uv_state::{StateBucket, StateStore}; use uv_state::{StateBucket, StateStore};
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_trampoline_builder::{Launcher, windows_python_launcher}; use uv_trampoline_builder::{Launcher, windows_python_launcher};
@ -26,9 +28,6 @@ use crate::implementation::{
Error as ImplementationError, ImplementationName, LenientImplementationName, Error as ImplementationError, ImplementationName, LenientImplementationName,
}; };
use crate::installation::{self, PythonInstallationKey}; use crate::installation::{self, PythonInstallationKey};
use crate::libc::LibcDetectionError;
use crate::platform::Error as PlatformError;
use crate::platform::{Arch, Libc, Os};
use crate::python_version::PythonVersion; use crate::python_version::PythonVersion;
use crate::{ use crate::{
PythonInstallationMinorVersionKey, PythonRequest, PythonVariant, macos_dylib, sysconfig, PythonInstallationMinorVersionKey, PythonRequest, PythonVariant, macos_dylib, sysconfig,
@ -271,7 +270,7 @@ impl ManagedPythonInstallations {
&& (arch.supports(installation.key.arch) && (arch.supports(installation.key.arch)
// TODO(zanieb): Allow inequal variants, as `Arch::supports` does not // TODO(zanieb): Allow inequal variants, as `Arch::supports` does not
// implement this yet. See https://github.com/astral-sh/uv/pull/9788 // implement this yet. See https://github.com/astral-sh/uv/pull/9788
|| arch.family == installation.key.arch.family) || arch.family() == installation.key.arch.family())
&& installation.key.libc == libc && installation.key.libc == libc
}); });
@ -545,7 +544,7 @@ impl ManagedPythonInstallation {
/// standard `EXTERNALLY-MANAGED` file. /// standard `EXTERNALLY-MANAGED` file.
pub fn ensure_externally_managed(&self) -> Result<(), Error> { pub fn ensure_externally_managed(&self) -> Result<(), Error> {
// Construct the path to the `stdlib` directory. // Construct the path to the `stdlib` directory.
let stdlib = if matches!(self.key.os, Os(target_lexicon::OperatingSystem::Windows)) { let stdlib = if self.key.os.is_windows() {
self.python_dir().join("Lib") self.python_dir().join("Lib")
} else { } else {
let lib_suffix = self.key.variant.suffix(); let lib_suffix = self.key.variant.suffix();

View file

@ -1,427 +0,0 @@
use crate::cpuinfo::detect_hardware_floating_point_support;
use crate::libc::{LibcDetectionError, LibcVersion, detect_linux_libc};
use std::fmt::Display;
use std::ops::Deref;
use std::{fmt, str::FromStr};
use thiserror::Error;
use uv_static::EnvVars;
#[derive(Error, Debug)]
pub enum Error {
#[error("Unknown operating system: {0}")]
UnknownOs(String),
#[error("Unknown architecture: {0}")]
UnknownArch(String),
#[error("Unknown libc environment: {0}")]
UnknownLibc(String),
#[error("Unsupported variant `{0}` for architecture `{1}`")]
UnsupportedVariant(String, String),
#[error(transparent)]
LibcDetectionError(#[from] LibcDetectionError),
}
/// Architecture variants, e.g., with support for different instruction sets
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum ArchVariant {
/// Targets 64-bit Intel/AMD CPUs newer than Nehalem (2008).
/// Includes SSE3, SSE4 and other post-2003 CPU instructions.
V2,
/// Targets 64-bit Intel/AMD CPUs newer than Haswell (2013) and Excavator (2015).
/// Includes AVX, AVX2, MOVBE and other newer CPU instructions.
V3,
/// Targets 64-bit Intel/AMD CPUs with AVX-512 instructions (post-2017 Intel CPUs).
/// Many post-2017 Intel CPUs do not support AVX-512.
V4,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct Arch {
pub(crate) family: target_lexicon::Architecture,
pub(crate) variant: Option<ArchVariant>,
}
impl Ord for Arch {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if self.family == other.family {
return self.variant.cmp(&other.variant);
}
// For the time being, manually make aarch64 windows disfavored
// on its own host platform, because most packages don't have wheels for
// aarch64 windows, making emulation more useful than native execution!
//
// The reason we do this in "sorting" and not "supports" is so that we don't
// *refuse* to use an aarch64 windows pythons if they happen to be installed
// and nothing else is available.
//
// Similarly if someone manually requests an aarch64 windows install, we
// should respect that request (this is the way users should "override"
// this behaviour).
let preferred = if cfg!(all(windows, target_arch = "aarch64")) {
Arch {
family: target_lexicon::Architecture::X86_64,
variant: None,
}
} else {
// Prefer native architectures
Arch::from_env()
};
match (
self.family == preferred.family,
other.family == preferred.family,
) {
(true, true) => unreachable!(),
(true, false) => std::cmp::Ordering::Less,
(false, true) => std::cmp::Ordering::Greater,
(false, false) => {
// Both non-preferred, fallback to lexicographic order
self.family.to_string().cmp(&other.family.to_string())
}
}
}
}
impl PartialOrd for Arch {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct Os(pub(crate) target_lexicon::OperatingSystem);
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum Libc {
Some(target_lexicon::Environment),
None,
}
impl Libc {
pub(crate) fn from_env() -> Result<Self, Error> {
match std::env::consts::OS {
"linux" => {
if let Ok(libc) = std::env::var(EnvVars::UV_LIBC) {
if !libc.is_empty() {
return Self::from_str(&libc);
}
}
Ok(Self::Some(match detect_linux_libc()? {
LibcVersion::Manylinux { .. } => match std::env::consts::ARCH {
// Checks if the CPU supports hardware floating-point operations.
// Depending on the result, it selects either the `gnueabihf` (hard-float) or `gnueabi` (soft-float) environment.
// download-metadata.json only includes armv7.
"arm" | "armv5te" | "armv7" => {
match detect_hardware_floating_point_support() {
Ok(true) => target_lexicon::Environment::Gnueabihf,
Ok(false) => target_lexicon::Environment::Gnueabi,
Err(_) => target_lexicon::Environment::Gnu,
}
}
_ => target_lexicon::Environment::Gnu,
},
LibcVersion::Musllinux { .. } => target_lexicon::Environment::Musl,
}))
}
"windows" | "macos" => Ok(Self::None),
// Use `None` on platforms without explicit support.
_ => Ok(Self::None),
}
}
pub fn is_musl(&self) -> bool {
matches!(self, Self::Some(target_lexicon::Environment::Musl))
}
}
impl FromStr for Libc {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"gnu" => Ok(Self::Some(target_lexicon::Environment::Gnu)),
"gnueabi" => Ok(Self::Some(target_lexicon::Environment::Gnueabi)),
"gnueabihf" => Ok(Self::Some(target_lexicon::Environment::Gnueabihf)),
"musl" => Ok(Self::Some(target_lexicon::Environment::Musl)),
"none" => Ok(Self::None),
_ => Err(Error::UnknownLibc(s.to_string())),
}
}
}
impl Os {
pub fn from_env() -> Self {
Self(target_lexicon::HOST.operating_system)
}
}
impl Arch {
pub fn from_env() -> Self {
Self {
family: target_lexicon::HOST.architecture,
variant: None,
}
}
/// Does the current architecture support running the other?
///
/// When the architecture is equal, this is always true. Otherwise, this is true if the
/// architecture is transparently emulated or is a microarchitecture with worse performance
/// characteristics.
pub(crate) fn supports(self, other: Self) -> bool {
if self == other {
return true;
}
// TODO: Implement `variant` support checks
// Windows ARM64 runs emulated x86_64 binaries transparently
// Similarly, macOS aarch64 runs emulated x86_64 binaries transparently if you have Rosetta
// installed. We don't try to be clever and check if that's the case here, we just assume
// that if x86_64 distributions are available, they're usable.
if (cfg!(windows) || cfg!(target_os = "macos"))
&& matches!(self.family, target_lexicon::Architecture::Aarch64(_))
{
return other.family == target_lexicon::Architecture::X86_64;
}
false
}
pub fn family(&self) -> target_lexicon::Architecture {
self.family
}
pub fn is_arm(&self) -> bool {
matches!(self.family, target_lexicon::Architecture::Arm(_))
}
}
impl Display for Libc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Some(env) => write!(f, "{env}"),
Self::None => write!(f, "none"),
}
}
}
impl Display for Os {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &**self {
target_lexicon::OperatingSystem::Darwin(_) => write!(f, "macos"),
inner => write!(f, "{inner}"),
}
}
}
impl Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.family {
target_lexicon::Architecture::X86_32(target_lexicon::X86_32Architecture::I686) => {
write!(f, "x86")?;
}
inner => write!(f, "{inner}")?,
}
if let Some(variant) = self.variant {
write!(f, "_{variant}")?;
}
Ok(())
}
}
impl FromStr for Os {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let inner = match s {
"macos" => target_lexicon::OperatingSystem::Darwin(None),
_ => target_lexicon::OperatingSystem::from_str(s)
.map_err(|()| Error::UnknownOs(s.to_string()))?,
};
if matches!(inner, target_lexicon::OperatingSystem::Unknown) {
return Err(Error::UnknownOs(s.to_string()));
}
Ok(Self(inner))
}
}
impl FromStr for Arch {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
fn parse_family(s: &str) -> Result<target_lexicon::Architecture, Error> {
let inner = match s {
// Allow users to specify "x86" as a shorthand for the "i686" variant, they should not need
// to specify the exact architecture and this variant is what we have downloads for.
"x86" => {
target_lexicon::Architecture::X86_32(target_lexicon::X86_32Architecture::I686)
}
_ => target_lexicon::Architecture::from_str(s)
.map_err(|()| Error::UnknownArch(s.to_string()))?,
};
if matches!(inner, target_lexicon::Architecture::Unknown) {
return Err(Error::UnknownArch(s.to_string()));
}
Ok(inner)
}
// First check for a variant
if let Some((Ok(family), Ok(variant))) = s
.rsplit_once('_')
.map(|(family, variant)| (parse_family(family), ArchVariant::from_str(variant)))
{
// We only support variants for `x86_64` right now
if !matches!(family, target_lexicon::Architecture::X86_64) {
return Err(Error::UnsupportedVariant(
variant.to_string(),
family.to_string(),
));
}
return Ok(Self {
family,
variant: Some(variant),
});
}
let family = parse_family(s)?;
Ok(Self {
family,
variant: None,
})
}
}
impl FromStr for ArchVariant {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"v2" => Ok(Self::V2),
"v3" => Ok(Self::V3),
"v4" => Ok(Self::V4),
_ => Err(()),
}
}
}
impl Display for ArchVariant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::V2 => write!(f, "v2"),
Self::V3 => write!(f, "v3"),
Self::V4 => write!(f, "v4"),
}
}
}
impl Deref for Os {
type Target = target_lexicon::OperatingSystem;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<&uv_platform_tags::Arch> for Arch {
fn from(value: &uv_platform_tags::Arch) -> Self {
match value {
uv_platform_tags::Arch::Aarch64 => Self {
family: target_lexicon::Architecture::Aarch64(
target_lexicon::Aarch64Architecture::Aarch64,
),
variant: None,
},
uv_platform_tags::Arch::Armv5TEL => Self {
family: target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv5te),
variant: None,
},
uv_platform_tags::Arch::Armv6L => Self {
family: target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv6),
variant: None,
},
uv_platform_tags::Arch::Armv7L => Self {
family: target_lexicon::Architecture::Arm(target_lexicon::ArmArchitecture::Armv7),
variant: None,
},
uv_platform_tags::Arch::S390X => Self {
family: target_lexicon::Architecture::S390x,
variant: None,
},
uv_platform_tags::Arch::Powerpc => Self {
family: target_lexicon::Architecture::Powerpc,
variant: None,
},
uv_platform_tags::Arch::Powerpc64 => Self {
family: target_lexicon::Architecture::Powerpc64,
variant: None,
},
uv_platform_tags::Arch::Powerpc64Le => Self {
family: target_lexicon::Architecture::Powerpc64le,
variant: None,
},
uv_platform_tags::Arch::X86 => Self {
family: target_lexicon::Architecture::X86_32(
target_lexicon::X86_32Architecture::I686,
),
variant: None,
},
uv_platform_tags::Arch::X86_64 => Self {
family: target_lexicon::Architecture::X86_64,
variant: None,
},
uv_platform_tags::Arch::LoongArch64 => Self {
family: target_lexicon::Architecture::LoongArch64,
variant: None,
},
uv_platform_tags::Arch::Riscv64 => Self {
family: target_lexicon::Architecture::Riscv64(
target_lexicon::Riscv64Architecture::Riscv64,
),
variant: None,
},
uv_platform_tags::Arch::Wasm32 => Self {
family: target_lexicon::Architecture::Wasm32,
variant: None,
},
}
}
}
impl From<&uv_platform_tags::Os> for Libc {
fn from(value: &uv_platform_tags::Os) -> Self {
match value {
uv_platform_tags::Os::Manylinux { .. } => Self::Some(target_lexicon::Environment::Gnu),
uv_platform_tags::Os::Musllinux { .. } => Self::Some(target_lexicon::Environment::Musl),
_ => Self::None,
}
}
}
impl From<&uv_platform_tags::Os> for Os {
fn from(value: &uv_platform_tags::Os) -> Self {
match value {
uv_platform_tags::Os::Dragonfly { .. } => {
Self(target_lexicon::OperatingSystem::Dragonfly)
}
uv_platform_tags::Os::FreeBsd { .. } => Self(target_lexicon::OperatingSystem::Freebsd),
uv_platform_tags::Os::Haiku { .. } => Self(target_lexicon::OperatingSystem::Haiku),
uv_platform_tags::Os::Illumos { .. } => Self(target_lexicon::OperatingSystem::Illumos),
uv_platform_tags::Os::Macos { .. } => {
Self(target_lexicon::OperatingSystem::Darwin(None))
}
uv_platform_tags::Os::Manylinux { .. }
| uv_platform_tags::Os::Musllinux { .. }
| uv_platform_tags::Os::Android { .. } => Self(target_lexicon::OperatingSystem::Linux),
uv_platform_tags::Os::NetBsd { .. } => Self(target_lexicon::OperatingSystem::Netbsd),
uv_platform_tags::Os::OpenBsd { .. } => Self(target_lexicon::OperatingSystem::Openbsd),
uv_platform_tags::Os::Windows => Self(target_lexicon::OperatingSystem::Windows),
uv_platform_tags::Os::Pyodide { .. } => {
Self(target_lexicon::OperatingSystem::Emscripten)
}
}
}
}

View file

@ -1,7 +1,6 @@
//! PEP 514 interactions with the Windows registry. //! PEP 514 interactions with the Windows registry.
use crate::managed::ManagedPythonInstallation; use crate::managed::ManagedPythonInstallation;
use crate::platform::Arch;
use crate::{COMPANY_DISPLAY_NAME, COMPANY_KEY, PythonInstallationKey, PythonVersion}; use crate::{COMPANY_DISPLAY_NAME, COMPANY_KEY, PythonInstallationKey, PythonVersion};
use anyhow::anyhow; use anyhow::anyhow;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -11,6 +10,7 @@ use std::str::FromStr;
use target_lexicon::PointerWidth; use target_lexicon::PointerWidth;
use thiserror::Error; use thiserror::Error;
use tracing::debug; use tracing::debug;
use uv_platform::Arch;
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use windows_registry::{CURRENT_USER, HSTRING, Key, LOCAL_MACHINE, Value}; use windows_registry::{CURRENT_USER, HSTRING, Key, LOCAL_MACHINE, Value};
use windows_result::HRESULT; use windows_result::HRESULT;

View file

@ -38,6 +38,7 @@ uv-normalize = { workspace = true }
uv-pep440 = { workspace = true } uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true } uv-pep508 = { workspace = true }
uv-performance-memory-allocator = { path = "../uv-performance-memory-allocator", optional = true } uv-performance-memory-allocator = { path = "../uv-performance-memory-allocator", optional = true }
uv-platform = { workspace = true }
uv-platform-tags = { workspace = true } uv-platform-tags = { workspace = true }
uv-publish = { workspace = true } uv-publish = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }

View file

@ -16,6 +16,7 @@ use tracing::{debug, trace};
use uv_configuration::{Preview, PreviewFeatures}; use uv_configuration::{Preview, PreviewFeatures};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_platform::{Arch, Libc};
use uv_python::downloads::{ use uv_python::downloads::{
self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest, self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest,
}; };
@ -23,7 +24,6 @@ use uv_python::managed::{
ManagedPythonInstallation, ManagedPythonInstallations, PythonMinorVersionLink, ManagedPythonInstallation, ManagedPythonInstallations, PythonMinorVersionLink,
create_link_to_executable, python_executable_dir, create_link_to_executable, python_executable_dir,
}; };
use uv_python::platform::{Arch, Libc};
use uv_python::{ use uv_python::{
PythonDownloads, PythonInstallationKey, PythonInstallationMinorVersionKey, PythonRequest, PythonDownloads, PythonInstallationKey, PythonInstallationMinorVersionKey, PythonRequest,
PythonVersionFile, VersionFileDiscoveryOptions, VersionFilePreference, VersionRequest, PythonVersionFile, VersionFileDiscoveryOptions, VersionFilePreference, VersionRequest,

View file

@ -2,7 +2,7 @@ use assert_fs::prelude::{FileTouch, PathChild};
use assert_fs::{fixture::FileWriteStr, prelude::PathCreateDir}; use assert_fs::{fixture::FileWriteStr, prelude::PathCreateDir};
use indoc::indoc; use indoc::indoc;
use uv_python::platform::{Arch, Os}; use uv_platform::{Arch, Os};
use uv_static::EnvVars; use uv_static::EnvVars;
use crate::common::{TestContext, uv_snapshot, venv_bin_path}; use crate::common::{TestContext, uv_snapshot, venv_bin_path};

View file

@ -1,4 +1,4 @@
use uv_python::platform::{Arch, Os}; use uv_platform::{Arch, Os};
use uv_static::EnvVars; use uv_static::EnvVars;
use crate::common::{TestContext, uv_snapshot}; use crate::common::{TestContext, uv_snapshot};

View file

@ -5,10 +5,8 @@ use anyhow::Result;
use assert_cmd::assert::OutputAssertExt; use assert_cmd::assert::OutputAssertExt;
use assert_fs::fixture::{FileWriteStr, PathChild, PathCreateDir}; use assert_fs::fixture::{FileWriteStr, PathChild, PathCreateDir};
use insta::assert_snapshot; use insta::assert_snapshot;
use uv_python::{ use uv_platform::{Arch, Os};
PYTHON_VERSION_FILENAME, PYTHON_VERSIONS_FILENAME, use uv_python::{PYTHON_VERSION_FILENAME, PYTHON_VERSIONS_FILENAME};
platform::{Arch, Os},
};
#[test] #[test]
fn python_pin() { fn python_pin() {