Move variant into wheel tag

This commit is contained in:
Charlie Marsh 2025-07-27 20:42:57 -04:00 committed by konstin
parent b71e278634
commit a36e44beef
8 changed files with 33 additions and 54 deletions

View File

@ -101,7 +101,6 @@ mod tests {
#[test] #[test]
fn wheel_filename_size() { fn wheel_filename_size() {
// TODO(konsti): Move the variant to the tag so this type remains small assert_eq!(size_of::<WheelFilename>(), 48);
assert_eq!(size_of::<WheelFilename>(), 72);
} }
} }

View File

@ -1,7 +1,6 @@
--- ---
source: crates/uv-distribution-filename/src/wheel.rs source: crates/uv-distribution-filename/src/wheel.rs
expression: "WheelFilename::from_str(\"foo-1.2.3-202206090410-py3-none-any.whl\")" expression: "WheelFilename::from_str(\"foo-1.2.3-202206090410-py3-none-any.whl\")"
snapshot_kind: text
--- ---
Ok( Ok(
WheelFilename { WheelFilename {
@ -29,9 +28,9 @@ Ok(
platform_tag: [ platform_tag: [
Any, Any,
], ],
variant: None,
repr: "202206090410-py3-none-any", repr: "202206090410-py3-none-any",
}, },
}, },
variant: None,
}, },
) )

View File

@ -1,7 +1,6 @@
--- ---
source: crates/uv-distribution-filename/src/wheel.rs source: crates/uv-distribution-filename/src/wheel.rs
expression: "WheelFilename::from_str(\"foo-1.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\")" expression: "WheelFilename::from_str(\"foo-1.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\")"
snapshot_kind: text
--- ---
Ok( Ok(
WheelFilename { WheelFilename {
@ -39,9 +38,9 @@ Ok(
arch: X86_64, arch: X86_64,
}, },
], ],
variant: None,
repr: "cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64", repr: "cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64",
}, },
}, },
variant: None,
}, },
) )

View File

@ -1,7 +1,6 @@
--- ---
source: crates/uv-distribution-filename/src/wheel.rs source: crates/uv-distribution-filename/src/wheel.rs
expression: "WheelFilename::from_str(\"foo-1.2.3-py3-none-any.whl\")" expression: "WheelFilename::from_str(\"foo-1.2.3-py3-none-any.whl\")"
snapshot_kind: text
--- ---
Ok( Ok(
WheelFilename { WheelFilename {
@ -19,6 +18,5 @@ Ok(
platform_tag: Any, platform_tag: Any,
}, },
}, },
variant: None,
}, },
) )

View File

@ -1,7 +1,6 @@
--- ---
source: crates/uv-distribution-filename/src/wheel.rs source: crates/uv-distribution-filename/src/wheel.rs
expression: "WheelFilename::from_str(\"dummy_project-0.0.1-1234-py3-none-any-36266d4d.whl\")" expression: "WheelFilename::from_str(\"dummy_project-0.0.1-1234-py3-none-any-36266d4d.whl\")"
snapshot_kind: text
--- ---
Ok( Ok(
WheelFilename { WheelFilename {
@ -29,11 +28,11 @@ Ok(
platform_tag: [ platform_tag: [
Any, Any,
], ],
variant: Some(
"36266d4d",
),
repr: "1234-py3-none-any-36266d4d", repr: "1234-py3-none-any-36266d4d",
}, },
}, },
variant: Some(
"36266d4d",
),
}, },
) )

View File

@ -1,7 +1,6 @@
--- ---
source: crates/uv-distribution-filename/src/wheel.rs source: crates/uv-distribution-filename/src/wheel.rs
expression: "WheelFilename::from_str(\"dummy_project-0.0.1-py3-none-any-36266d4d.whl\")" expression: "WheelFilename::from_str(\"dummy_project-0.0.1-py3-none-any-36266d4d.whl\")"
snapshot_kind: text
--- ---
Ok( Ok(
WheelFilename { WheelFilename {
@ -24,11 +23,11 @@ Ok(
platform_tag: [ platform_tag: [
Any, Any,
], ],
variant: Some(
"36266d4d",
),
repr: "py3-none-any-36266d4d", repr: "py3-none-any-36266d4d",
}, },
}, },
variant: Some(
"36266d4d",
),
}, },
) )

