mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-10-31 12:06:13 +00:00 
			
		
		
		
	Merge uv-toolchain and uv-interpreter (#3265)
				
					
				
			Moves all of `uv-toolchain` into `uv-interpreter`. We may split these out in the future, but the refactoring I want to do for interpreter discovery is easier if I don't have to deal with entanglement. Includes some restructuring of `uv-interpreter`. Part of #2386
This commit is contained in:
		
							parent
							
								
									1d2c57a259
								
							
						
					
					
						commit
						630d3fde5c
					
				
					 35 changed files with 275 additions and 285 deletions
				
			
		
							
								
								
									
										37
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										37
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -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", | ||||
| ] | ||||
| 
 | ||||
|  |  | |||
|  | @ -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" } | ||||
|  |  | |||
|  | @ -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"] } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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, | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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] | ||||
|  |  | |||
							
								
								
									
										3
									
								
								crates/uv-interpreter/src/environment/mod.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								crates/uv-interpreter/src/environment/mod.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| pub(crate) mod cfg; | ||||
| pub(crate) mod python_environment; | ||||
| pub(crate) mod virtualenv; | ||||
|  | @ -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.
 | ||||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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)] | ||||
|  |  | |||
|  | @ -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}`")] | ||||
|  |  | |||
|  | @ -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<Self, Error> { | ||||
|         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, Error> { | ||||
|         Self::from_str(std::env::consts::OS) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FromStr for Os { | ||||
|     type Err = Error; | ||||
| 
 | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         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<Self, Self::Err> { | ||||
|         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, Error> { | ||||
|         Self::from_str(std::env::consts::ARCH) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Libc { | ||||
|     pub(crate) fn from_env() -> Result<Self, Error> { | ||||
|         // 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<reqwest::Error> for Error { | ||||
|     fn from(error: reqwest::Error) -> Self { | ||||
|         Self::NetworkError(BetterReqwestError::from(error)) | ||||
|  | @ -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; | ||||
| 
 | ||||
							
								
								
									
										5
									
								
								crates/uv-interpreter/src/managed/mod.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								crates/uv-interpreter/src/managed/mod.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|  | @ -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 { | ||||
|  | @ -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<Self, Self::Err> { | ||||
|         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<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { | ||||
|         let s = String::deserialize(deserializer)?; | ||||
							
								
								
									
										204
									
								
								crates/uv-interpreter/src/selectors.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								crates/uv-interpreter/src/selectors.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Self, Self::Err> { | ||||
|         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<Self, PythonSelectorError> { | ||||
|         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, PythonSelectorError> { | ||||
|         Self::from_str(std::env::consts::OS) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FromStr for Os { | ||||
|     type Err = PythonSelectorError; | ||||
| 
 | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         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<Self, Self::Err> { | ||||
|         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, PythonSelectorError> { | ||||
|         Self::from_str(std::env::consts::ARCH) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Libc { | ||||
|     pub(crate) fn from_env() -> Result<Self, PythonSelectorError> { | ||||
|         // 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"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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("") | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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 | ||||
|  | @ -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; | ||||
|  | @ -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 } | ||||
|  |  | |||
|  | @ -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)] | ||||
|  |  | |||
|  | @ -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 } | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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::{ | ||||
|  |  | |||
|  | @ -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<Parent: assert_fs::prelude::PathChild + AsRef<std::path::Path | |||
|     ) | ||||
|     .expect("Tests are run on a supported platform") | ||||
|     .first() | ||||
|     .map(uv_toolchain::Toolchain::executable) | ||||
|     .map(uv_interpreter::managed::Toolchain::executable) | ||||
|     // We'll search for the request Python on the PATH if not found in the toolchain versions
 | ||||
|     // We hack this into a `PathBuf` to satisfy the compiler but it's just a string
 | ||||
|     .unwrap_or(PathBuf::from(python)); | ||||
|  |  | |||
|  | @ -984,7 +984,7 @@ fn compile_python_invalid_version() -> Result<()> { | |||
|     ----- stdout ----- | ||||
| 
 | ||||
|     ----- stderr ----- | ||||
|     error: invalid value '3.7.x' for '--python-version <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>': 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>': Python version 3.7-dev is a development release | ||||
|     error: invalid value '3.7-dev' for '--python-version <PYTHON_VERSION>': Python version `3.7-dev` is a development release | ||||
| 
 | ||||
|     For more information, try '--help'. | ||||
|     "###
 | ||||
|  |  | |||
|  | @ -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}; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zanie Blue
						Zanie Blue