From c1fb698eae349484d1b809c389223b5f8a763b5b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 10 Oct 2023 19:21:18 -0400 Subject: [PATCH] Add a separate dist-info name struct (#85) --- crates/puffin-cli/src/commands/sync.rs | 2 +- crates/puffin-installer/src/distribution.rs | 5 +- crates/puffin-package/src/dist_info_name.rs | 77 +++++++++++++++++++++ crates/puffin-package/src/lib.rs | 1 + crates/puffin-package/src/package_name.rs | 56 +++++++++++++-- 5 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 crates/puffin-package/src/dist_info_name.rs diff --git a/crates/puffin-cli/src/commands/sync.rs b/crates/puffin-cli/src/commands/sync.rs index c70cb9865..0658214a5 100644 --- a/crates/puffin-cli/src/commands/sync.rs +++ b/crates/puffin-cli/src/commands/sync.rs @@ -215,7 +215,7 @@ pub(crate) async fn sync( printer, " {} {}{}", "+".green(), - wheel.name().white().bold(), + wheel.name().as_ref().white().bold(), format!("@{}", wheel.version()).dimmed() )?; } diff --git a/crates/puffin-installer/src/distribution.rs b/crates/puffin-installer/src/distribution.rs index e27b883b4..d83b6d04b 100644 --- a/crates/puffin-installer/src/distribution.rs +++ b/crates/puffin-installer/src/distribution.rs @@ -5,6 +5,7 @@ use anyhow::{anyhow, Result}; use pep440_rs::Version; use puffin_client::File; +use puffin_package::dist_info_name::DistInfoName; use puffin_package::package_name::PackageName; use wheel_filename::WheelFilename; @@ -77,7 +78,7 @@ impl RemoteDistribution { } pub fn id(&self) -> String { - format!("{}-{}", self.name().replace('-', "_"), self.version()) + format!("{}-{}", DistInfoName::from(self.name()), self.version()) } } @@ -135,6 +136,6 @@ impl LocalDistribution { } pub fn id(&self) -> String { - format!("{}-{}", self.name().replace('-', "_"), self.version()) + format!("{}-{}", DistInfoName::from(self.name()), self.version()) } } diff --git a/crates/puffin-package/src/dist_info_name.rs b/crates/puffin-package/src/dist_info_name.rs new file mode 100644 index 000000000..f3418ab3e --- /dev/null +++ b/crates/puffin-package/src/dist_info_name.rs @@ -0,0 +1,77 @@ +use std::fmt; +use std::fmt::{Display, Formatter}; + +use once_cell::sync::Lazy; +use regex::Regex; + +use crate::package_name::PackageName; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct DistInfoName(String); + +impl Display for DistInfoName { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +static NAME_NORMALIZE: Lazy = Lazy::new(|| Regex::new(r"[-_.]+").unwrap()); + +impl DistInfoName { + /// See: + pub fn normalize(name: impl AsRef) -> Self { + // 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(); + normalized.make_ascii_lowercase(); + Self(normalized) + } +} + +impl AsRef for DistInfoName { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + +impl From<&PackageName> for DistInfoName { + fn from(package_name: &PackageName) -> Self { + Self::normalize(package_name) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn normalize() { + assert_eq!( + DistInfoName::normalize("friendly-bard").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("Friendly-Bard").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("FRIENDLY-BARD").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("friendly.bard").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("friendly_bard").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("friendly--bard").as_ref(), + "friendly_bard" + ); + assert_eq!( + DistInfoName::normalize("FrIeNdLy-._.-bArD").as_ref(), + "friendly_bard" + ); + } +} diff --git a/crates/puffin-package/src/lib.rs b/crates/puffin-package/src/lib.rs index e00867e2a..f35d5d5e6 100644 --- a/crates/puffin-package/src/lib.rs +++ b/crates/puffin-package/src/lib.rs @@ -1,3 +1,4 @@ +pub mod dist_info_name; pub mod metadata; pub mod package_name; pub mod requirements; diff --git a/crates/puffin-package/src/package_name.rs b/crates/puffin-package/src/package_name.rs index 16aa375aa..5781de4bf 100644 --- a/crates/puffin-package/src/package_name.rs +++ b/crates/puffin-package/src/package_name.rs @@ -1,10 +1,11 @@ use std::fmt; use std::fmt::{Display, Formatter}; -use std::ops::Deref; use once_cell::sync::Lazy; use regex::Regex; +use crate::dist_info_name::DistInfoName; + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct PackageName(String); @@ -14,7 +15,7 @@ impl Display for PackageName { } } -static NAME_NORMALIZE: Lazy = Lazy::new(|| Regex::new(r"[-_.]").unwrap()); +static NAME_NORMALIZE: Lazy = Lazy::new(|| Regex::new(r"[-_.]+").unwrap()); impl PackageName { /// See: @@ -26,10 +27,51 @@ impl PackageName { } } -impl Deref for PackageName { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 +impl AsRef for PackageName { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + +impl From for PackageName { + fn from(dist_info_name: DistInfoName) -> Self { + Self::normalize(dist_info_name) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn normalize() { + assert_eq!( + PackageName::normalize("friendly-bard").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("Friendly-Bard").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("FRIENDLY-BARD").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("friendly.bard").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("friendly_bard").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("friendly--bard").as_ref(), + "friendly-bard" + ); + assert_eq!( + PackageName::normalize("FrIeNdLy-._.-bArD").as_ref(), + "friendly-bard" + ); } }