Search.pm revision 1.14
1# ex:ts=8 sw=4: 2# $OpenBSD: Search.pm,v 1.14 2009/11/10 11:36:56 espie Exp $ 3# 4# Copyright (c) 2007 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18use strict; 19use warnings; 20 21package OpenBSD::Search; 22sub match_locations 23{ 24 my ($self, $o) = @_; 25 require OpenBSD::PackageLocation; 26 27 my @l = map {$o->new_location($_)} $self->match($o); 28 return \@l; 29} 30 31# XXX this is not efficient 32sub filter_locations 33{ 34 my ($self, $l) = @_; 35 my $r = []; 36 for my $loc (@$l) { 37 if ($self->filter($loc->{name})) { 38 push(@$r, $loc); 39 } 40 } 41 return $r; 42} 43 44package OpenBSD::Search::PkgSpec; 45our @ISA=(qw(OpenBSD::Search)); 46 47sub match_ref 48{ 49 my ($self, $r) = @_; 50 return $self->{spec}->match_ref($r); 51} 52 53sub match 54{ 55 my ($self, $o) = @_; 56 return $self->match_ref($o->list); 57} 58 59sub match_locations 60{ 61 my ($self, $o) = @_; 62 return $self->{spec}->match_locations($o->locations_list); 63} 64 65sub filter_locations 66{ 67 my ($self, $l) = @_; 68 return $self->{spec}->match_locations($l); 69} 70 71sub filter 72{ 73 my ($self, @list) = @_; 74 return $self->match_ref(\@list); 75} 76 77sub new 78{ 79 my ($class, $pattern) = @_; 80 require OpenBSD::PkgSpec; 81 82 bless { spec => $class->spec_class->new($pattern)}, $class; 83} 84 85sub add_pkgpath_hint 86{ 87 my ($self, $pkgpath) = @_; 88 $self->{pkgpath} = $pkgpath; 89} 90 91sub spec_class 92{ "OpenBSD::PkgSpec" } 93 94package OpenBSD::Search::Exact; 95our @ISA=(qw(OpenBSD::Search::PkgSpec)); 96sub spec_class 97{ "OpenBSD::PkgSpec::Exact" } 98 99package OpenBSD::Search::Stem; 100our @ISA=(qw(OpenBSD::Search)); 101 102sub new 103{ 104 my ($class, $stem) = @_; 105 106 my $flavors; 107 108 if ($stem =~ m/^(.*)\-\-(.*)/) { 109 # XXX 110 return OpenBSD::Search::Exact->new("$1-*-$2"); 111 } 112 return bless {stem => $stem}, $class; 113} 114 115sub split 116{ 117 my ($class, $pkgname) = @_; 118 require OpenBSD::PackageName; 119 120 return $class->new(OpenBSD::PackageName::splitstem($pkgname)); 121} 122 123sub match 124{ 125 my ($self, $o) = @_; 126 return $o->stemlist->find($self->{stem}); 127} 128 129sub _keep 130{ 131 my ($self, $stem) = @_; 132 return $self->{stem} eq $stem; 133} 134 135sub filter 136{ 137 my ($self, @l) = @_; 138 my @result = (); 139 require OpenBSD::PackageName; 140 for my $pkg (@l) { 141 if ($self->_keep(OpenBSD::PackageName::splitstem($pkg))) { 142 push(@result, $pkg); 143 } 144 } 145 return @result; 146} 147 148package OpenBSD::Search::PartialStem; 149our @ISA=(qw(OpenBSD::Search::Stem)); 150 151sub match 152{ 153 my ($self, $o) = @_; 154 return $o->stemlist->find_partial($self->{stem}); 155} 156 157sub _keep 158{ 159 my ($self, $stem) = @_; 160 my $partial = $self->{stem}; 161 return $stem =~ /\Q$partial\E/; 162} 163 164package OpenBSD::Search::Filter; 165our @ISA=(qw(OpenBSD::Search)); 166 167sub new 168{ 169 my ($class, $code) = @_; 170 171 return bless {code => $code}, $class; 172} 173 174sub filter 175{ 176 my ($self, @l) = @_; 177 return &{$self->{code}}(@l); 178} 179 180package OpenBSD::Search::FilterLocation; 181our @ISA=(qw(OpenBSD::Search)); 182sub new 183{ 184 my ($class, $code) = @_; 185 186 return bless {code => $code}, $class; 187} 188 189sub filter_locations 190{ 191 my ($self, $l) = @_; 192 return &{$self->{code}}($l); 193} 194 195sub more_recent_than 196{ 197 my ($class, $name) = @_; 198 require OpenBSD::PackageName; 199 200 my $f = OpenBSD::PackageName->from_string($name); 201 202 return $class->new( 203sub { 204 my $l = shift; 205 my $r = []; 206 for my $e (@$l) { 207 if ($f->{version}->compare($e->pkgname->{version}) <= 0) { 208 push(@$r, $e); 209 } 210 } 211 return $r; 212 }); 213} 214 215sub keep_most_recent 216{ 217 my $class = shift; 218 return $class->new( 219sub { 220 my $l = shift; 221 # no need to filter 222 return $l if @$l <= 1; 223 224 require OpenBSD::PackageName; 225 my $h = {}; 226 # we have to prove we have to keep it 227 while (my $e = pop @$l) { 228 my $stem = $e->pkgname->{stem}; 229 my $keep = 1; 230 # so let's compare with every element in $h with the same stem 231 for my $f (@{$h->{$e->pkgname->{stem}}}) { 232 # if this is not the same flavors, 233 # we don't filter 234 if ($f->pkgname->flavor_string ne $e->pkgname->flavor_string) { 235 next; 236 } 237 # okay, now we need to prove there's a common pkgpath 238 if (!$e->update_info->match_pkgpath($f->update_info)) { 239 next; 240 } 241 242 if ($f->pkgname->{version}->compare($e->pkgname->{version}) < 0) { 243 $f = $e; 244 } 245 $keep = 0; 246 last; 247 248 } 249 if ($keep) { 250 push(@{$h->{$e->pkgname->{stem}}}, $e); 251 } 252 } 253 my $largest = []; 254 push @$largest, map {@$_} values %$h; 255 return $largest; 256} 257 ); 258} 259 2601; 261