Validate package and extra name (#290)

`PackageName` and `ExtraName` can now only be constructed from valid
names. They share the same rules, so i gave them the same
implementation. Constructors are split between `new` (owned) and
`from_str` (borrowed), with the owned version avoiding allocations.

Closes #279

---------

Co-authored-by: Zanie <contact@zanie.dev>
This commit is contained in:
konsti 2023-11-06 11:04:31 +01:00 committed by GitHub
parent ea28b3d0d3
commit 81f380b10e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 258 additions and 171 deletions

View file

@ -4,7 +4,7 @@ use std::str::FromStr;
use thiserror::Error;
use pep440_rs::Version;
use puffin_normalize::PackageName;
use puffin_normalize::{InvalidNameError, PackageName};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SourceDistributionExtension {
@ -71,8 +71,12 @@ impl SourceDistributionFilename {
));
};
let actual_package_name = PackageName::from_str(&stem[..package_name.as_ref().len()])
.map_err(|err| {
SourceDistributionFilenameError::InvalidPackageName(filename.to_string(), err)
})?;
if stem.len() <= package_name.as_ref().len() + "-".len()
|| &PackageName::new(&stem[..package_name.as_ref().len()]) != package_name
|| &actual_package_name != package_name
{
return Err(SourceDistributionFilenameError::InvalidFilename {
filename: filename.to_string(),
@ -109,11 +113,14 @@ pub enum SourceDistributionFilenameError {
InvalidExtension(String),
#[error("Source distribution filename version section is invalid: {0}")]
InvalidVersion(String),
#[error("Source distribution filename has an invalid package name: {0}")]
InvalidPackageName(String, #[source] InvalidNameError),
}
#[cfg(test)]
mod tests {
use puffin_normalize::PackageName;
use std::str::FromStr;
use crate::SourceDistributionFilename;
@ -126,9 +133,12 @@ mod tests {
"foo-lib-1.2.3.tar.gz",
] {
assert_eq!(
SourceDistributionFilename::parse(normalized, &PackageName::new("foo_lib"))
.unwrap()
.to_string(),
SourceDistributionFilename::parse(
normalized,
&PackageName::from_str("foo_lib").unwrap()
)
.unwrap()
.to_string(),
normalized
);
}
@ -137,7 +147,11 @@ mod tests {
#[test]
fn errors() {
for invalid in ["b-1.2.3.zip", "a-1.2.3-gamma.3.zip", "a-1.2.3.tar.zstd"] {
assert!(SourceDistributionFilename::parse(invalid, &PackageName::new("a")).is_err());
assert!(SourceDistributionFilename::parse(
invalid,
&PackageName::from_str("a").unwrap()
)
.is_err());
}
}
}

View file

@ -6,7 +6,7 @@ use url::Url;
use pep440_rs::Version;
use platform_tags::Tags;
use puffin_normalize::PackageName;
use puffin_normalize::{InvalidNameError, PackageName};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct WheelFilename {
@ -87,10 +87,12 @@ impl FromStr for WheelFilename {
)
};
let distribution = PackageName::from_str(distribution)
.map_err(|err| WheelFilenameError::InvalidPackageName(filename.to_string(), err))?;
let version = Version::from_str(version)
.map_err(|err| WheelFilenameError::InvalidVersion(filename.to_string(), err))?;
Ok(WheelFilename {
distribution: PackageName::new(distribution),
distribution,
version,
python_tag: python_tag.split('.').map(String::from).collect(),
abi_tag: abi_tag.split('.').map(String::from).collect(),
@ -165,4 +167,6 @@ pub enum WheelFilenameError {
InvalidWheelFileName(String, String),
#[error("The wheel filename \"{0}\" has an invalid version part: {1}")]
InvalidVersion(String, String),
#[error("The wheel filename \"{0}\" has an invalid package name")]
InvalidPackageName(String, InvalidNameError),
}