diff --git a/Cargo.lock b/Cargo.lock index 0e7fee75f..2199f3525 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4524,7 +4524,6 @@ dependencies = [ "uv-normalize", "uv-requirements", "uv-resolver", - "uv-toolchain", "uv-types", "uv-virtualenv", "uv-warnings", @@ -4716,7 +4715,6 @@ dependencies = [ "uv-interpreter", "uv-normalize", "uv-resolver", - "uv-toolchain", "uv-types", "uv-workspace", "walkdir", @@ -4891,6 +4889,7 @@ dependencies = [ "cache-key", "configparser", "fs-err", + "futures", "indoc", "insta", "install-wheel-rs", @@ -4901,16 +4900,22 @@ dependencies = [ "platform-tags", "pypi-types", "regex", + "reqwest", + "reqwest-middleware", "rmp-serde", "same-file", + "schemars", "serde", "serde_json", "tempfile", "thiserror", + "tokio-util", "tracing", + "url", "uv-cache", + "uv-client", + "uv-extract", "uv-fs", - "uv-toolchain", "uv-warnings", "which", "winapi", @@ -5007,30 +5012,6 @@ dependencies = [ "uv-warnings", ] -[[package]] -name = "uv-toolchain" -version = "0.1.0" -dependencies = [ - "anyhow", - "fs-err", - "futures", - "once_cell", - "pep440_rs", - "pep508_rs", - "reqwest", - "reqwest-middleware", - "schemars", - "serde", - "tempfile", - "thiserror", - "tokio-util", - "tracing", - "url", - "uv-client", - "uv-extract", - "uv-fs", -] - [[package]] name = "uv-types" version = "0.0.1" @@ -5100,9 +5081,9 @@ dependencies = [ "tracing", "uv-configuration", "uv-fs", + "uv-interpreter", "uv-normalize", "uv-resolver", - "uv-toolchain", "uv-warnings", ] diff --git a/Cargo.toml b/Cargo.toml index 3acaa5969..ded696643 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,6 @@ uv-interpreter = { path = "crates/uv-interpreter" } uv-normalize = { path = "crates/uv-normalize" } uv-requirements = { path = "crates/uv-requirements" } uv-resolver = { path = "crates/uv-resolver" } -uv-toolchain = { path = "crates/uv-toolchain" } uv-types = { path = "crates/uv-types" } uv-version = { path = "crates/uv-version" } uv-virtualenv = { path = "crates/uv-virtualenv" } diff --git a/crates/uv-dev/Cargo.toml b/crates/uv-dev/Cargo.toml index c2081c8f5..2bd28af9c 100644 --- a/crates/uv-dev/Cargo.toml +++ b/crates/uv-dev/Cargo.toml @@ -31,7 +31,6 @@ uv-installer = { workspace = true } uv-interpreter = { workspace = true } uv-normalize = { workspace = true } uv-resolver = { workspace = true } -uv-toolchain = { workspace = true } uv-types = { workspace = true } uv-workspace = { workspace = true, features = ["schemars"] } diff --git a/crates/uv-dev/src/fetch_python.rs b/crates/uv-dev/src/fetch_python.rs index cdbdfcea0..95845d351 100644 --- a/crates/uv-dev/src/fetch_python.rs +++ b/crates/uv-dev/src/fetch_python.rs @@ -13,7 +13,7 @@ use tokio::time::Instant; use tracing::{info, info_span, Instrument}; use uv_fs::Simplified; -use uv_toolchain::{ +use uv_interpreter::managed::{ DownloadResult, Error, PythonDownload, PythonDownloadRequest, TOOLCHAIN_DIRECTORY, }; diff --git a/crates/uv-interpreter/Cargo.toml b/crates/uv-interpreter/Cargo.toml index 101085871..356839867 100644 --- a/crates/uv-interpreter/Cargo.toml +++ b/crates/uv-interpreter/Cargo.toml @@ -16,26 +16,34 @@ workspace = true cache-key = { workspace = true } install-wheel-rs = { workspace = true } pep440_rs = { workspace = true } -pep508_rs = { workspace = true, features = ["serde"] } +pep508_rs = { workspace = true, features = ["serde", "non-pep508-extensions"] } platform-tags = { workspace = true } pypi-types = { workspace = true } uv-cache = { workspace = true } +uv-client = { workspace = true } +uv-extract = { workspace = true } uv-fs = { workspace = true } -uv-toolchain = { workspace = true } uv-warnings = { workspace = true } +anyhow = { workspace = true } configparser = { workspace = true } fs-err = { workspace = true, features = ["tokio"] } itertools = { workspace = true } +futures = { workspace = true } once_cell = { workspace = true } regex = { workspace = true } +reqwest = { workspace = true } +reqwest-middleware = { workspace = true } rmp-serde = { workspace = true } same-file = { workspace = true } +schemars = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } +tokio-util = { workspace = true, features = ["compat"] } tracing = { workspace = true } +url = { workspace = true } which = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/crates/uv-toolchain/fetch-version-metadata.py b/crates/uv-interpreter/fetch-version-metadata.py similarity index 100% rename from crates/uv-toolchain/fetch-version-metadata.py rename to crates/uv-interpreter/fetch-version-metadata.py diff --git a/crates/uv-toolchain/python-version-metadata.json b/crates/uv-interpreter/python-version-metadata.json similarity index 100% rename from crates/uv-toolchain/python-version-metadata.json rename to crates/uv-interpreter/python-version-metadata.json diff --git a/crates/uv-interpreter/src/cfg.rs b/crates/uv-interpreter/src/environment/cfg.rs similarity index 100% rename from crates/uv-interpreter/src/cfg.rs rename to crates/uv-interpreter/src/environment/cfg.rs diff --git a/crates/uv-interpreter/src/environment/mod.rs b/crates/uv-interpreter/src/environment/mod.rs new file mode 100644 index 000000000..004e68269 --- /dev/null +++ b/crates/uv-interpreter/src/environment/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod cfg; +pub(crate) mod python_environment; +pub(crate) mod virtualenv; diff --git a/crates/uv-interpreter/src/python_environment.rs b/crates/uv-interpreter/src/environment/python_environment.rs similarity index 99% rename from crates/uv-interpreter/src/python_environment.rs rename to crates/uv-interpreter/src/environment/python_environment.rs index db490fac7..2518c5b3e 100644 --- a/crates/uv-interpreter/src/python_environment.rs +++ b/crates/uv-interpreter/src/environment/python_environment.rs @@ -8,7 +8,7 @@ use tracing::{debug, info}; use uv_cache::Cache; use uv_fs::{LockedFile, Simplified}; -use crate::cfg::PyVenvConfiguration; +use crate::environment::cfg::PyVenvConfiguration; use crate::{find_default_python, find_requested_python, Error, Interpreter, Target}; /// A Python environment, consisting of a Python [`Interpreter`] and its associated paths. diff --git a/crates/uv-interpreter/src/virtualenv.rs b/crates/uv-interpreter/src/environment/virtualenv.rs similarity index 100% rename from crates/uv-interpreter/src/virtualenv.rs rename to crates/uv-interpreter/src/environment/virtualenv.rs diff --git a/crates/uv-interpreter/src/find_python.rs b/crates/uv-interpreter/src/find_python.rs index d84f8dc45..d2090a5c7 100644 --- a/crates/uv-interpreter/src/find_python.rs +++ b/crates/uv-interpreter/src/find_python.rs @@ -6,11 +6,11 @@ use std::path::PathBuf; use tracing::{debug, instrument}; use uv_cache::Cache; -use uv_toolchain::PythonVersion; use uv_warnings::warn_user_once; +use crate::environment::python_environment::{detect_python_executable, detect_virtual_env}; use crate::interpreter::InterpreterInfoError; -use crate::python_environment::{detect_python_executable, detect_virtual_env}; +use crate::PythonVersion; use crate::{Error, Interpreter}; /// Find a Python of a specific version, a binary with a name or a path to a binary. diff --git a/crates/uv-interpreter/src/interpreter.rs b/crates/uv-interpreter/src/interpreter.rs index 1b2248a19..0270424af 100644 --- a/crates/uv-interpreter/src/interpreter.rs +++ b/crates/uv-interpreter/src/interpreter.rs @@ -16,10 +16,8 @@ use platform_tags::{Tags, TagsError}; use pypi_types::Scheme; use uv_cache::{Cache, CacheBucket, CachedByTimestamp, Freshness, Timestamp}; use uv_fs::{write_atomic_sync, PythonExt, Simplified}; -use uv_toolchain::PythonVersion; -use crate::Virtualenv; -use crate::{Error, Target}; +use crate::{Error, PythonVersion, Target, Virtualenv}; /// A Python executable and its associated platform markers. #[derive(Debug, Clone)] diff --git a/crates/uv-interpreter/src/lib.rs b/crates/uv-interpreter/src/lib.rs index 607be77f4..4c0fb9fb4 100644 --- a/crates/uv-interpreter/src/lib.rs +++ b/crates/uv-interpreter/src/lib.rs @@ -14,20 +14,22 @@ use std::process::ExitStatus; use thiserror::Error; -pub use crate::cfg::PyVenvConfiguration; +pub use crate::environment::cfg::PyVenvConfiguration; +pub use crate::environment::python_environment::PythonEnvironment; +pub use crate::environment::virtualenv::Virtualenv; pub use crate::find_python::{find_best_python, find_default_python, find_requested_python}; pub use crate::interpreter::Interpreter; use crate::interpreter::InterpreterInfoError; -pub use crate::python_environment::PythonEnvironment; +pub use crate::python_version::PythonVersion; pub use crate::target::Target; -pub use crate::virtualenv::Virtualenv; -mod cfg; +mod environment; mod find_python; mod interpreter; -mod python_environment; +pub mod managed; +mod python_version; +pub mod selectors; mod target; -mod virtualenv; #[derive(Debug, Error)] pub enum Error { @@ -73,7 +75,7 @@ pub enum Error { #[error("Failed to write to cache")] Encode(#[from] rmp_serde::encode::Error), #[error("Broken virtualenv: Failed to parse pyvenv.cfg")] - Cfg(#[from] cfg::Error), + Cfg(#[from] environment::cfg::Error), #[error("Error finding `{}` in PATH", _0.to_string_lossy())] WhichError(OsString, #[source] which::Error), #[error("Can't use Python at `{interpreter}`")] diff --git a/crates/uv-toolchain/src/downloads.rs b/crates/uv-interpreter/src/managed/downloads.rs similarity index 63% rename from crates/uv-toolchain/src/downloads.rs rename to crates/uv-interpreter/src/managed/downloads.rs index 85c709259..22792e7f5 100644 --- a/crates/uv-toolchain/src/downloads.rs +++ b/crates/uv-interpreter/src/managed/downloads.rs @@ -1,8 +1,9 @@ -use std::fmt::{self, Display}; +use std::fmt::Display; use std::io; use std::path::{Path, PathBuf}; use std::str::FromStr; +use crate::selectors::{Arch, ImplementationName, Libc, Os, PythonSelectorError}; use crate::PythonVersion; use thiserror::Error; use uv_client::BetterReqwestError; @@ -16,12 +17,8 @@ use uv_fs::Simplified; #[derive(Error, Debug)] pub enum Error { - #[error("operating system not supported: {0}")] - OsNotSupported(String), - #[error("architecture not supported: {0}")] - ArchNotSupported(String), - #[error("libc type could not be detected")] - LibcNotDetected(), + #[error(transparent)] + SelectorError(#[from] PythonSelectorError), #[error("invalid python version: {0}")] InvalidPythonVersion(String), #[error("download failed")] @@ -139,24 +136,6 @@ impl FromStr for PythonDownloadRequest { } } -#[derive(Debug, PartialEq)] -pub enum Libc { - Gnu, - Musl, - None, -} - -#[derive(Debug, PartialEq)] -pub enum ImplementationName { - Cpython, -} -#[derive(Debug, PartialEq)] -pub struct Platform { - os: Os, - arch: Arch, - libc: Libc, -} - include!("python_versions.inc"); pub enum DownloadResult { @@ -273,147 +252,6 @@ impl PythonDownload { } } -impl Platform { - pub fn new(os: Os, arch: Arch, libc: Libc) -> Self { - Self { os, arch, libc } - } - pub fn from_env() -> Result { - Ok(Self::new( - Os::from_env()?, - Arch::from_env()?, - Libc::from_env()?, - )) - } -} - -/// All supported operating systems. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Os { - Windows, - Linux, - Macos, - FreeBsd, - NetBsd, - OpenBsd, - Dragonfly, - Illumos, - Haiku, -} - -impl fmt::Display for Os { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::Windows => write!(f, "Windows"), - Self::Macos => write!(f, "MacOS"), - Self::FreeBsd => write!(f, "FreeBSD"), - Self::NetBsd => write!(f, "NetBSD"), - Self::Linux => write!(f, "Linux"), - Self::OpenBsd => write!(f, "OpenBSD"), - Self::Dragonfly => write!(f, "DragonFly"), - Self::Illumos => write!(f, "Illumos"), - Self::Haiku => write!(f, "Haiku"), - } - } -} - -impl Os { - pub(crate) fn from_env() -> Result { - Self::from_str(std::env::consts::OS) - } -} - -impl FromStr for Os { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "windows" => Ok(Self::Windows), - "linux" => Ok(Self::Linux), - "macos" => Ok(Self::Macos), - "freebsd" => Ok(Self::FreeBsd), - "netbsd" => Ok(Self::NetBsd), - "openbsd" => Ok(Self::OpenBsd), - "dragonfly" => Ok(Self::Dragonfly), - "illumos" => Ok(Self::Illumos), - "haiku" => Ok(Self::Haiku), - _ => Err(Error::OsNotSupported(s.to_string())), - } - } -} - -/// All supported CPU architectures -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Arch { - Aarch64, - Armv6L, - Armv7L, - Powerpc64Le, - Powerpc64, - X86, - X86_64, - S390X, -} - -impl fmt::Display for Arch { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::Aarch64 => write!(f, "aarch64"), - Self::Armv6L => write!(f, "armv6l"), - Self::Armv7L => write!(f, "armv7l"), - Self::Powerpc64Le => write!(f, "ppc64le"), - Self::Powerpc64 => write!(f, "ppc64"), - Self::X86 => write!(f, "i686"), - Self::X86_64 => write!(f, "x86_64"), - Self::S390X => write!(f, "s390x"), - } - } -} - -impl FromStr for Arch { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "aarch64" | "arm64" => Ok(Self::Aarch64), - "armv6l" => Ok(Self::Armv6L), - "armv7l" => Ok(Self::Armv7L), - "powerpc64le" | "ppc64le" => Ok(Self::Powerpc64Le), - "powerpc64" | "ppc64" => Ok(Self::Powerpc64), - "x86" | "i686" | "i386" => Ok(Self::X86), - "x86_64" | "amd64" => Ok(Self::X86_64), - "s390x" => Ok(Self::S390X), - _ => Err(Error::ArchNotSupported(s.to_string())), - } - } -} - -impl Arch { - pub(crate) fn from_env() -> Result { - Self::from_str(std::env::consts::ARCH) - } -} - -impl Libc { - pub(crate) fn from_env() -> Result { - // TODO(zanieb): Perform this lookup - match std::env::consts::OS { - "linux" => Ok(Libc::Gnu), - "windows" | "macos" => Ok(Libc::None), - _ => Err(Error::LibcNotDetected()), - } - } -} - -impl fmt::Display for Libc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Libc::Gnu => f.write_str("gnu"), - Libc::None => f.write_str("none"), - Libc::Musl => f.write_str("musl"), - } - } -} - impl From for Error { fn from(error: reqwest::Error) -> Self { Self::NetworkError(BetterReqwestError::from(error)) diff --git a/crates/uv-toolchain/src/find.rs b/crates/uv-interpreter/src/managed/find.rs similarity index 97% rename from crates/uv-toolchain/src/find.rs rename to crates/uv-interpreter/src/managed/find.rs index 69022bae6..ddeb02b19 100644 --- a/crates/uv-toolchain/src/find.rs +++ b/crates/uv-interpreter/src/managed/find.rs @@ -2,8 +2,9 @@ use std::collections::BTreeSet; use std::ffi::OsStr; use std::path::{Path, PathBuf}; -use crate::downloads::{Arch, Error, Libc, Os}; +use crate::managed::downloads::Error; use crate::python_version::PythonVersion; +use crate::selectors::{Arch, Libc, Os}; use once_cell::sync::Lazy; diff --git a/crates/uv-interpreter/src/managed/mod.rs b/crates/uv-interpreter/src/managed/mod.rs new file mode 100644 index 000000000..1d5967030 --- /dev/null +++ b/crates/uv-interpreter/src/managed/mod.rs @@ -0,0 +1,5 @@ +pub use crate::managed::downloads::{DownloadResult, Error, PythonDownload, PythonDownloadRequest}; +pub use crate::managed::find::{toolchains_for_version, Toolchain, TOOLCHAIN_DIRECTORY}; + +mod downloads; +mod find; diff --git a/crates/uv-toolchain/src/python_versions.inc b/crates/uv-interpreter/src/managed/python_versions.inc similarity index 99% rename from crates/uv-toolchain/src/python_versions.inc rename to crates/uv-interpreter/src/managed/python_versions.inc index 56c2aeac0..305f36d39 100644 --- a/crates/uv-toolchain/src/python_versions.inc +++ b/crates/uv-interpreter/src/managed/python_versions.inc @@ -1,7 +1,7 @@ // DO NOT EDIT // -// Generated with `crates/uv-toolchain/template-version-metadata.py` -// From template at `crates/uv-toolchain/src/python_versions.inc.mustache` +// Generated with `crates/uv-interpreter/template-version-metadata.py` +// From template at `crates/uv-interpreter/src/python_versions.inc.mustache` pub(crate) const PYTHON_DOWNLOADS: &[PythonDownload] = &[ PythonDownload { diff --git a/crates/uv-toolchain/src/python_versions.inc.mustache b/crates/uv-interpreter/src/managed/python_versions.inc.mustache similarity index 100% rename from crates/uv-toolchain/src/python_versions.inc.mustache rename to crates/uv-interpreter/src/managed/python_versions.inc.mustache diff --git a/crates/uv-toolchain/src/python_version.rs b/crates/uv-interpreter/src/python_version.rs similarity index 92% rename from crates/uv-toolchain/src/python_version.rs rename to crates/uv-interpreter/src/python_version.rs index 73ea5874b..76a016696 100644 --- a/crates/uv-toolchain/src/python_version.rs +++ b/crates/uv-interpreter/src/python_version.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use pep440_rs::Version; use pep508_rs::{MarkerEnvironment, StringVersion}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PythonVersion(StringVersion); impl Deref for PythonVersion { @@ -20,21 +20,22 @@ impl FromStr for PythonVersion { type Err = String; fn from_str(s: &str) -> Result { - let version = StringVersion::from_str(s)?; + let version = StringVersion::from_str(s) + .map_err(|err| format!("Python version `{s}` could not be parsed: {err}"))?; if version.is_dev() { - return Err(format!("Python version {s} is a development release")); + return Err(format!("Python version `{s}` is a development release")); } if version.is_local() { - return Err(format!("Python version {s} is a local version")); + return Err(format!("Python version `{s}` is a local version")); } if version.epoch() != 0 { - return Err(format!("Python version {s} has a non-zero epoch")); + return Err(format!("Python version `{s}` has a non-zero epoch")); } if version.version < Version::new([3, 7]) { - return Err(format!("Python version {s} must be >= 3.7")); + return Err(format!("Python version `{s}` must be >= 3.7")); } if version.version >= Version::new([4, 0]) { - return Err(format!("Python version {s} must be < 4.0")); + return Err(format!("Python version `{s}` must be < 4.0")); } Ok(Self(version)) @@ -52,7 +53,6 @@ impl schemars::JsonSchema for PythonVersion { } } -#[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for PythonVersion { fn deserialize>(deserializer: D) -> Result { let s = String::deserialize(deserializer)?; diff --git a/crates/uv-interpreter/src/selectors.rs b/crates/uv-interpreter/src/selectors.rs new file mode 100644 index 000000000..f790763f0 --- /dev/null +++ b/crates/uv-interpreter/src/selectors.rs @@ -0,0 +1,204 @@ +use std::{ + fmt::{self, Display}, + str::FromStr, +}; +use thiserror::Error; + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum ImplementationName { + Cpython, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Platform { + os: Os, + arch: Arch, + libc: Libc, +} + +/// All supported operating systems. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Os { + Windows, + Linux, + Macos, + FreeBsd, + NetBsd, + OpenBsd, + Dragonfly, + Illumos, + Haiku, +} + +/// All supported CPU architectures +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Arch { + Aarch64, + Armv6L, + Armv7L, + Powerpc64Le, + Powerpc64, + X86, + X86_64, + S390X, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum Libc { + Gnu, + Musl, + None, +} + +#[derive(Error, Debug)] +pub enum PythonSelectorError { + #[error("Operating system not supported: {0}")] + OsNotSupported(String), + #[error("Architecture not supported: {0}")] + ArchNotSupported(String), + #[error("Libc type could not be detected")] + LibcNotDetected(), + #[error("Implementation not supported: {0}")] + ImplementationNotSupported(String), +} + +impl ImplementationName { + pub fn as_str(&self) -> &str { + match self { + Self::Cpython => "cpython", + } + } +} + +impl FromStr for ImplementationName { + type Err = PythonSelectorError; + + fn from_str(s: &str) -> Result { + match s { + "cpython" => Ok(Self::Cpython), + _ => Err(PythonSelectorError::ImplementationNotSupported( + s.to_string(), + )), + } + } +} + +impl Display for ImplementationName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl Platform { + pub fn new(os: Os, arch: Arch, libc: Libc) -> Self { + Self { os, arch, libc } + } + pub fn from_env() -> Result { + Ok(Self::new( + Os::from_env()?, + Arch::from_env()?, + Libc::from_env()?, + )) + } +} + +impl fmt::Display for Os { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Windows => write!(f, "Windows"), + Self::Macos => write!(f, "MacOS"), + Self::FreeBsd => write!(f, "FreeBSD"), + Self::NetBsd => write!(f, "NetBSD"), + Self::Linux => write!(f, "Linux"), + Self::OpenBsd => write!(f, "OpenBSD"), + Self::Dragonfly => write!(f, "DragonFly"), + Self::Illumos => write!(f, "Illumos"), + Self::Haiku => write!(f, "Haiku"), + } + } +} + +impl Os { + pub(crate) fn from_env() -> Result { + Self::from_str(std::env::consts::OS) + } +} + +impl FromStr for Os { + type Err = PythonSelectorError; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "windows" => Ok(Self::Windows), + "linux" => Ok(Self::Linux), + "macos" => Ok(Self::Macos), + "freebsd" => Ok(Self::FreeBsd), + "netbsd" => Ok(Self::NetBsd), + "openbsd" => Ok(Self::OpenBsd), + "dragonfly" => Ok(Self::Dragonfly), + "illumos" => Ok(Self::Illumos), + "haiku" => Ok(Self::Haiku), + _ => Err(PythonSelectorError::OsNotSupported(s.to_string())), + } + } +} + +impl fmt::Display for Arch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Aarch64 => write!(f, "aarch64"), + Self::Armv6L => write!(f, "armv6l"), + Self::Armv7L => write!(f, "armv7l"), + Self::Powerpc64Le => write!(f, "ppc64le"), + Self::Powerpc64 => write!(f, "ppc64"), + Self::X86 => write!(f, "i686"), + Self::X86_64 => write!(f, "x86_64"), + Self::S390X => write!(f, "s390x"), + } + } +} + +impl FromStr for Arch { + type Err = PythonSelectorError; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "aarch64" | "arm64" => Ok(Self::Aarch64), + "armv6l" => Ok(Self::Armv6L), + "armv7l" => Ok(Self::Armv7L), + "powerpc64le" | "ppc64le" => Ok(Self::Powerpc64Le), + "powerpc64" | "ppc64" => Ok(Self::Powerpc64), + "x86" | "i686" | "i386" => Ok(Self::X86), + "x86_64" | "amd64" => Ok(Self::X86_64), + "s390x" => Ok(Self::S390X), + _ => Err(PythonSelectorError::ArchNotSupported(s.to_string())), + } + } +} + +impl Arch { + pub(crate) fn from_env() -> Result { + Self::from_str(std::env::consts::ARCH) + } +} + +impl Libc { + pub(crate) fn from_env() -> Result { + // TODO(zanieb): Perform this lookup + match std::env::consts::OS { + "linux" => Ok(Libc::Gnu), + "windows" | "macos" => Ok(Libc::None), + _ => Err(PythonSelectorError::LibcNotDetected()), + } + } +} + +impl fmt::Display for Libc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Libc::Gnu => f.write_str("gnu"), + Libc::None => f.write_str("none"), + Libc::Musl => f.write_str("musl"), + } + } +} diff --git a/crates/uv-toolchain/template-version-metadata.py b/crates/uv-interpreter/template-version-metadata.py similarity index 96% rename from crates/uv-toolchain/template-version-metadata.py rename to crates/uv-interpreter/template-version-metadata.py index f8d70f14d..7050c02a8 100644 --- a/crates/uv-toolchain/template-version-metadata.py +++ b/crates/uv-interpreter/template-version-metadata.py @@ -19,7 +19,7 @@ from pathlib import Path CRATE_ROOT = Path(__file__).parent WORKSPACE_ROOT = CRATE_ROOT.parent.parent VERSION_METADATA = CRATE_ROOT / "python-version-metadata.json" -TEMPLATE = CRATE_ROOT / "src" / "python_versions.inc.mustache" +TEMPLATE = CRATE_ROOT / "src" / "managed" / "python_versions.inc.mustache" TARGET = TEMPLATE.with_suffix("") diff --git a/crates/uv-toolchain/Cargo.toml b/crates/uv-toolchain/Cargo.toml deleted file mode 100644 index 86cccb449..000000000 --- a/crates/uv-toolchain/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "uv-toolchain" -version = "0.1.0" -edition.workspace = true -rust-version.workspace = true -homepage.workspace = true -documentation.workspace = true -repository.workspace = true -authors.workspace = true -license.workspace = true - -[dependencies] -pep440_rs = { workspace = true } -pep508_rs = { workspace = true, features = ["non-pep508-extensions"] } -uv-client = { workspace = true } -uv-extract = { workspace = true } -uv-fs = { workspace = true } - -anyhow = { workspace = true } -fs-err = { workspace = true } -futures = { workspace = true } -once_cell = {workspace = true} -reqwest = { workspace = true } -reqwest-middleware = { workspace = true } -schemars = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -tempfile = { workspace = true } -thiserror = { workspace = true } -tokio-util = { workspace = true, features = ["compat"] } -tracing = { workspace = true } -url = { workspace = true } - -[lints] -workspace = true diff --git a/crates/uv-toolchain/src/lib.rs b/crates/uv-toolchain/src/lib.rs deleted file mode 100644 index 116571ff7..000000000 --- a/crates/uv-toolchain/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use crate::downloads::{ - DownloadResult, Error, Platform, PythonDownload, PythonDownloadRequest, -}; -pub use crate::find::{toolchains_for_version, Toolchain, TOOLCHAIN_DIRECTORY}; -pub use crate::python_version::PythonVersion; - -mod downloads; -mod find; -mod python_version; diff --git a/crates/uv-workspace/Cargo.toml b/crates/uv-workspace/Cargo.toml index 2ac77b00a..7c4fdc4df 100644 --- a/crates/uv-workspace/Cargo.toml +++ b/crates/uv-workspace/Cargo.toml @@ -19,7 +19,7 @@ uv-configuration = { workspace = true, features = ["schemars", "serde"] } uv-fs = { workspace = true } uv-normalize = { workspace = true, features = ["schemars"] } uv-resolver = { workspace = true, features = ["schemars", "serde"] } -uv-toolchain = { workspace = true, features = ["schemars", "serde"] } +uv-interpreter = { workspace = true, features = ["schemars"] } uv-warnings = { workspace = true } dirs-sys = { workspace = true } diff --git a/crates/uv-workspace/src/settings.rs b/crates/uv-workspace/src/settings.rs index 3f97126c1..359854b7c 100644 --- a/crates/uv-workspace/src/settings.rs +++ b/crates/uv-workspace/src/settings.rs @@ -7,9 +7,9 @@ use install_wheel_rs::linker::LinkMode; use uv_configuration::{ ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, }; +use uv_interpreter::PythonVersion; use uv_normalize::{ExtraName, PackageName}; use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode}; -use uv_toolchain::PythonVersion; /// A `pyproject.toml` with an (optional) `[tool.uv]` section. #[allow(dead_code)] diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index 13dc5c6b5..0fcdf60c8 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -32,7 +32,6 @@ uv-interpreter = { workspace = true } uv-normalize = { workspace = true } uv-requirements = { workspace = true } uv-resolver = { workspace = true, features = ["clap"] } -uv-toolchain = { workspace = true } uv-types = { workspace = true } uv-virtualenv = { workspace = true } uv-warnings = { workspace = true } diff --git a/crates/uv/src/cli.rs b/crates/uv/src/cli.rs index f4deaddeb..abb75d6ed 100644 --- a/crates/uv/src/cli.rs +++ b/crates/uv/src/cli.rs @@ -11,9 +11,9 @@ use uv_cache::CacheArgs; use uv_configuration::{ ConfigSettingEntry, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, }; +use uv_interpreter::PythonVersion; use uv_normalize::{ExtraName, PackageName}; use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode}; -use uv_toolchain::PythonVersion; use crate::commands::{extra_name_with_clap_error, ListFormat, VersionFormat}; use crate::compat; diff --git a/crates/uv/src/commands/pip_compile.rs b/crates/uv/src/commands/pip_compile.rs index 0828ab5b1..722d6112d 100644 --- a/crates/uv/src/commands/pip_compile.rs +++ b/crates/uv/src/commands/pip_compile.rs @@ -29,6 +29,7 @@ use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_dispatch::BuildDispatch; use uv_fs::Simplified; use uv_installer::Downloader; +use uv_interpreter::PythonVersion; use uv_interpreter::{find_best_python, find_requested_python, PythonEnvironment}; use uv_normalize::{ExtraName, PackageName}; use uv_requirements::{ @@ -40,7 +41,6 @@ use uv_resolver::{ InMemoryIndex, Manifest, OptionsBuilder, PreReleaseMode, PythonRequirement, ResolutionMode, Resolver, }; -use uv_toolchain::PythonVersion; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_warnings::warn_user; diff --git a/crates/uv/src/commands/pip_install.rs b/crates/uv/src/commands/pip_install.rs index 1fc5c18db..a9b7bcfac 100644 --- a/crates/uv/src/commands/pip_install.rs +++ b/crates/uv/src/commands/pip_install.rs @@ -33,7 +33,7 @@ use uv_fs::Simplified; use uv_installer::{ BuiltEditable, Downloader, Plan, Planner, ResolvedEditable, SatisfiesResult, SitePackages, }; -use uv_interpreter::{Interpreter, PythonEnvironment, Target}; +use uv_interpreter::{Interpreter, PythonEnvironment, PythonVersion, Target}; use uv_normalize::PackageName; use uv_requirements::{ ExtrasSpecification, LookaheadResolver, NamedRequirementsResolver, RequirementsSource, @@ -43,7 +43,6 @@ use uv_resolver::{ DependencyMode, ExcludeNewer, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, OptionsBuilder, PreReleaseMode, Preference, ResolutionGraph, ResolutionMode, Resolver, }; -use uv_toolchain::PythonVersion; use uv_types::{BuildIsolation, HashStrategy, InFlight}; use uv_warnings::warn_user; diff --git a/crates/uv/src/commands/pip_sync.rs b/crates/uv/src/commands/pip_sync.rs index 36ab75785..0568d6722 100644 --- a/crates/uv/src/commands/pip_sync.rs +++ b/crates/uv/src/commands/pip_sync.rs @@ -26,13 +26,12 @@ use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_dispatch::BuildDispatch; use uv_fs::Simplified; use uv_installer::{is_dynamic, Downloader, Plan, Planner, ResolvedEditable, SitePackages}; -use uv_interpreter::{Interpreter, PythonEnvironment, Target}; +use uv_interpreter::{Interpreter, PythonEnvironment, PythonVersion, Target}; use uv_requirements::{ ExtrasSpecification, NamedRequirementsResolver, RequirementsSource, RequirementsSpecification, SourceTreeResolver, }; use uv_resolver::{DependencyMode, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, Resolver}; -use uv_toolchain::PythonVersion; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_warnings::warn_user; diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index a55d88fe2..1be4f5cbf 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -9,11 +9,10 @@ use uv_configuration::{ ConfigSettings, IndexStrategy, KeyringProviderType, NoBinary, NoBuild, PreviewMode, Reinstall, SetupPyStrategy, TargetTriple, Upgrade, }; -use uv_interpreter::Target; +use uv_interpreter::{PythonVersion, Target}; use uv_normalize::PackageName; use uv_requirements::ExtrasSpecification; use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode}; -use uv_toolchain::PythonVersion; use uv_workspace::{PipOptions, Workspace}; use crate::cli::{ diff --git a/crates/uv/tests/common/mod.rs b/crates/uv/tests/common/mod.rs index 46f6538c5..fb6cbbcd8 100644 --- a/crates/uv/tests/common/mod.rs +++ b/crates/uv/tests/common/mod.rs @@ -13,11 +13,10 @@ use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::Output; use std::str::FromStr; -use uv_interpreter::find_requested_python; - use uv_cache::Cache; use uv_fs::Simplified; -use uv_toolchain::{toolchains_for_version, PythonVersion}; +use uv_interpreter::managed::toolchains_for_version; +use uv_interpreter::{find_requested_python, PythonVersion}; // Exclude any packages uploaded after this date. pub static EXCLUDE_NEWER: &str = "2024-03-25T00:00:00Z"; @@ -341,7 +340,7 @@ pub fn create_venv Result<()> { ----- stdout ----- ----- stderr ----- - error: invalid value '3.7.x' for '--python-version ': after parsing '3.7', found '.x', which is not part of a valid version + error: invalid value '3.7.x' for '--python-version ': Python version `3.7.x` could not be parsed: after parsing '3.7', found '.x', which is not part of a valid version For more information, try '--help'. "### @@ -1009,7 +1009,7 @@ fn compile_python_dev_version() -> Result<()> { ----- stdout ----- ----- stderr ----- - error: invalid value '3.7-dev' for '--python-version ': Python version 3.7-dev is a development release + error: invalid value '3.7-dev' for '--python-version ': Python version `3.7-dev` is a development release For more information, try '--help'. "### diff --git a/crates/uv/tests/venv.rs b/crates/uv/tests/venv.rs index aab95a699..e4637a42e 100644 --- a/crates/uv/tests/venv.rs +++ b/crates/uv/tests/venv.rs @@ -9,7 +9,7 @@ use assert_fs::fixture::ChildPath; use assert_fs::prelude::*; use fs_err::PathExt; use uv_fs::Simplified; -use uv_toolchain::PythonVersion; +use uv_interpreter::PythonVersion; use crate::common::{get_bin, python_path_with_versions, uv_snapshot, TestContext, EXCLUDE_NEWER};