Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions crates/uv-client/src/registry_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;

Expand All @@ -22,7 +21,7 @@ use uv_configuration::KeyringProviderType;
use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
use uv_distribution_types::{
BuiltDist, File, IndexCapabilities, IndexFormat, IndexLocations, IndexMetadataRef,
IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl, Name,
IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl, Name, RegistryBuiltWheel,
};
use uv_git::{GIT_LFS, GitError, GitHttpSettings, GitResolver, Reporter};
use uv_metadata::{read_metadata_async_seek, read_metadata_async_stream};
Expand Down Expand Up @@ -962,7 +961,7 @@ impl RegistryClient {
})?
}
WheelLocation::Url(url) => {
self.wheel_metadata_registry(&wheel.index, &wheel.file, &url, capabilities)
self.wheel_metadata_registry(wheel, &url, capabilities)
.await?
}
}
Expand Down Expand Up @@ -1055,13 +1054,17 @@ impl RegistryClient {
/// Fetch the metadata from a wheel file.
async fn wheel_metadata_registry(
&self,
index: &IndexUrl,
file: &File,
wheel: &RegistryBuiltWheel,
url: &DisplaySafeUrl,
capabilities: &IndexCapabilities,
) -> Result<ResolutionMetadata, Error> {
let RegistryBuiltWheel {
filename,
file,
index,
} = wheel;

// If the metadata file is available at its own url (PEP 658), download it from there.
let filename = WheelFilename::from_str(&file.filename).map_err(ErrorKind::WheelFilename)?;
if file.dist_info_metadata {
let mut url = url.clone();
let path = format!("{}.metadata", url.path());
Expand Down Expand Up @@ -1124,7 +1127,7 @@ impl RegistryClient {
// `.dist-info/METADATA` file from the zip, and if that also fails, download the whole wheel
// into the cache and read from there
self.wheel_metadata_no_pep658(
&filename,
filename,
url,
Some(index),
WheelCache::Index(index),
Expand Down
13 changes: 12 additions & 1 deletion crates/uv-distribution-filename/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ mod splitter;
mod wheel;
mod wheel_tag;

fn normalized_package_name_matches(actual: &str, expected: &PackageName) -> bool {
actual
.bytes()
.map(|byte| match byte {
b'A'..=b'Z' => byte.to_ascii_lowercase(),
b'_' | b'.' => b'-',
_ => byte,
})
.eq(expected.as_ref().bytes())
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum DistFilename {
SourceDistFilename(SourceDistFilename),
Expand All @@ -44,7 +55,7 @@ impl DistFilename {
package_name: &PackageName,
) -> Result<Self, DistFilenameError> {
match DistExtension::from_path(filename) {
Ok(DistExtension::Wheel) => match WheelFilename::from_str(filename) {
Ok(DistExtension::Wheel) => match WheelFilename::from_hint(filename, package_name) {
Ok(filename) => Ok(Self::WheelFilename(filename)),
Err(err) => Err(DistFilenameError::InvalidWheel(err)),
},
Expand Down
13 changes: 1 addition & 12 deletions crates/uv-distribution-filename/src/source_dist.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::{Display, Formatter};
use std::str::FromStr;

use crate::SourceDistExtension;
use crate::{SourceDistExtension, normalized_package_name_matches};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use uv_normalize::{InvalidNameError, PackageName};
Expand Down Expand Up @@ -140,17 +140,6 @@ impl SourceDistFilename {
}
}

fn normalized_package_name_matches(actual: &str, expected: &PackageName) -> bool {
actual
.bytes()
.map(|byte| match byte {
b'A'..=b'Z' => byte.to_ascii_lowercase(),
b'_' | b'.' => b'-',
_ => byte,
})
.eq(expected.as_ref().bytes())
}

impl Display for SourceDistFilename {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
Expand Down
48 changes: 36 additions & 12 deletions crates/uv-distribution-filename/src/wheel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use uv_platform_tags::{

use crate::splitter::MemchrSplitter;
use crate::wheel_tag::{TagSet, WheelTag, WheelTagLarge, WheelTagSmall};
use crate::{BuildTag, BuildTagError};
use crate::{BuildTag, BuildTagError, normalized_package_name_matches};

#[derive(
Debug,
Expand All @@ -41,13 +41,7 @@ impl FromStr for WheelFilename {
type Err = WheelFilenameError;

fn from_str(filename: &str) -> Result<Self, Self::Err> {
let stem = filename.strip_suffix(".whl").ok_or_else(|| {
WheelFilenameError::InvalidWheelFileName(
filename.to_string(),
"Must end with .whl".to_string(),
)
})?;
Self::parse(stem, filename)
Self::parse_filename(filename, None)
}
}

Expand All @@ -64,6 +58,26 @@ impl Display for WheelFilename {
}

impl WheelFilename {
fn parse_filename(
filename: &str,
hint: Option<&PackageName>,
) -> Result<Self, WheelFilenameError> {
let stem = filename.strip_suffix(".whl").ok_or_else(|| {
WheelFilenameError::InvalidWheelFileName(
filename.to_string(),
"Must end with .whl".to_string(),
)
})?;
Self::parse(stem, filename, hint)
}

pub(crate) fn from_hint(
filename: &str,
hint: &PackageName,
) -> Result<Self, WheelFilenameError> {
Self::parse_filename(filename, Some(hint))
}

/// Create a [`WheelFilename`] from its components.
pub fn new(
name: PackageName,
Expand Down Expand Up @@ -161,13 +175,17 @@ impl WheelFilename {
{
return Err(WheelFilenameError::UnexpectedExtension(stem.to_string()));
}
Self::parse(stem, stem)
Self::parse(stem, stem, None)
}

/// Parse a wheel filename from the stem (e.g., `foo-1.2.3-py3-none-any`).
///
/// The originating `filename` is used for high-fidelity error messages.
fn parse(stem: &str, filename: &str) -> Result<Self, WheelFilenameError> {
fn parse(
stem: &str,
filename: &str,
hint: Option<&PackageName>,
) -> Result<Self, WheelFilenameError> {
// The wheel filename should contain either five or six entries. If six, then the third
// entry is the build tag. If five, then the third entry is the Python tag.
// https://www.python.org/dev/peps/pep-0427/#file-name-convention
Expand Down Expand Up @@ -234,8 +252,14 @@ impl WheelFilename {
)
};

let name = PackageName::from_str(name)
.map_err(|err| WheelFilenameError::InvalidPackageName(filename.to_string(), err))?;
let name = if let Some(hint) = hint
&& normalized_package_name_matches(name, hint)
{
hint.clone()
} else {
PackageName::from_str(name)
.map_err(|err| WheelFilenameError::InvalidPackageName(filename.to_string(), err))?
};
let version = Version::from_str(version)
.map_err(|err| WheelFilenameError::InvalidVersion(filename.to_string(), err))?;
let build_tag = build_tag
Expand Down
Loading