From 0d332faf48ec417d2e3d8d1fcc9c89e84a0fec4f Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 17 Dec 2024 22:04:29 +0100 Subject: [PATCH 1/2] Add `Purl::combined_name` method This method adds the inverse of `Purl::builder_with_combined_name`, allowing ecosystem-specific accurate printing of package names with namespaces. --- purl/src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/purl/src/lib.rs b/purl/src/lib.rs index 1bb845c..4a90591 100644 --- a/purl/src/lib.rs +++ b/purl/src/lib.rs @@ -355,6 +355,23 @@ impl Purl { builder } + + /// Combine the namespace and ecosystem in the ecosystem-specific format. + pub fn combined_name(&self) -> Cow<'_, str> { + match self.package_type { + PackageType::Cargo | PackageType::Gem | PackageType::NuGet | PackageType::PyPI => { + self.name().into() + }, + PackageType::Golang | PackageType::Npm => match self.namespace() { + Some(namespace) => Cow::Owned(format!("{}/{}", namespace, self.name())), + None => self.name().into(), + }, + PackageType::Maven => match self.namespace() { + Some(namespace) => Cow::Owned(format!("{}:{}", namespace, self.name())), + None => self.name().into(), + }, + } + } } /// Check whether a package type string is valid according to the rules of the @@ -598,11 +615,18 @@ mod tests { Purl::builder_with_combined_name(PackageType::Npm, "@angular/cli").build().unwrap(); assert_eq!(purl.namespace(), Some("@angular")); assert_eq!(purl.name(), "cli"); + assert_eq!(purl.combined_name(), "@angular/cli"); let purl = Purl::builder_with_combined_name(PackageType::Maven, "org.maven.plugins:pom") .build() .unwrap(); assert_eq!(purl.namespace(), Some("org.maven.plugins")); assert_eq!(purl.name(), "pom"); + assert_eq!(purl.combined_name(), "org.maven.plugins:pom"); + + let purl = Purl::builder_with_combined_name(PackageType::Cargo, "libc").build().unwrap(); + assert_eq!(purl.namespace(), None); + assert_eq!(purl.name(), "libc"); + assert_eq!(purl.combined_name(), "libc"); } } From 170e9fb1c0178be432ea35c218273ffe1c60d6e4 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 17 Dec 2024 22:16:31 +0100 Subject: [PATCH 2/2] Add serde support to `PackageType` This adds both serialization and deserialization to the `PackageType` enum, based on its lowercase representation. --- purl/Cargo.toml | 2 +- purl/src/package_type.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/purl/Cargo.toml b/purl/Cargo.toml index e09a7d4..d42949b 100644 --- a/purl/Cargo.toml +++ b/purl/Cargo.toml @@ -18,7 +18,7 @@ package-type = ["phf", "unicase"] hex = "0.4.3" percent-encoding = "2.2.0" phf = { version = "0.11.1", features = ["macros", "unicase"], optional = true } -serde = { version = "1.0.150", optional = true } +serde = { version = "1.0.150", optional = true, features = ["derive"] } smartstring = { version = "1.0.1", optional = true } thiserror = "1.0.37" unicase = { version = "2.6.0", optional = true } diff --git a/purl/src/package_type.rs b/purl/src/package_type.rs index ecc2f35..ce2f1f3 100644 --- a/purl/src/package_type.rs +++ b/purl/src/package_type.rs @@ -5,6 +5,8 @@ use std::fmt; use std::str::FromStr; use phf::phf_map; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; use unicase::UniCase; use crate::{ @@ -134,6 +136,8 @@ pub type PurlBuilder = GenericPurlBuilder; /// /// This is a subset of the types described in the PURL spec repository. See /// [`Purl`] for details. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[non_exhaustive] pub enum PackageType {