xref: /openbsd-src/usr.sbin/pkg_add/OpenBSD/LibSpec.pm (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1# ex:ts=8 sw=4:
2# $OpenBSD: LibSpec.pm,v 1.16 2014/03/18 18:53:29 espie Exp $
3#
4# Copyright (c) 2010 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::LibObject;
22
23
24sub key
25{
26	my $self = shift;
27	if (defined $self->{dir}) {
28		return "$self->{dir}/$self->{stem}";
29	} else {
30		return $self->{stem};
31	}
32}
33
34sub major
35{
36	my $self = shift;
37	return $self->{major};
38}
39
40sub minor
41{
42	my $self = shift;
43	return $self->{minor};
44}
45
46sub version
47{
48	my $self = shift;
49	return ".".$self->major.".".$self->minor;
50}
51
52sub is_static { 0 }
53
54sub is_valid { 1 }
55
56sub stem
57{
58	my $self = shift;
59	return $self->{stem};
60}
61
62sub badclass
63{
64	"OpenBSD::BadLib";
65}
66
67sub lookup
68{
69	my ($spec, $repo, $base) = @_;
70
71	my $approx = $spec->lookup_stem($repo);
72	if (!defined $approx) {
73		return undef;
74	}
75	my $r = [];
76	for my $c (@$approx) {
77		if ($spec->match($c, $base)) {
78			push(@$r, $c);
79		}
80	}
81	return $r;
82}
83
84package OpenBSD::BadLib;
85our @ISA=qw(OpenBSD::LibObject);
86
87sub to_string
88{
89	my $self = shift;
90	return $$self;
91}
92
93sub new
94{
95	my ($class, $string) = @_;
96	bless \$string, $class;
97}
98
99sub is_valid
100{
101	return 0;
102}
103
104sub lookup_stem
105{
106	return undef;
107}
108
109sub match
110{
111	return 0;
112}
113
114package OpenBSD::LibRepo;
115sub new
116{
117	my $class = shift;
118	bless {}, $class;
119}
120
121sub register
122{
123	my ($repo, $lib, $origin) = @_;
124	$lib->set_origin($origin);
125	push @{$repo->{$lib->stem}}, $lib;
126}
127
128package OpenBSD::Library;
129our @ISA = qw(OpenBSD::LibObject);
130
131sub from_string
132{
133	my ($class, $filename) = @_;
134	if (my ($dir, $stem, $major, $minor) = $filename =~ m/^(.*)\/lib([^\/]+)\.so\.(\d+)\.(\d+)$/o) {
135		bless { dir => $dir, stem => $stem, major => $major,
136		    minor => $minor }, $class;
137	} else {
138		return $class->badclass->new($filename);
139	}
140}
141
142sub to_string
143{
144	my $self = shift;
145	return "$self->{dir}/lib$self->{stem}.so.$self->{major}.$self->{minor}";
146}
147
148sub set_origin
149{
150	my ($self, $origin) = @_;
151	$self->{origin} = $origin;
152	return $self;
153}
154
155sub origin
156{
157	my $self = shift;
158	return $self->{origin};
159}
160
161sub no_match_dispatch
162{
163	my ($library, $spec, $base) = @_;
164	return $spec->no_match_shared($library, $base);
165}
166
167sub is_better
168{
169	my ($self, $other) = @_;
170	if ($other->is_static) {
171		return 1;
172	}
173	if ($self->major > $other->major) {
174		return 1;
175	}
176	if ($self->major == $other->major && $self->minor > $other->minor) {
177		return 1;
178    	}
179	return 0;
180}
181
182package OpenBSD::LibSpec;
183our @ISA = qw(OpenBSD::LibObject);
184
185sub new
186{
187	my ($class, $dir, $stem, $major, $minor) = @_;
188	bless {
189		dir => $dir, stem => $stem,
190		major => $major, minor => $minor
191	    }, $class;
192}
193
194my $cached = {};
195
196sub from_string
197{
198	my ($class, $s) = @_;
199	return $cached->{$s} //= $class->new_from_string($s);
200}
201
202sub new_with_stem
203{
204	my ($class, $stem, $major, $minor) = @_;
205
206	if ($stem =~ m/^(.*)\/([^\/]+)$/o) {
207		return $class->new($1, $2, $major, $minor);
208	} else {
209		return $class->new(undef, $stem, $major, $minor);
210	}
211}
212
213sub new_from_string
214{
215	my ($class, $string) = @_;
216	if (my ($stem, $major, $minor) = $string =~ m/^(.*)\.(\d+)\.(\d+)$/o) {
217		return $class->new_with_stem($stem, $major, $minor);
218	} else {
219		return $class->badclass->new($string);
220	}
221}
222
223sub to_string
224{
225	my $self = shift;
226	return join('.', $self->key, $self->major, $self->minor);
227
228}
229
230sub lookup_stem
231{
232	my ($spec, $repo) = @_;
233
234	my $result = $repo->{$spec->stem};
235	if (!defined $result) {
236		return undef;
237	} else {
238		return $result;
239	}
240}
241
242sub no_match_major
243{
244	my ($spec, $library) = @_;
245	return $spec->major != $library->major;
246}
247
248sub no_match_name
249{
250	my ($spec, $library, $base) = @_;
251
252	if (defined $spec->{dir}) {
253		if ("$base/$spec->{dir}" eq $library->{dir}) {
254			return undef;
255		}
256	} else {
257		for my $d ($base, OpenBSD::Paths->library_dirs) {
258			if ("$d/lib" eq $library->{dir}) {
259				return undef;
260			}
261		}
262	}
263	return "bad directory";
264}
265
266sub no_match_shared
267{
268	my ($spec, $library, $base) = @_;
269
270	if ($spec->no_match_major($library)) {
271		return "bad major";
272	}
273	if ($spec->major == $library->major &&
274	    $spec->minor > $library->minor) {
275		return "minor is too small";
276	}
277	return $spec->no_match_name($library, $base);
278}
279
280# classic double dispatch pattern
281sub no_match
282{
283	my ($spec, $library, $base) = @_;
284	return $library->no_match_dispatch($spec, $base);
285}
286
287sub match
288{
289	my ($spec, $library, $base) = @_;
290	return !$spec->no_match($library, $base);
291}
292
293sub compare
294{
295	my ($a, $b) = @_;
296
297	if ($a->key ne $b->key) {
298		return undef;
299	}
300	if ($a->major != $b->major) {
301		return $a->major <=> $b->major;
302	}
303	return $a->minor <=> $b->minor;
304}
305
3061;
307