View File

@ -6,9 +6,6 @@ use memchr::memchr;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use thiserror::Error; use thiserror::Error;
use crate::splitter::MemchrSplitter;
use crate::wheel_tag::{WheelTag, WheelTagLarge, WheelTagSmall};
use crate::{BuildTag, BuildTagError};
use uv_cache_key::cache_digest; use uv_cache_key::cache_digest;
use uv_normalize::{InvalidNameError, PackageName}; use uv_normalize::{InvalidNameError, PackageName};
use uv_pep440::{Version, VersionParseError}; use uv_pep440::{Version, VersionParseError};
@ -16,6 +13,11 @@ use uv_platform_tags::{
AbiTag, LanguageTag, ParseAbiTagError, ParseLanguageTagError, ParsePlatformTagError, AbiTag, LanguageTag, ParseAbiTagError, ParseLanguageTagError, ParsePlatformTagError,
PlatformTag, TagCompatibility, Tags, PlatformTag, TagCompatibility, Tags,
}; };
use uv_small_str::SmallString;
use crate::splitter::MemchrSplitter;
use crate::wheel_tag::{WheelTag, WheelTagLarge, WheelTagSmall};
use crate::{BuildTag, BuildTagError};
#[derive( #[derive(
Debug, Debug,
@ -34,7 +36,6 @@ pub struct WheelFilename {
pub name: PackageName, pub name: PackageName,
pub version: Version, pub version: Version,
tags: WheelTag, tags: WheelTag,
variant: Option<String>,
} }
impl FromStr for WheelFilename { impl FromStr for WheelFilename {
@ -75,7 +76,6 @@ impl WheelFilename {
Self { Self {
name, name,
version, version,
variant: None,
tags: WheelTag::Small { tags: WheelTag::Small {
small: WheelTagSmall { small: WheelTagSmall {
python_tag, python_tag,
@ -98,22 +98,12 @@ impl WheelFilename {
/// The wheel filename without the extension. /// The wheel filename without the extension.
pub fn stem(&self) -> String { pub fn stem(&self) -> String {
if let Some(variant) = &self.variant { format!(
format!( "{}-{}-{}",
"{}-{}-{}-{}", self.name.as_dist_info_name(),
self.name.as_dist_info_name(), self.version,
self.version, self.tags
self.tags, )
variant
)
} else {
format!(
"{}-{}-{}",
self.name.as_dist_info_name(),
self.version,
self.tags
)
}
} }
/// Returns a consistent cache key with a maximum length of 64 characters. /// Returns a consistent cache key with a maximum length of 64 characters.
@ -123,12 +113,7 @@ impl WheelFilename {
pub fn cache_key(&self) -> String { pub fn cache_key(&self) -> String {
const CACHE_KEY_MAX_LEN: usize = 64; const CACHE_KEY_MAX_LEN: usize = 64;
// Include variant in the cache key if it exists let full = format!("{}-{}", self.version, self.tags);
let full = if let Some(variant) = &self.variant {
format!("{}-{}-{}", self.version, self.tags, variant)
} else {
format!("{}-{}", self.version, self.tags)
};
if full.len() <= CACHE_KEY_MAX_LEN { if full.len() <= CACHE_KEY_MAX_LEN {
return full; return full;
@ -136,11 +121,7 @@ impl WheelFilename {
// Create a digest of the tag string (and variant if it exists) to retain // Create a digest of the tag string (and variant if it exists) to retain
// compatibility across platforms, Rust versions, etc. // compatibility across platforms, Rust versions, etc.
let digest = if let Some(variant) = &self.variant { let digest = cache_digest(&format!("{}", self.tags));
cache_digest(&format!("{}-{}", self.tags, variant))
} else {
cache_digest(&format!("{}", self.tags))
};
// Truncate the version, but avoid trailing dots, plus signs, etc. to avoid ambiguity. // Truncate the version, but avoid trailing dots, plus signs, etc. to avoid ambiguity.
let version_width = CACHE_KEY_MAX_LEN - 1 /* dash */ - 16 /* digest */; let version_width = CACHE_KEY_MAX_LEN - 1 /* dash */ - 16 /* digest */;
@ -155,7 +136,10 @@ impl WheelFilename {
/// Return the wheel's variant tag, if present. /// Return the wheel's variant tag, if present.
pub fn variant(&self) -> Option<&str> { pub fn variant(&self) -> Option<&str> {
self.variant.as_deref() match &self.tags {
WheelTag::Small { .. } => None,
WheelTag::Large { large } => large.variant.as_deref(),
}
} }
/// Return the wheel's Python tags. /// Return the wheel's Python tags.
@ -244,7 +228,7 @@ impl WheelFilename {
// Extract variant from filenames with the format, e.g., `ml_project-0.0.1-py3-none-any-cu128.whl`. // Extract variant from filenames with the format, e.g., `ml_project-0.0.1-py3-none-any-cu128.whl`.
// TODO(charlie): Integrate this into the filename parsing; it's just easier to do it upfront // TODO(charlie): Integrate this into the filename parsing; it's just easier to do it upfront
// for now. // for now.
// 7 components: We have both a build tag and a variant_tag // 7 components: We have both a build tag and a variant tag.
if let Some(variant_tag) = splitter.next() { if let Some(variant_tag) = splitter.next() {
if splitter.next().is_some() { if splitter.next().is_some() {
return Err(WheelFilenameError::InvalidWheelFileName( return Err(WheelFilenameError::InvalidWheelFileName(
@ -264,7 +248,7 @@ impl WheelFilename {
false, false,
) )
} else { } else {
// 6 components: Check whether we have a build tag or variant tag // 6 components: Determine whether we have a build tag or a variant tag.
if LanguageTag::from_str( if LanguageTag::from_str(
&stem[build_tag_or_python_tag + 1..python_tag_or_abi_tag], &stem[build_tag_or_python_tag + 1..python_tag_or_abi_tag],
) )
@ -278,7 +262,7 @@ impl WheelFilename {
&stem[python_tag_or_abi_tag + 1..abi_tag_or_platform_tag], &stem[python_tag_or_abi_tag + 1..abi_tag_or_platform_tag],
&stem[abi_tag_or_platform_tag + 1..platform_tag], &stem[abi_tag_or_platform_tag + 1..platform_tag],
Some(&stem[platform_tag + 1..]), Some(&stem[platform_tag + 1..]),
// Always take the slow path if a build tag is present. // Always take the slow path if a variant tag is present.
false, false,
) )
} else { } else {
@ -351,6 +335,7 @@ impl WheelFilename {
.map(PlatformTag::from_str) .map(PlatformTag::from_str)
.filter_map(Result::ok) .filter_map(Result::ok)
.collect(), .collect(),
variant: variant.map(SmallString::from),
repr: repr.into(), repr: repr.into(),
}), }),
} }
@ -360,7 +345,6 @@ impl WheelFilename {
name, name,
version, version,
tags, tags,
variant: variant.map(ToString::to_string),
}) })
} }
} }
@ -563,6 +547,6 @@ mod tests {
// Variant tags should be included in the cache key. // Variant tags should be included in the cache key.
let filename = let filename =
WheelFilename::from_str("dummy_project-0.0.1-py3-none-any-36266d4d.whl").unwrap(); WheelFilename::from_str("dummy_project-0.0.1-py3-none-any-36266d4d.whl").unwrap();
insta::assert_snapshot!(filename.cache_key(), @"0.0.1-py3-none-any-36266d4d-36266d4d"); insta::assert_snapshot!(filename.cache_key(), @"0.0.1-py3-none-any-36266d4d");
} }
} }

View File

@ -102,6 +102,8 @@ pub(crate) struct WheelTagLarge {
pub(crate) abi_tag: TagSet<AbiTag>, pub(crate) abi_tag: TagSet<AbiTag>,
/// The platform tag(s), e.g., `none` in `1.2.3-73-py3-none-any`. /// The platform tag(s), e.g., `none` in `1.2.3-73-py3-none-any`.
pub(crate) platform_tag: TagSet<PlatformTag>, pub(crate) platform_tag: TagSet<PlatformTag>,
/// The optional variant tag.
pub(crate) variant: Option<SmallString>,
/// The string representation of the tag. /// The string representation of the tag.
/// ///
/// Preserves any unsupported tags that were filtered out when parsing the wheel filename. /// Preserves any unsupported tags that were filtered out when parsing the wheel filename.