mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Add PackageName::validate
This commit is contained in:
parent
3d5f8249ef
commit
ac906c6dc7
1 changed files with 45 additions and 5 deletions
|
@ -1,11 +1,11 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
use crate::dist_info_name::DistInfoName;
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::dist_info_name::DistInfoName;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct PackageName(String);
|
pub struct PackageName(String);
|
||||||
|
|
||||||
|
@ -23,20 +23,37 @@ impl Display for PackageName {
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAME_NORMALIZE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[-_.]+").unwrap());
|
static NAME_NORMALIZE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[-_.]+").unwrap());
|
||||||
|
static NAME_VALIDATE: Lazy<Regex> =
|
||||||
|
Lazy::new(|| Regex::new(r"(?i)^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$").unwrap());
|
||||||
|
|
||||||
|
/// A package name.
|
||||||
|
///
|
||||||
|
/// See:
|
||||||
|
/// - <https://packaging.python.org/en/latest/specifications/name-normalization/>
|
||||||
|
/// - <https://peps.python.org/pep-0508/#names>
|
||||||
|
/// - <https://peps.python.org/pep-0503/#normalized-names>
|
||||||
impl PackageName {
|
impl PackageName {
|
||||||
/// Create a normalized representation of a package name.
|
/// Create a normalized package name without validation.
|
||||||
///
|
///
|
||||||
/// Converts the name to lowercase and collapses any run of the characters `-`, `_` and `.`
|
/// Converts the name to lowercase and collapses any run of the characters `-`, `_` and `.`
|
||||||
/// down to a single `-`, e.g., `---`, `.`, and `__` all get converted to just `-`.
|
/// down to a single `-`, e.g., `---`, `.`, and `__` all get converted to just `-`.
|
||||||
///
|
|
||||||
/// See: <https://packaging.python.org/en/latest/specifications/name-normalization/>
|
|
||||||
pub fn normalize(name: impl AsRef<str>) -> Self {
|
pub fn normalize(name: impl AsRef<str>) -> Self {
|
||||||
// TODO(charlie): Avoid allocating in the common case (when no normalization is required).
|
// TODO(charlie): Avoid allocating in the common case (when no normalization is required).
|
||||||
let mut normalized = NAME_NORMALIZE.replace_all(name.as_ref(), "-").to_string();
|
let mut normalized = NAME_NORMALIZE.replace_all(name.as_ref(), "-").to_string();
|
||||||
normalized.make_ascii_lowercase();
|
normalized.make_ascii_lowercase();
|
||||||
Self(normalized)
|
Self(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a validated, normalized extra name.
|
||||||
|
pub fn validate(name: impl AsRef<str>) -> Result<Self> {
|
||||||
|
if NAME_VALIDATE.is_match(name.as_ref()) {
|
||||||
|
Ok(Self::normalize(name))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Package names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for PackageName {
|
impl AsRef<str> for PackageName {
|
||||||
|
@ -86,4 +103,27 @@ mod tests {
|
||||||
"friendly-bard"
|
"friendly-bard"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate() {
|
||||||
|
// Unchanged
|
||||||
|
assert_eq!(
|
||||||
|
PackageName::validate("friendly-bard").unwrap().as_ref(),
|
||||||
|
"friendly-bard"
|
||||||
|
);
|
||||||
|
assert_eq!(PackageName::validate("1okay").unwrap().as_ref(), "1okay");
|
||||||
|
assert_eq!(PackageName::validate("okay2").unwrap().as_ref(), "okay2");
|
||||||
|
// Normalizes
|
||||||
|
assert_eq!(
|
||||||
|
PackageName::validate("Friendly-Bard").unwrap().as_ref(),
|
||||||
|
"friendly-bard"
|
||||||
|
);
|
||||||
|
// Failures...
|
||||||
|
assert!(PackageName::validate(" starts-with-space").is_err());
|
||||||
|
assert!(PackageName::validate("-starts-with-dash").is_err());
|
||||||
|
assert!(PackageName::validate("ends-with-dash-").is_err());
|
||||||
|
assert!(PackageName::validate("ends-with-space ").is_err());
|
||||||
|
assert!(PackageName::validate("includes!invalid-char").is_err());
|
||||||
|
assert!(PackageName::validate("space in middle").is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue