diff --git a/Cargo.lock b/Cargo.lock index da480ead5..2faea988b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5360,6 +5360,7 @@ dependencies = [ "uv-torch", "uv-trampoline-builder", "uv-types", + "uv-variants", "uv-version", "uv-virtualenv", "uv-warnings", diff --git a/crates/uv-distribution-types/src/installed.rs b/crates/uv-distribution-types/src/installed.rs index 9024d3d21..7486406e2 100644 --- a/crates/uv-distribution-types/src/installed.rs +++ b/crates/uv-distribution-types/src/installed.rs @@ -17,10 +17,10 @@ use uv_normalize::PackageName; use uv_pep440::Version; use uv_pypi_types::{DirectUrl, MetadataError}; use uv_redacted::DisplaySafeUrl; +use uv_variants::variants_json::DistInfoVariantsJson; use crate::{ - BuildInfo, DistributionMetadata, InstalledMetadata, InstalledVersion, Name, VariantsJson, - VersionOrUrlRef, + BuildInfo, DistributionMetadata, InstalledMetadata, InstalledVersion, Name, VersionOrUrlRef, }; #[derive(Error, Debug)] @@ -486,15 +486,16 @@ impl InstalledDist { } /// Read the `variant.json` file of the distribution, if it exists. - pub fn read_variant_json(&self) -> Result, InstalledDistError> { + pub fn read_variant_json(&self) -> Result, InstalledDistError> { let path = self.install_path().join("variant.json"); let file = match fs_err::File::open(&path) { Ok(file) => file, Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), Err(err) => return Err(err.into()), }; - let variants_json = - serde_json::from_reader::, VariantsJson>(BufReader::new(file))?; + let variants_json = serde_json::from_reader::, DistInfoVariantsJson>( + BufReader::new(file), + )?; Ok(Some(variants_json)) } diff --git a/crates/uv-distribution-types/src/variant_json.rs b/crates/uv-distribution-types/src/variant_json.rs index ab5b10bfb..fa799e21b 100644 --- a/crates/uv-distribution-types/src/variant_json.rs +++ b/crates/uv-distribution-types/src/variant_json.rs @@ -1,5 +1,6 @@ -use rustc_hash::FxHashMap; -use std::{fmt::Display, str::FromStr}; +use std::fmt::Display; +use std::str::FromStr; + use uv_normalize::{InvalidNameError, PackageName}; use uv_pep440::{Version, VersionParseError}; @@ -13,25 +14,6 @@ pub enum VariantsJsonError { InvalidVersion(#[from] VersionParseError), } -/// A `--variants.json` file. -#[derive(Debug, Clone, serde::Deserialize)] -pub struct VariantsJson { - variants: FxHashMap, -} - -impl VariantsJson { - /// Returns the label for the current variant. - pub fn label(&self) -> Option<&str> { - let mut keys = self.variants.keys(); - let label = keys.next()?; - if keys.next().is_some() { - None - } else { - Some(label) - } - } -} - /// A `--variants.json` filename. #[derive( Debug, diff --git a/crates/uv-variants/src/variants_json.rs b/crates/uv-variants/src/variants_json.rs index 0f036df04..9ee4f30d9 100644 --- a/crates/uv-variants/src/variants_json.rs +++ b/crates/uv-variants/src/variants_json.rs @@ -96,6 +96,26 @@ pub struct VariantsJsonContent { pub variants: FxHashMap, } +/// A `{name}-{version}.dist-info/variant.json` file. +#[derive(Debug, Clone, serde::Deserialize)] +#[allow(clippy::zero_sized_map_values)] +pub struct DistInfoVariantsJson { + pub variants: FxHashMap, +} + +impl DistInfoVariantsJson { + /// Returns the label for the current variant. + pub fn label(&self) -> Option<&VariantLabel> { + let mut keys = self.variants.keys(); + let label = keys.next()?; + if keys.next().is_some() { + None + } else { + Some(label) + } + } +} + /// Default provider priorities #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index c7805069f..214c9cdf1 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -59,6 +59,7 @@ uv-tool = { workspace = true } uv-torch = { workspace = true } uv-trampoline-builder = { workspace = true } uv-types = { workspace = true } +uv-variants = { workspace = true } uv-version = { workspace = true } uv-virtualenv = { workspace = true } uv-warnings = { workspace = true } diff --git a/crates/uv/src/commands/pip/list.rs b/crates/uv/src/commands/pip/list.rs index fe1ebfb36..f80e4abd0 100644 --- a/crates/uv/src/commands/pip/list.rs +++ b/crates/uv/src/commands/pip/list.rs @@ -16,10 +16,9 @@ use uv_cache_info::Timestamp; use uv_cli::ListFormat; use uv_client::{BaseClientBuilder, RegistryClientBuilder}; use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType}; -use uv_distribution_filename::DistFilename; +use uv_distribution_filename::{DistFilename, VariantLabel}; use uv_distribution_types::{ Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython, - VariantsJson, }; use uv_fs::Simplified; use uv_installer::SitePackages; @@ -29,6 +28,7 @@ use uv_preview::Preview; use uv_python::PythonRequest; use uv_python::{EnvironmentPreference, PythonEnvironment, PythonPreference}; use uv_resolver::{ExcludeNewer, PrereleaseMode}; +use uv_variants::variants_json::DistInfoVariantsJson; use crate::commands::ExitStatus; use crate::commands::pip::latest::LatestClient; @@ -172,8 +172,8 @@ pub(crate) async fn pip_list( .ok() .flatten() .as_ref() - .and_then(VariantsJson::label) - .map(ToString::to_string), + .and_then(DistInfoVariantsJson::label) + .cloned(), latest_version: latest .get(dist.name()) .and_then(|filename| filename.as_ref()) @@ -220,7 +220,7 @@ pub(crate) async fn pip_list( .ok() .flatten() .as_ref() - .and_then(VariantsJson::label) + .and_then(DistInfoVariantsJson::label) .map(ToString::to_string) }) .collect_vec(); @@ -360,7 +360,7 @@ struct Entry { name: PackageName, version: Version, #[serde(skip_serializing_if = "Option::is_none")] - variant: Option, + variant: Option, #[serde(skip_serializing_if = "Option::is_none")] latest_version: Option, #[serde(skip_serializing_if = "Option::is_none")]