1f5d79ea0Sespie# ex:ts=8 sw=4: 2*039cbdaaSespie# $OpenBSD: PkgSpec.pm,v 1.51 2023/06/13 09:07:17 espie Exp $ 3f5d79ea0Sespie# 43ac6f416Sespie# Copyright (c) 2003-2007 Marc Espie <espie@openbsd.org> 5f5d79ea0Sespie# 6f5d79ea0Sespie# Permission to use, copy, modify, and distribute this software for any 7f5d79ea0Sespie# purpose with or without fee is hereby granted, provided that the above 8f5d79ea0Sespie# copyright notice and this permission notice appear in all copies. 9f5d79ea0Sespie# 10f5d79ea0Sespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11f5d79ea0Sespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12f5d79ea0Sespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13f5d79ea0Sespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14f5d79ea0Sespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15f5d79ea0Sespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16f5d79ea0Sespie# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f5d79ea0Sespie 18*039cbdaaSespieuse v5.36; 19f5d79ea0Sespie 20e451b54dSespiepackage OpenBSD::PkgSpec::flavorspec; 21*039cbdaaSespiesub new($class, $spec) 22f5d79ea0Sespie{ 23e451b54dSespie bless \$spec, $class; 24f5d79ea0Sespie} 25f5d79ea0Sespie 26*039cbdaaSespiesub check_1flavor($f, $spec) 27f5d79ea0Sespie{ 284b54d96fSespie for my $flavor (split /\-/o, $spec) { 29f5d79ea0Sespie # must not be here 304b54d96fSespie if ($flavor =~ m/^\!(.*)$/o) { 31a7ceec02Sespie return 0 if $f->{$1}; 32f5d79ea0Sespie # must be here 33f5d79ea0Sespie } else { 344b54d96fSespie return 0 unless $f->{$flavor}; 35f5d79ea0Sespie } 36f5d79ea0Sespie } 37f5d79ea0Sespie return 1; 38f5d79ea0Sespie} 39f5d79ea0Sespie 40*039cbdaaSespiesub match($self, $h) 41f5d79ea0Sespie{ 42f5d79ea0Sespie # check each flavor constraint 434b54d96fSespie for my $c (split /\,/o, $$self) { 444b54d96fSespie if (check_1flavor($h->{flavors}, $c)) { 45f5d79ea0Sespie return 1; 46f5d79ea0Sespie } 47f5d79ea0Sespie } 48f5d79ea0Sespie return 0; 49f5d79ea0Sespie} 50f5d79ea0Sespie 51e451b54dSespiepackage OpenBSD::PkgSpec::exactflavor; 52e451b54dSespieour @ISA = qw(OpenBSD::PkgSpec::flavorspec); 53*039cbdaaSespiesub new($class, $value) 5448b1a19dSespie{ 5548b1a19dSespie bless {map{($_, 1)} split(/\-/, $value)}, $class; 5648b1a19dSespie} 5748b1a19dSespie 58*039cbdaaSespiesub flavor_string($self) 5948b1a19dSespie{ 6048b1a19dSespie return join('-', sort keys %$self); 6148b1a19dSespie} 6248b1a19dSespie 63*039cbdaaSespiesub match($self, $h) 64f5d79ea0Sespie{ 6548b1a19dSespie if ($self->flavor_string eq $h->flavor_string) { 66e451b54dSespie return 1; 67e451b54dSespie } else { 68e451b54dSespie return 0; 69e451b54dSespie } 70e451b54dSespie} 71e451b54dSespie 72e451b54dSespiepackage OpenBSD::PkgSpec::versionspec; 739a76099aSespieour @ISA = qw(OpenBSD::PackageName::version); 749a76099aSespiemy $ops = { 759a76099aSespie '<' => 'lt', 769a76099aSespie '<=' => 'le', 779a76099aSespie '>' => 'gt', 789a76099aSespie '>=' => 'ge', 799a76099aSespie '=' => 'eq' 809a76099aSespie}; 819a76099aSespie 82*039cbdaaSespiesub new($class, $s) 83e451b54dSespie{ 849a76099aSespie my ($op, $version) = ('=', $s); 859a76099aSespie if ($s =~ m/^(\>\=|\>|\<\=|\<|\=)(.*)$/) { 869a76099aSespie ($op, $version) = ($1, $2); 879a76099aSespie } 889a76099aSespie return "OpenBSD::PkgSpec::version::$ops->{$op}"->from_string($version); 89e451b54dSespie} 90e451b54dSespie 91*039cbdaaSespiesub pnum_compare($self, $b) 929a76099aSespie{ 939a76099aSespie if (!defined $self->{p}) { 949a76099aSespie return 0; 959a76099aSespie } else { 969a76099aSespie return $self->SUPER::pnum_compare($b); 979a76099aSespie } 989a76099aSespie} 999a76099aSespie 100*039cbdaaSespiesub is_exact($) 1019a76099aSespie{ 1029a76099aSespie return 0; 1039a76099aSespie} 1049a76099aSespie 1059a76099aSespiepackage OpenBSD::PkgSpec::version::lt; 1069a76099aSespieour @ISA = qw(OpenBSD::PkgSpec::versionspec); 107*039cbdaaSespiesub match($self, $b) 108e451b54dSespie{ 1099a76099aSespie -$self->compare($b->{version}) < 0 ? 1 : 0; 1109a76099aSespie} 111e451b54dSespie 1129a76099aSespiepackage OpenBSD::PkgSpec::version::le; 1139a76099aSespieour @ISA = qw(OpenBSD::PkgSpec::versionspec); 114*039cbdaaSespiesub match($self, $b) 1159a76099aSespie{ 1169a76099aSespie -$self->compare($b->{version}) <= 0 ? 1 : 0; 1179a76099aSespie} 1189a76099aSespie 1199a76099aSespiepackage OpenBSD::PkgSpec::version::gt; 1209a76099aSespieour @ISA = qw(OpenBSD::PkgSpec::versionspec); 121*039cbdaaSespiesub match($self, $b) 1229a76099aSespie{ 1239a76099aSespie -$self->compare($b->{version}) > 0 ? 1 : 0; 1249a76099aSespie} 1259a76099aSespie 1269a76099aSespiepackage OpenBSD::PkgSpec::version::ge; 1279a76099aSespieour @ISA = qw(OpenBSD::PkgSpec::versionspec); 128*039cbdaaSespiesub match($self, $b) 1299a76099aSespie{ 1309a76099aSespie -$self->compare($b->{version}) >= 0 ? 1 : 0; 1319a76099aSespie} 1329a76099aSespie 1339a76099aSespiepackage OpenBSD::PkgSpec::version::eq; 1349a76099aSespieour @ISA = qw(OpenBSD::PkgSpec::versionspec); 135*039cbdaaSespiesub match($self, $b) 1369a76099aSespie{ 1379a76099aSespie -$self->compare($b->{version}) == 0 ? 1 : 0; 1389a76099aSespie} 1399a76099aSespie 140*039cbdaaSespiesub is_exact($) 1419a76099aSespie{ 1429a76099aSespie return 1; 143e451b54dSespie} 144e451b54dSespie 145d348934bSespiepackage OpenBSD::PkgSpec::badspec; 146*039cbdaaSespiesub new($class) 147d348934bSespie{ 148d348934bSespie bless {}, $class; 149d348934bSespie} 150d348934bSespie 151*039cbdaaSespie# $self->match*($list) 152*039cbdaaSespiesub match_ref($, $) 153d348934bSespie{ 154d348934bSespie return (); 155d348934bSespie} 156d348934bSespie 157*039cbdaaSespiesub match_libs_ref($, $) 1588ac01a5dSespie{ 1598ac01a5dSespie return (); 1608ac01a5dSespie} 1618ac01a5dSespie 162*039cbdaaSespiesub match_locations($, $) 163d348934bSespie{ 16467e90883Sespie return []; 165d348934bSespie} 166d348934bSespie 167*039cbdaaSespiesub is_valid($) 168d348934bSespie{ 169d348934bSespie return 0; 170d348934bSespie} 171e451b54dSespie 172e451b54dSespiepackage OpenBSD::PkgSpec::SubPattern; 173e451b54dSespieuse OpenBSD::PackageName; 174e451b54dSespie 175*039cbdaaSespiesub parse($class, $p) 176e451b54dSespie{ 177d348934bSespie my $r = {}; 178d348934bSespie 179415f1c34Sespie # let's try really hard to find the stem and the flavors 1802dadf88dSespie unless ($p =~ m/^ 181a1e0fe66Sespie ([^%]+?) # stem part 1822dadf88dSespie \- 1832dadf88dSespie ( 184a1e0fe66Sespie (?:\>|\>\=|\<\=|\<|\=)?\d[^-%]* # optional op + version 1852dadf88dSespie |\* # or any version 1862dadf88dSespie ) 187d5381c5aSespie (?:\-([^%]*))? # optional flavor part 1882dadf88dSespie $/x) { 189d348934bSespie return undef; 190f5d79ea0Sespie } 191d348934bSespie ($r->{stemspec}, $r->{vspec}, $r->{flavorspec}) = ($1, $2, $3); 192415f1c34Sespie 1932dadf88dSespie $r->{flavorspec} //= ''; 194d348934bSespie $r->{stemspec} =~ s/\./\\\./go; 195d348934bSespie $r->{stemspec} =~ s/\+/\\\+/go; 196d348934bSespie $r->{stemspec} =~ s/\*/\.\*/go; 197d348934bSespie $r->{stemspec} =~ s/\?/\./go; 198d348934bSespie $r->{stemspec} =~ s/^(\\\.libs)\-/$1\\d*\-/go; 199d348934bSespie return $r; 200e451b54dSespie} 201415f1c34Sespie 202*039cbdaaSespiesub add_version_constraints($class, $constraints, $vspec) 203e451b54dSespie{ 204eca3935aSespie # turn the vspec into a list of constraints. 205eca3935aSespie if ($vspec eq '*') { 206eca3935aSespie # non constraint 207eca3935aSespie } else { 208eca3935aSespie for my $c (split /\,/, $vspec) { 209e451b54dSespie push(@$constraints, 210e451b54dSespie OpenBSD::PkgSpec::versionspec->new($c)); 211e451b54dSespie } 212eca3935aSespie } 213eca3935aSespie} 214f5d79ea0Sespie 215*039cbdaaSespiesub add_flavor_constraints($class, $constraints, $flavorspec) 216e451b54dSespie{ 217e451b54dSespie # and likewise for flavors 218e451b54dSespie if ($flavorspec eq '') { 219e451b54dSespie # non constraint 220e451b54dSespie } else { 221e451b54dSespie push(@$constraints, 222e451b54dSespie OpenBSD::PkgSpec::flavorspec->new($flavorspec)); 223e451b54dSespie } 224e451b54dSespie} 225e451b54dSespie 226*039cbdaaSespiesub new($class, $p, $with_partial) 227e451b54dSespie{ 228d348934bSespie my $r = $class->parse($p); 229d348934bSespie if (defined $r) { 230d348934bSespie my $stemspec = $r->{stemspec}; 231e451b54dSespie my $constraints = []; 232d348934bSespie $class->add_version_constraints($constraints, $r->{vspec}); 233d348934bSespie $class->add_flavor_constraints($constraints, $r->{flavorspec}); 234e451b54dSespie 235d348934bSespie my $o = bless { 2368ac01a5dSespie libstem => qr{^\.libs\d*\-$stemspec\-\d.*$}, 237e451b54dSespie }, $class; 238d24f1704Sespie 239d24f1704Sespie if ($with_partial) { 2405f772b88Sespie $o->{fuzzystem} = qr{^(?:partial\-)*$stemspec\-\d.*$}; 241d24f1704Sespie } else { 242d24f1704Sespie $o->{fuzzystem} = qr{^$stemspec\-\d.*$}; 243d24f1704Sespie } 2448f642ffbSespie if (@$constraints != 0) { 2458f642ffbSespie $o->{constraints} = $constraints; 2468f642ffbSespie } 247d348934bSespie if (defined $r->{e}) { 248d348934bSespie $o->{e} = 1; 249d348934bSespie } 250d348934bSespie return $o; 251d348934bSespie } else { 252d348934bSespie return OpenBSD::PkgSpec::badspec->new; 253d348934bSespie } 254e451b54dSespie} 255e451b54dSespie 256*039cbdaaSespiesub match_ref($o, $list) 257e451b54dSespie{ 258f5d79ea0Sespie my @result = (); 259f5d79ea0Sespie # Now, have to extract the version number, and the flavor... 260e451b54dSespieLOOP1: 2611f9ffadcSespie for my $s (grep(/$o->{fuzzystem}/, @$list)) { 262eca3935aSespie my $name = OpenBSD::PackageName->from_string($s); 2638f642ffbSespie if (defined $o->{constraints}) { 264e451b54dSespie for my $c (@{$o->{constraints}}) { 265e451b54dSespie next LOOP1 unless $c->match($name); 266f5d79ea0Sespie } 2678f642ffbSespie } 268cfda5a0cSespie if (wantarray) { 269e451b54dSespie push(@result, $s); 270cfda5a0cSespie } else { 271cfda5a0cSespie return 1; 272cfda5a0cSespie } 273f5d79ea0Sespie } 274f5d79ea0Sespie 2759d478369Sespie if (wantarray) { 276f5d79ea0Sespie return @result; 2779d478369Sespie } else { 2789d478369Sespie return 0; 2799d478369Sespie } 280f5d79ea0Sespie} 281f5d79ea0Sespie 282*039cbdaaSespiesub match_libs_ref($o, $list) 2838ac01a5dSespie{ 2848ac01a5dSespie return grep(/$o->{libstem}/, @$list); 2858ac01a5dSespie} 2868ac01a5dSespie 2878ac01a5dSespie 288*039cbdaaSespiesub match_locations($o, $list) 289e451b54dSespie{ 290e451b54dSespie my $result = []; 291e451b54dSespie # Now, have to extract the version number, and the flavor... 292e451b54dSespieLOOP2: 2935ac93686Sespie for my $s (grep { $_->name =~ m/$o->{fuzzystem}/} @$list) { 294e451b54dSespie my $name = $s->pkgname; 2958f642ffbSespie if (defined $o->{constraints}) { 296e451b54dSespie for my $c (@{$o->{constraints}}) { 297e451b54dSespie next LOOP2 unless $c->match($name); 298e451b54dSespie } 2998f642ffbSespie } 300e451b54dSespie push(@$result, $s); 301e451b54dSespie } 302e451b54dSespie 303e451b54dSespie return $result; 304e451b54dSespie} 305e451b54dSespie 306*039cbdaaSespiesub is_valid($) 307d348934bSespie{ 3084f16f0f9Sespie return 1; 309d348934bSespie} 310d348934bSespie 311e451b54dSespiepackage OpenBSD::PkgSpec; 312*039cbdaaSespiesub subpattern_class($) 313e451b54dSespie{ "OpenBSD::PkgSpec::SubPattern" } 314*039cbdaaSespiesub new($class, $pattern, $with_partial = 0) 315e451b54dSespie{ 316d24f1704Sespie my @l = map { $class->subpattern_class->new($_, $with_partial) } 317e451b54dSespie (split /\|/o, $pattern); 3185ac93686Sespie if (@l == 1) { 3195ac93686Sespie return $l[0]; 3205ac93686Sespie } else { 3215ac93686Sespie return bless \@l, $class; 3225ac93686Sespie } 323e451b54dSespie} 324e451b54dSespie 325*039cbdaaSespiesub match_ref($self, $r) 326e451b54dSespie{ 327cfda5a0cSespie if (wantarray) { 328e451b54dSespie my @l = (); 329e451b54dSespie for my $subpattern (@$self) { 330e451b54dSespie push(@l, $subpattern->match_ref($r)); 331e451b54dSespie } 332e451b54dSespie return @l; 333cfda5a0cSespie } else { 334cfda5a0cSespie for my $subpattern (@$self) { 335cfda5a0cSespie if ($subpattern->match_ref($r)) { 336cfda5a0cSespie return 1; 337cfda5a0cSespie } 338cfda5a0cSespie } 339cfda5a0cSespie return 0; 340cfda5a0cSespie } 341e451b54dSespie} 342e451b54dSespie 343*039cbdaaSespiesub match_libs_ref($self, $r) 3448ac01a5dSespie{ 3458ac01a5dSespie if (wantarray) { 3468ac01a5dSespie my @l = (); 3478ac01a5dSespie for my $subpattern (@$self) { 3488ac01a5dSespie push(@l, $subpattern->match_libs_ref($r)); 3498ac01a5dSespie } 3508ac01a5dSespie return @l; 3518ac01a5dSespie } else { 3528ac01a5dSespie for my $subpattern (@$self) { 3538ac01a5dSespie if ($subpattern->match_libs_ref($r)) { 3548ac01a5dSespie return 1; 3558ac01a5dSespie } 3568ac01a5dSespie } 3578ac01a5dSespie return 0; 3588ac01a5dSespie } 3598ac01a5dSespie} 3608ac01a5dSespie 361*039cbdaaSespiesub match_locations($self, $r) 362e451b54dSespie{ 363e451b54dSespie my $l = []; 364e451b54dSespie for my $subpattern (@$self) { 365e451b54dSespie push(@$l, @{$subpattern->match_locations($r)}); 366e451b54dSespie } 367e451b54dSespie return $l; 368e451b54dSespie} 369e451b54dSespie 370*039cbdaaSespiesub is_valid($self) 371d348934bSespie{ 372d348934bSespie for my $subpattern (@$self) { 373d348934bSespie return 0 unless $subpattern->is_valid; 374d348934bSespie } 375d348934bSespie return 1; 376d348934bSespie} 377d348934bSespie 378e451b54dSespiepackage OpenBSD::PkgSpec::SubPattern::Exact; 379e451b54dSespieour @ISA = qw(OpenBSD::PkgSpec::SubPattern); 380e451b54dSespie 381*039cbdaaSespiesub add_version_constraints($class, $constraints, $vspec) 382e451b54dSespie{ 38341e3defdSespie return if $vspec eq '*'; # XXX 384e451b54dSespie my $v = OpenBSD::PkgSpec::versionspec->new($vspec); 385e47637b9Sespie die "not a good exact spec" if !$v->is_exact; 386e47637b9Sespie delete $v->{p}; 387e451b54dSespie push(@$constraints, $v); 388e451b54dSespie} 389e451b54dSespie 390*039cbdaaSespiesub add_flavor_constraints($class, $constraints, $flavorspec) 391e451b54dSespie{ 392e451b54dSespie push(@$constraints, OpenBSD::PkgSpec::exactflavor->new($flavorspec)); 393e451b54dSespie} 394e451b54dSespie 395e451b54dSespiepackage OpenBSD::PkgSpec::Exact; 396e451b54dSespieour @ISA = qw(OpenBSD::PkgSpec); 397e451b54dSespie 398*039cbdaaSespiesub subpattern_class($) 399e451b54dSespie{ "OpenBSD::PkgSpec::SubPattern::Exact" } 400e451b54dSespie 401f5d79ea0Sespie1; 402