From 49879e8f3f917c08550e17d89c90da639d6d1234 Mon Sep 17 00:00:00 2001 From: Giuseppe Di Terlizzi Date: Mon, 16 Dec 2024 22:23:44 +0100 Subject: [PATCH] URI::PackageURL 2.22 - Improved parsing of non-canonical PURL (package-url/purl-spec#363) - Improved "URI::VersionRange->constraint_contains" - Updated "maven" repository URL - FIX typo in documentation - Synced "test-suite-data.json" from "package-url/purl-spec" --- Changes | 7 +++ lib/URI/PackageURL.pm | 22 ++++----- lib/URI/PackageURL/App.pm | 2 +- lib/URI/PackageURL/Util.pm | 28 +++++++----- lib/URI/VersionRange.pm | 18 ++++---- lib/URI/VersionRange/App.pm | 2 +- lib/URI/VersionRange/Constraint.pm | 2 +- t/20-decode.t | 18 +++++++- t/30-util.t | 3 +- t/50-version-range.t | 5 +++ t/test-suite-data.json | 72 ++++++++++++++++++++++++++++++ 11 files changed, 141 insertions(+), 38 deletions(-) diff --git a/Changes b/Changes index b193f03..e0a7980 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,12 @@ Change history for URI-PackageURL +2.22 2024-12-16 + - Improved parsing of non-canonical PURL (package-url/purl-spec#363) + - Improved "URI::VersionRange->constraint_contains" + - Updated "maven" repository URL + - FIX typo in documentation + - Synced "test-suite-data.json" from "package-url/purl-spec" + 2.21 2024-07-24 - Use RFC 2119 terms for CPAN purl type specification (sjn) - Added "swid" purl type support diff --git a/lib/URI/PackageURL.pm b/lib/URI/PackageURL.pm index 5f308df..9e539b2 100644 --- a/lib/URI/PackageURL.pm +++ b/lib/URI/PackageURL.pm @@ -13,7 +13,7 @@ use constant DEBUG => $ENV{PURL_DEBUG}; use overload '""' => 'to_string', fallback => 1; -our $VERSION = '2.21'; +our $VERSION = '2.22'; our @EXPORT = qw(encode_purl decode_purl); my $PURL_REGEXP = qr{^pkg:[A-Za-z\\.\\-\\+][A-Za-z0-9\\.\\-\\+]*/.+}; @@ -80,7 +80,7 @@ sub from_string { # Join segments back with a '/' # This is the subpath - my @s1 = split('#', $string); + my @s1 = split(/#([^#]+)$/, $string); if ($s1[1]) { $s1[1] =~ s/(^\/|\/$)//; @@ -100,7 +100,7 @@ sub from_string { # If the key is checksums, split the value on ',' to create a list of checksums # This list of key/value is the qualifiers object - my @s2 = split(/\?/, $s1[0]); + my @s2 = split(/\?([^\?]+)$/, $s1[0]); if ($s2[1]) { @@ -146,7 +146,7 @@ sub from_string { # UTF-8-decode the version if needed in your programming language # This is the version - my @s5 = split('@', $s4[1]); + my @s5 = split(/@([^@]+)$/, $s4[1]); $components{version} = _url_decode($s5[1]) if ($s5[1]); @@ -283,21 +283,21 @@ URI::PackageURL - Perl extension for Package URL (aka "purl") type => 'cpan', namespace => 'GDT', name => 'URI-PackageURL', - version => '2.21' + version => '2.22' ); - say $purl; # pkg:cpan/GDT/URI-PackageURL@2.20 + say $purl; # pkg:cpan/GDT/URI-PackageURL@2.22 # Parse Package URL string - $purl = URI::PackageURL->from_string('pkg:cpan/GDT/URI-PackageURL@2.20'); + $purl = URI::PackageURL->from_string('pkg:cpan/GDT/URI-PackageURL@2.22'); # exported functions - $purl = decode_purl('pkg:cpan/GDT/URI-PackageURL@2.20'); + $purl = decode_purl('pkg:cpan/GDT/URI-PackageURL@2.22'); say $purl->type; # cpan - $purl_string = encode_purl(type => cpan, name => 'URI::PackageURL', version => '2.21'); - say $purl_string; # pkg:cpan/URI::PackageURL@2.20 + $purl_string = encode_purl(type => cpan, name => 'URI::PackageURL', version => '2.22'); + say $purl_string; # pkg:cpan/URI::PackageURL@2.22 =head1 DESCRIPTION @@ -466,7 +466,7 @@ Helper method for JSON modules (L, L, L, L use Mojo::JSON qw(encode_json); - say encode_json($purl); # {"name":"URI-PackageURL","namespace":"GDT","qualifiers":null,"subpath":null,"type":"cpan","version":"2.20"} + say encode_json($purl); # {"name":"URI-PackageURL","namespace":"GDT","qualifiers":null,"subpath":null,"type":"cpan","version":"2.22"} =item $purl = URI::PackageURL->from_string($purl_string); diff --git a/lib/URI/PackageURL/App.pm b/lib/URI/PackageURL/App.pm index ca2a7ba..75ef7a9 100644 --- a/lib/URI/PackageURL/App.pm +++ b/lib/URI/PackageURL/App.pm @@ -13,7 +13,7 @@ use Data::Dumper (); use URI::PackageURL (); -our $VERSION = '2.21'; +our $VERSION = '2.22'; sub cli_error { my ($error) = @_; diff --git a/lib/URI/PackageURL/Util.pm b/lib/URI/PackageURL/Util.pm index 6114ea2..0f70164 100644 --- a/lib/URI/PackageURL/Util.pm +++ b/lib/URI/PackageURL/Util.pm @@ -7,7 +7,7 @@ use warnings; use Exporter qw(import); -our $VERSION = '2.21'; +our $VERSION = '2.22'; our @EXPORT = qw(purl_to_urls purl_components_normalize); sub purl_components_normalize { @@ -467,12 +467,16 @@ sub _maven_urls { my $purl = shift; - my $namespace = $purl->namespace; - my $name = $purl->name; - my $version = $purl->version; - my $qualifiers = $purl->qualifiers; - my $extension = $qualifiers->{extension} // 'jar'; - my $repo_url = $qualifiers->{repository_url} // 'repo1.maven.org/maven2'; + my $namespace = $purl->namespace; + my $name = $purl->name; + my $version = $purl->version; + my $qualifiers = $purl->qualifiers; + my $extension = $qualifiers->{extension} // 'jar'; + my $repository_url = $qualifiers->{repository_url} // 'https://repo.maven.apache.org/maven2'; + + if ($repository_url !~ /^(http|https):\/\//) { + $repository_url = 'https://' . $repository_url; + } if ($namespace && $name && $version) { @@ -480,7 +484,7 @@ sub _maven_urls { return { repository => "https://mvnrepository.com/artifact/$namespace/$name/$version", - download => "https://$repo_url/$ns_url/$name/$version/$name-$version.$extension" + download => "$repository_url/$ns_url/$name/$version/$name-$version.$extension" }; } @@ -565,7 +569,7 @@ URI::PackageURL::Util - Utility for URI::PackageURL use URI::PackageURL::Util qw(purl_to_urls); - $urls = purl_to_urls('pkg:cpan/GDT/URI-PackageURL@2.20'); + $urls = purl_to_urls('pkg:cpan/GDT/URI-PackageURL@2.22'); $filename = basename($urls->{download}); $ua->mirror($urls->{download}, "/tmp/$filename"); @@ -611,13 +615,13 @@ C, C, C, C, C, C, C, C, (*) Only with B component (**) Only if B qualifier is provided - $urls = purl_to_urls('pkg:cpan/GDT/URI-PackageURL@2.20'); + $urls = purl_to_urls('pkg:cpan/GDT/URI-PackageURL@2.22'); print Dumper($urls); # $VAR1 = { - # 'repository' => 'https://metacpan.org/release/GDT/URI-PackageURL-2.20', - # 'download' => 'http://www.cpan.org/authors/id/G/GD/GDT/URI-PackageURL-2.20.tar.gz' + # 'repository' => 'https://metacpan.org/release/GDT/URI-PackageURL-2.22', + # 'download' => 'http://www.cpan.org/authors/id/G/GD/GDT/URI-PackageURL-2.22.tar.gz' # }; =back diff --git a/lib/URI/VersionRange.pm b/lib/URI/VersionRange.pm index e1ffc5d..ada8e8a 100644 --- a/lib/URI/VersionRange.pm +++ b/lib/URI/VersionRange.pm @@ -18,7 +18,7 @@ use constant FALSE => !!0; use overload '""' => 'to_string', fallback => 1; -our $VERSION = '2.21'; +our $VERSION = '2.22'; our @EXPORT = qw(encode_vers decode_vers); my $VERS_REGEXP = qr{^vers:[a-z\\.\\-\\+][a-z0-9\\.\\-\\+]*/.+}; @@ -178,8 +178,8 @@ sub constraint_contains { return ($v1 != $v2) if ($constraint->comparator eq '!='); return ($v1 <= $v2) if ($constraint->comparator eq '<='); return ($v1 >= $v2) if ($constraint->comparator eq '>='); - return ($v1 > $v2) if ($constraint->comparator eq '<'); - return ($v1 < $v2) if ($constraint->comparator eq '>'); + return ($v1 < $v2) if ($constraint->comparator eq '<'); + return ($v1 > $v2) if ($constraint->comparator eq '>'); return FALSE; @@ -339,11 +339,11 @@ URI::VersionRange - Perl extension for Version Range Specification } # Parse "vers" string - $vers = URI::VersionRange->from_string('vers:cpan/>2.00|<2.20'); + $vers = URI::VersionRange->from_string('vers:cpan/>2.00|<2.22'); # exported functions - $vers = decode_vers('vers:cpan/>2.00|<2.20'); + $vers = decode_vers('vers:cpan/>2.00|<2.22'); say $vers->scheme; # cpan $vers_string = encode_vers(scheme => cpan, constraints => ['>2.00']); @@ -400,9 +400,9 @@ This function call is functionally identical to: =over -=item $vers = URI::VersionRange->new( scheme => STRING, constraints -> ARRAY ) +=item $vers = URI::VersionRange->new( scheme => STRING, constraints => ARRAY ) -Create new B instance using provided C components +Create new B instance using provided C components (scheme, constraints). =item $vers->scheme @@ -418,7 +418,7 @@ C is ARRAY of L object. Check if a version is contained within a range - my $vers = URI::VersionRange::from_string('vers:cpan/>2.00|<2.20'); + my $vers = URI::VersionRange::from_string('vers:cpan/>2.00|<2.22'); if ($vers->contains('2.10')) { say "The version is in range"; @@ -442,7 +442,7 @@ Helper method for JSON modules (L, L, L, L use Mojo::JSON qw(encode_json); - say encode_json($vers); # {"constraints":[{"comparator":">","version":"2.00"},{"comparator":"<","version":"2.20"}],"scheme":"cpan"} + say encode_json($vers); # {"constraints":[{"comparator":">","version":"2.00"},{"comparator":"<","version":"2.22"}],"scheme":"cpan"} =item $vers = URI::VersionRange->from_string($vers_string); diff --git a/lib/URI/VersionRange/App.pm b/lib/URI/VersionRange/App.pm index c28b3ca..ff1adc8 100644 --- a/lib/URI/VersionRange/App.pm +++ b/lib/URI/VersionRange/App.pm @@ -13,7 +13,7 @@ use Data::Dumper (); use URI::VersionRange (); -our $VERSION = '2.21'; +our $VERSION = '2.22'; sub cli_error { my ($error) = @_; diff --git a/lib/URI/VersionRange/Constraint.pm b/lib/URI/VersionRange/Constraint.pm index c8cfc7c..1f8b2e2 100644 --- a/lib/URI/VersionRange/Constraint.pm +++ b/lib/URI/VersionRange/Constraint.pm @@ -12,7 +12,7 @@ use overload '""' => 'to_string', fallback => 1; use URI::VersionRange::Version; -our $VERSION = '2.21'; +our $VERSION = '2.22'; our %COMPARATOR = ( '=' => 'equal', diff --git a/t/20-decode.t b/t/20-decode.t index 3bfb72c..d9354d8 100644 --- a/t/20-decode.t +++ b/t/20-decode.t @@ -7,10 +7,11 @@ use Test::More; use URI::PackageURL; -my $t1 = 'pkg:cpan/GDT/URI-PackageURL@2.00'; +my $t1 = 'pkg:cpan/GDT/URI-PackageURL@2.22'; my $t2 = 'pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie'; my $t3 = 'pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations'; my $t4 = 'pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io'; +my $t5 = 'pkg:generic/ns/n@m#?@version?qualifier=#v@lue#subp@th?'; subtest "Decode '$t1'" => sub { @@ -19,7 +20,7 @@ subtest "Decode '$t1'" => sub { is($purl->type, 'cpan', 'Type'); is($purl->namespace, 'GDT', 'Namespace'); is($purl->name, 'URI-PackageURL', 'Name'); - is($purl->version, '2.00', 'Version'); + is($purl->version, '2.22', 'Version'); is($purl->to_string, $t1, 'PackageURL'); @@ -69,4 +70,17 @@ subtest "Decode '$t4'" => sub { }; +subtest "Decode '$t5'" => sub { + + my $purl = decode_purl($t5); + + is($purl->type, 'generic', 'Type'); + is($purl->namespace, 'ns', 'Namespace'); + is($purl->name, 'n@m#?', 'Name'); + is($purl->version, 'version', 'Version'); + is($purl->qualifiers->{qualifier}, '#v@lue', 'Qualifier "qualifier"'); + is($purl->subpath, 'subp@th?', 'Subpath'); + +}; + done_testing(); diff --git a/t/30-util.t b/t/30-util.t index c593bf8..54a8984 100644 --- a/t/30-util.t +++ b/t/30-util.t @@ -60,7 +60,8 @@ my @tests = ( { purl => 'pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?packaging=sources', repository_url => 'https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-anim/1.9.1', - download_url => 'https://repo1.maven.org/maven2/org/apache/xmlgraphics/batik-anim/1.9.1/batik-anim-1.9.1.jar' + download_url => + 'https://repo.maven.apache.org/maven2/org/apache/xmlgraphics/batik-anim/1.9.1/batik-anim-1.9.1.jar' }, {purl => 'pkg:pypi/django@1.11.1', repository_url => 'https://pypi.org/project/django/1.11.1'}, diff --git a/t/50-version-range.t b/t/50-version-range.t index 4720bf8..2708daf 100644 --- a/t/50-version-range.t +++ b/t/50-version-range.t @@ -44,4 +44,9 @@ foreach (sort keys %TESTS) { is $v1->contains($_), !!1, "$_ version in range ($v1)" for (sort @in_range); is $v1->contains($_), !!0, "$_ version not in range ($v1)" for (sort @not_in_range); +is decode_vers('vers:cpan/contains($_), !!1, "$_ version in range" for (sort @in_range); + +eval { decode_vers('foo:bar