diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-04 14:48:25 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-04 15:44:11 +0900 |
| commit | d4309521f10b6f0090ef2548fb8f241949074e1f (patch) | |
| tree | 3c7fa9049b34e73e9a73e21bf19f8a3674c54c57 /crates/mozart/src/commands/show.rs | |
| parent | a24d6e2f148417b32188cd1e643439a2858f4eac (diff) | |
| download | php-mozart-d4309521f10b6f0090ef2548fb8f241949074e1f.tar.gz php-mozart-d4309521f10b6f0090ef2548fb8f241949074e1f.tar.zst php-mozart-d4309521f10b6f0090ef2548fb8f241949074e1f.zip | |
feat(show): expand license output with name, OSI flag, and URL
Mirror Composer's Command\ShowCommand::printLicenses(): emit one line
per license identifier, expanded to "<full name> (<id>) [(OSI
approved)] <url>" when the id is in the SPDX database, or just the id
otherwise. The URL is built by mozart-spdx-licenses' new
LicenseInfo::url() so the construction lives in the SPDX crate, like
Composer's SpdxLicenses::getLicenseByIdentifier().
Diffstat (limited to 'crates/mozart/src/commands/show.rs')
| -rw-r--r-- | crates/mozart/src/commands/show.rs | 118 |
1 files changed, 95 insertions, 23 deletions
diff --git a/crates/mozart/src/commands/show.rs b/crates/mozart/src/commands/show.rs index c59a595..cf15bb2 100644 --- a/crates/mozart/src/commands/show.rs +++ b/crates/mozart/src/commands/show.rs @@ -671,10 +671,14 @@ fn show_installed_package_detail( Verbosity::Normal, ); - // License - if let Some(licenses) = get_installed_license(pkg) { + // License — one line per identifier, matching Composer's printLicenses. + for license_id in get_installed_licenses(pkg) { console.write_stdout( - &format!("{} : {}", console_format!("<info>license</info>"), licenses), + &format!( + "{} : {}", + console_format!("<info>license</info>"), + format_license_for_show(&license_id), + ), Verbosity::Normal, ); } @@ -1128,16 +1132,18 @@ fn show_locked_package_detail( Verbosity::Normal, ); - // License + // License — one line per identifier, matching Composer's printLicenses. if let Some(ref licenses) = pkg.license { - console.write_stdout( - &format!( - "{} : {}", - console_format!("<info>license</info>"), - licenses.join(", ") - ), - Verbosity::Normal, - ); + for license_id in licenses { + console.write_stdout( + &format!( + "{} : {}", + console_format!("<info>license</info>"), + format_license_for_show(license_id), + ), + Verbosity::Normal, + ); + } } // Homepage @@ -1276,7 +1282,11 @@ fn show_self( ); if let Some(ref license) = root.license { console.write_stdout( - &format!("{} : {}", console_format!("<info>license</info>"), license), + &format!( + "{} : {}", + console_format!("<info>license</info>"), + format_license_for_show(license), + ), Verbosity::Normal, ); } @@ -1875,18 +1885,35 @@ fn get_installed_keywords(pkg: &mozart_registry::installed::InstalledPackageEntr .unwrap_or_default() } -/// Extract license from an InstalledPackageEntry's extra_fields. -fn get_installed_license( - pkg: &mozart_registry::installed::InstalledPackageEntry, -) -> Option<String> { - pkg.extra_fields.get("license").and_then(|v| { - v.as_array().map(|arr| { +/// Extract license identifiers from an InstalledPackageEntry's extra_fields. +fn get_installed_licenses(pkg: &mozart_registry::installed::InstalledPackageEntry) -> Vec<String> { + pkg.extra_fields + .get("license") + .and_then(|v| v.as_array()) + .map(|arr| { arr.iter() - .filter_map(|v| v.as_str()) - .collect::<Vec<_>>() - .join(", ") + .filter_map(|v| v.as_str().map(String::from)) + .collect() }) - }) + .unwrap_or_default() +} + +/// Format a single license identifier for the `show` text output. Mirrors +/// Composer's `Command\ShowCommand::printLicenses()`: +/// * unknown id → just the id +/// * OSI-approved → `<full name> (<id>) (OSI approved) <url>` +/// * otherwise → `<full name> (<id>) <url>` +fn format_license_for_show(license_id: &str) -> String { + match mozart_spdx_licenses::spdx().get_license_by_identifier(license_id) { + None => license_id.to_string(), + Some(info) if info.osi_approved => format!( + "{} ({}) (OSI approved) {}", + info.full_name, + license_id, + info.url(), + ), + Some(info) => format!("{} ({}) {}", info.full_name, license_id, info.url()), + } } /// Extract homepage from an InstalledPackageEntry's extra_fields. @@ -1937,6 +1964,51 @@ fn normalize_version_simple(version: &str) -> String { mod tests { use super::*; + // ── format_license_for_show ───────────────────────────────────────────── + + #[test] + fn test_format_license_for_show_osi_approved() { + let out = format_license_for_show("MIT"); + assert!( + out.contains("MIT License") && out.contains("(MIT)") && out.contains("(OSI approved)"), + "got: {out}", + ); + assert!( + out.contains("https://spdx.org/licenses/MIT.html#licenseText"), + "got: {out}", + ); + } + + #[test] + fn test_format_license_for_show_non_osi() { + // CC-BY-4.0 is in the SPDX list but is not OSI-approved. + let out = format_license_for_show("CC-BY-4.0"); + assert!( + out.contains("(CC-BY-4.0)") && !out.contains("(OSI approved)"), + "got: {out}", + ); + assert!( + out.contains("https://spdx.org/licenses/CC-BY-4.0.html#licenseText"), + "got: {out}", + ); + } + + #[test] + fn test_format_license_for_show_unknown_falls_back_to_id() { + assert_eq!(format_license_for_show("not-a-license"), "not-a-license"); + } + + #[test] + fn test_format_license_for_show_url_uses_canonical_id_casing() { + // Lookup is case-insensitive, but the URL uses the canonical id casing + // from the SPDX database — matching SpdxLicenses::getLicenseByIdentifier. + let out = format_license_for_show("mit"); + assert!( + out.contains("https://spdx.org/licenses/MIT.html#licenseText"), + "got: {out}", + ); + } + // ── format_version ────────────────────────────────────────────────────── #[test] |
