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