Add it to index pages too

This commit is contained in:
konstin 2025-07-03 16:55:00 +02:00
parent ab3e837a72
commit e4ea748074
5 changed files with 83 additions and 29 deletions

View file

@ -998,7 +998,7 @@ impl CacheBucket {
Self::Interpreter => "interpreter-v4",
// Note that when bumping this, you'll also need to bump it
// in `crates/uv/tests/it/cache_clean.rs`.
Self::Simple => "simple-v16",
Self::Simple => "simple-v17",
// Note that when bumping this, you'll also need to bump it
// in `crates/uv/tests/it/cache_prune.rs`.
Self::Wheels => "wheels-v5",

View file

@ -21,8 +21,9 @@ use uv_configuration::KeyringProviderType;
use uv_configuration::{IndexStrategy, TrustedHost};
use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
use uv_distribution_types::{
BuiltDist, File, FileLocation, IndexCapabilities, IndexFormat, IndexLocations,
IndexMetadataRef, IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl, IndexUrls, Name,
BuiltDist, File, FileLocation, IndexCapabilities, IndexEntryFilename, IndexFormat,
IndexLocations, IndexMetadataRef, IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl,
IndexUrls, Name, VariantsJson,
};
use uv_metadata::{read_metadata_async_seek, read_metadata_async_stream};
use uv_normalize::PackageName;
@ -1050,15 +1051,21 @@ impl FlatIndexCache {
pub struct VersionFiles {
pub wheels: Vec<VersionWheel>,
pub source_dists: Vec<VersionSourceDist>,
pub variant_jsons: Vec<VersionVariantJson>,
}
impl VersionFiles {
fn push(&mut self, filename: DistFilename, file: File) {
fn push(&mut self, filename: IndexEntryFilename, file: File) {
match filename {
DistFilename::WheelFilename(name) => self.wheels.push(VersionWheel { name, file }),
DistFilename::SourceDistFilename(name) => {
IndexEntryFilename::DistFilename(DistFilename::WheelFilename(name)) => {
self.wheels.push(VersionWheel { name, file })
}
IndexEntryFilename::DistFilename(DistFilename::SourceDistFilename(name)) => {
self.source_dists.push(VersionSourceDist { name, file });
}
IndexEntryFilename::VariantJson(variants_json) => {
self.variant_jsons.push(VersionVariantJson { name: variants_json, file });
}
}
}
@ -1088,6 +1095,13 @@ pub struct VersionSourceDist {
pub file: File,
}
#[derive(Debug, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)]
#[rkyv(derive(Debug))]
pub struct VersionVariantJson {
pub name: VariantsJson,
pub file: File,
}
#[derive(Default, Debug, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)]
#[rkyv(derive(Debug))]
pub struct SimpleMetadata(Vec<SimpleMetadatum>);
@ -1112,15 +1126,11 @@ impl SimpleMetadata {
// Group the distributions by version and kind
for file in files {
let Some(filename) = DistFilename::try_from_filename(&file.filename, package_name)
let Some(filename) = IndexEntryFilename::try_from_filename(&file.filename, package_name)
else {
warn!("Skipping file for {package_name}: {}", file.filename);
continue;
};
let version = match filename {
DistFilename::SourceDistFilename(ref inner) => &inner.version,
DistFilename::WheelFilename(ref inner) => &inner.version,
};
let file = match File::try_from(file, &base) {
Ok(file) => file,
Err(err) => {
@ -1129,7 +1139,7 @@ impl SimpleMetadata {
continue;
}
};
match map.entry(version.clone()) {
match map.entry(filename.version().clone()) {
std::collections::btree_map::Entry::Occupied(mut entry) => {
entry.get_mut().push(filename, file);
}

View file

@ -1,5 +1,8 @@
use std::str::FromStr;
use uv_distribution_filename::DistFilename;
use uv_normalize::PackageName;
use uv_pep440::Version;
use crate::VariantsJson;
@ -18,12 +21,29 @@ impl IndexEntryFilename {
}
}
pub fn version(&self) -> &Version {
match self {
Self::DistFilename(filename) => filename.version(),
Self::VariantJson(variant_json) => &variant_json.version,
}
}
/// Parse a filename as either a distribution filename or a `variants.json` filename.
#[allow(clippy::manual_map)]
pub fn try_from_normalized_filename(filename: &str) -> Option<Self> {
if let Some(dist_filename) = DistFilename::try_from_normalized_filename(filename) {
Some(Self::DistFilename(dist_filename))
} else if let Some(variant_json) = VariantsJson::try_from_normalized_filename(filename) {
} else if let Ok(variant_json) = VariantsJson::from_str(filename) {
Some(Self::VariantJson(variant_json))
} else {
None
}
}
/// Parse a filename as either a distribution filename or a `variants.json` filename.
pub fn try_from_filename(filename: &str, package_name: &PackageName) -> Option<Self> {
if let Some(dist_filename) = DistFilename::try_from_filename(filename, package_name) {
Some(Self::DistFilename(dist_filename))
} else if let Ok(variant_json) = VariantsJson::from_str(filename) {
Some(Self::VariantJson(variant_json))
} else {
None

View file

@ -1,27 +1,52 @@
use std::str::FromStr;
use std::{fmt::Display, str::FromStr};
use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_normalize::{InvalidNameError, PackageName};
use uv_pep440::{Version, VersionParseError};
#[derive(Debug, thiserror::Error)]
pub enum VariantsJsonError {
#[error("Invalid variants.json filename")]
InvalidFilename,
#[error("Invalid variants.json package name: {0}")]
InvalidName(#[from] InvalidNameError),
#[error("Invalid variants.json version: {0}")]
InvalidVersion(#[from] VersionParseError),
}
/// A `<name>-<version>-variants.json` file.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize,
)]
#[rkyv(derive(Debug))]
pub struct VariantsJson {
pub name: PackageName,
pub version: Version,
}
impl VariantsJson {
impl FromStr for VariantsJson {
type Err = VariantsJsonError;
/// Parse a `<name>-<version>-variants.json` filename.
///
/// name and version must be normalized, i.e., they don't contain dashes.
pub fn try_from_normalized_filename(filename: &str) -> Option<Self> {
let stem = filename.strip_suffix("-variants.json")?;
fn from_str(filename: &str) -> Result<Self, Self::Err> {
let stem = filename
.strip_suffix("-variants.json")
.ok_or(VariantsJsonError::InvalidFilename)?;
let (name, version) = stem.split_once('-')?;
let name = PackageName::from_str(name).ok()?;
let version = Version::from_str(version).ok()?;
let (name, version) = stem
.split_once('-')
.ok_or(VariantsJsonError::InvalidFilename)?;
let name = PackageName::from_str(name)?;
let version = Version::from_str(version)?;
Some(VariantsJson { name, version })
Ok(VariantsJson { name, version })
}
}
impl Display for VariantsJson {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}-{}-variants.json", self.name, self.version)
}
}
@ -31,8 +56,7 @@ mod tests {
#[test]
fn variants_json_parsing() {
let variant =
VariantsJson::try_from_normalized_filename("numpy-1.21.0-variants.json").unwrap();
let variant = VariantsJson::from_str("numpy-1.21.0-variants.json").unwrap();
assert_eq!(variant.name.as_str(), "numpy");
assert_eq!(variant.version.to_string(), "1.21.0");
}

View file

@ -51,7 +51,7 @@ fn clean_package_pypi() -> Result<()> {
// Assert that the `.rkyv` file is created for `iniconfig`.
let rkyv = context
.cache_dir
.child("simple-v16")
.child("simple-v17")
.child("pypi")
.child("iniconfig.rkyv");
assert!(
@ -125,7 +125,7 @@ fn clean_package_index() -> Result<()> {
// Assert that the `.rkyv` file is created for `iniconfig`.
let rkyv = context
.cache_dir
.child("simple-v16")
.child("simple-v17")
.child("index")
.child("e8208120cae3ba69")
.child("iniconfig.rkyv");