Search.pm revision 1.10
1# ex:ts=8 sw=4:
2# $OpenBSD: Search.pm,v 1.10 2009/04/19 15:18:23 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
18package OpenBSD::Search;
19sub match_locations
20{
21	my ($self, $o) = @_;
22	require OpenBSD::PackageLocation;
23
24	my @l = map {$o->new_location($_)} $self->match($o);
25	return \@l;
26}
27
28# XXX this is not efficient
29sub filter_locations
30{
31	my ($self, $l) = @_;
32	my $r = [];
33	for my $loc (@$l) {
34		if ($self->filter($loc->{name})) {
35			push(@$r, $loc);
36		}
37	}
38	return $r;
39}
40
41package OpenBSD::Search::PkgSpec;
42our @ISA=(qw(OpenBSD::Search));
43
44sub match_ref
45{
46	my ($self, $r) = @_;
47	return $self->{spec}->match_ref($r);
48}
49
50sub match
51{
52	my ($self, $o) = @_;
53	return $self->match_ref($o->list);
54}
55
56sub match_locations
57{
58	my ($self, $o) = @_;
59	return $self->{spec}->match_locations($o->locations_list);
60}
61
62sub filter_locations
63{
64	my ($self, $l) = @_;
65	return $self->{$spec}->match_locations($l);
66}
67
68sub filter
69{
70	my ($self, @list) = @_;
71	return $self->match_ref(\@list);
72}
73
74sub new
75{
76	my ($class, $pattern) = @_;
77	require OpenBSD::PkgSpec;
78
79	bless { spec => $class->spec_class->new($pattern)}, $class;
80}
81
82sub add_pkgpath_hint
83{
84	my ($self, $pkgpath) = @_;
85	$self->{pkgpath} = $pkgpath;
86}
87
88sub spec_class
89{ "OpenBSD::PkgSpec" }
90
91package OpenBSD::Search::Exact;
92our @ISA=(qw(OpenBSD::Search::PkgSpec));
93sub spec_class
94{ "OpenBSD::PkgSpec::Exact" }
95
96package OpenBSD::Search::Stem;
97our @ISA=(qw(OpenBSD::Search));
98
99sub new
100{
101	my ($class, $stem) = @_;
102
103	return bless {stem => $stem}, $class;
104}
105
106sub split
107{
108	my ($class, $pkgname) = @_;
109	require OpenBSD::PackageName;
110
111	return $class->new(OpenBSD::PackageName::splitstem($pkgname));
112}
113
114sub match
115{
116	my ($self, $o) = @_;
117	return $o->stemlist->find($self->{stem});
118}
119
120sub _keep
121{
122	my ($self, $stem) = @_;
123	return $self->{stem} eq $stem;
124}
125
126sub filter
127{
128	my ($self, @l) = @_;
129	my @result = ();
130	require OpenBSD::PackageName;
131	for my $pkg (@l) {
132		if ($self->_keep(OpenBSD::PackageName::splitstem($pkgname))) {
133			push(@result, $pkg);
134		}
135	}
136	return @result;
137}
138
139package OpenBSD::Search::PartialStem;
140our @ISA=(qw(OpenBSD::Search::Stem));
141
142sub match
143{
144	my ($self, $o) = @_;
145	return $o->stemlist->find_partial($self->{stem});
146}
147
148sub _keep
149{
150	my ($self, $stem) = @_;
151	my $partial = $self->{stem};
152	return $stem =~ /\Q$partial\E/;
153}
154
155package OpenBSD::Search::Filter;
156our @ISA=(qw(OpenBSD::Search));
157
158sub new
159{
160	my ($class, $code) = @_;
161
162	return bless {code => $code}, $class;
163}
164
165sub filter
166{
167	my ($self, @l) = @_;
168	return &{$self->{code}}(@l);
169}
170
171package OpenBSD::Search::FilterLocation;
172our @ISA=(qw(OpenBSD::Search));
173sub new
174{
175	my ($class, $code) = @_;
176
177	return bless {code => $code}, $class;
178}
179
180sub filter_locations
181{
182	my ($self, $l) = @_;
183	return &{$self->{code}}($l);
184}
185
186sub keep_most_recent
187{
188	my $class = shift;
189	return $class->new(
190sub {
191	my $l = shift;
192	# no need to filter
193	return $l if @$l <= 1;
194
195	require OpenBSD::PackageName;
196	my $h = {};
197	# we have to prove we have to keep it
198	while (my $e = pop @$l) {
199		my $stem = $e->pkgname->{stem};
200		my $keep = 1;
201		# so let's compare with every element in $h with the same stem
202		for my $f (@{$h->{$e->pkgname->{stem}}}) {
203			# if this is not the same flavors,
204			# we don't filter
205			if ($f->pkgname->flavor_string ne $e->pkgname->flavor_string) {
206				next;
207			}
208			# okay, now we need to prove there's a common pkgpath
209			if (!$e->update_info->match_pkgpath($f->update_info)) {
210				next;
211			}
212
213			if ($f->pkgname->{version}->compare($e->pkgname->{version}) < 0) {
214			    $f = $e;
215			}
216			$keep = 0;
217			last;
218
219		}
220		if ($keep) {
221			push(@{$h->{$e->pkgname->{stem}}}, $e);
222		}
223	}
224	my $largest = [];
225	push @$largest, map {@$_} values %$h;
226	return $largest;
227}
228	);
229}
230
2311;
232