Sat Jul 30 10:11:45 2022 UTC ()
lintpkgsrc: add automatic tests

Not sure whether this form of running tests is the idiomatic one, as
lintpkgsrc is not a Perl module but a Perl program, but it works.

The number of planned tests (5 for now) seems to be ignored, no idea
why.


(rillig)
diff -r1.39 -r1.40 pkgsrc/pkgtools/lintpkgsrc/Makefile
diff -r1.34 -r1.35 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl
diff -r0 -r1.1 pkgsrc/pkgtools/lintpkgsrc/files/t/pkgversion.t

cvs diff -r1.39 -r1.40 pkgsrc/pkgtools/lintpkgsrc/Makefile (switch to unified diff)

--- pkgsrc/pkgtools/lintpkgsrc/Makefile 2022/06/28 11:35:24 1.39
+++ pkgsrc/pkgtools/lintpkgsrc/Makefile 2022/07/30 10:11:45 1.40
@@ -1,52 +1,56 @@ @@ -1,52 +1,56 @@
1# $NetBSD: Makefile,v 1.39 2022/06/28 11:35:24 wiz Exp $ 1# $NetBSD: Makefile,v 1.40 2022/07/30 10:11:45 rillig Exp $
2 2
3PKGNAME= lintpkgsrc-4.98 3PKGNAME= lintpkgsrc-4.98
4PKGREVISION= 1 4PKGREVISION= 1
5CATEGORIES= pkgtools 5CATEGORIES= pkgtools
6 6
7MAINTAINER= pkgsrc-users@NetBSD.org 7MAINTAINER= pkgsrc-users@NetBSD.org
8HOMEPAGE= https://www.NetBSD.org/Documentation/pkgsrc/ 8HOMEPAGE= https://www.NetBSD.org/Documentation/pkgsrc/
9COMMENT= Sanity checks on the complete pkgsrc tree 9COMMENT= Sanity checks on the complete pkgsrc tree
10 10
11DEPENDS+= digest>=20010101:../../pkgtools/digest 11DEPENDS+= digest>=20010101:../../pkgtools/digest
12CONFLICTS+= pkglint<4.82 12CONFLICTS+= pkglint<4.82
13 13
14USE_TOOLS+= perl:run 14USE_TOOLS+= perl:run
15 15
16WRKSRC= ${WRKDIR} 16WRKSRC= ${WRKDIR}
17NO_BUILD= yes 
18USE_LANGUAGES= # none 17USE_LANGUAGES= # none
19AUTO_MKDIRS= yes 18AUTO_MKDIRS= yes
20 19
21SUBST_CLASSES+= lp 20SUBST_CLASSES+= lp
22SUBST_STAGE.lp= post-configure 21SUBST_STAGE.lp= post-configure
23SUBST_FILES.lp+= lintpkgsrc.0 lintpkgsrc.1 lintpkgsrc.pl 22SUBST_FILES.lp+= lintpkgsrc.0 lintpkgsrc.1 lintpkgsrc.pl
24.if defined(BATCH) 23SUBST_SED.lp+= -e 's;@PKGSRCDIR@;${BATCH:D/usr/pkgsrc:U${PKGSRCDIR}};g'
25SUBST_SED.lp+= -e 's;@PKGSRCDIR@;/usr/pkgsrc;g' 
26.else 
27SUBST_VARS.lp+= PKGSRCDIR 
28.endif 
29SUBST_VARS.lp+= MAKE 24SUBST_VARS.lp+= MAKE
30SUBST_VARS.lp+= PERL5 25SUBST_VARS.lp+= PERL5
31SUBST_VARS.lp+= PKG_SYSCONFDIR 26SUBST_VARS.lp+= PKG_SYSCONFDIR
32SUBST_VARS.lp+= PREFIX 27SUBST_VARS.lp+= PREFIX
33 28
34.include "../../mk/bsd.prefs.mk" 29.include "../../mk/bsd.prefs.mk"
35 30
36do-extract: 31do-extract:
37 cd ${FILESDIR} && cp lintpkgsrc.* ${WRKSRC}/ 32 cd ${FILESDIR} && cp -R lintpkgsrc.* t ${WRKSRC}/
 33
 34do-build:
 35 # Nothing
 36
 37do-test:
 38 ${RUN} cd ${WRKSRC}/t; \
 39 for test in ./*.t; do \
 40 perl "$$test"; \
 41 done
38 42
39do-install: 43do-install:
40 ${INSTALL_SCRIPT} ${WRKSRC}/lintpkgsrc.pl ${DESTDIR}${PREFIX}/bin/lintpkgsrc 44 ${INSTALL_SCRIPT} ${WRKSRC}/lintpkgsrc.pl ${DESTDIR}${PREFIX}/bin/lintpkgsrc
41.if !empty(MANINSTALL:Mcatinstall) 45.if !empty(MANINSTALL:Mcatinstall)
42. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]) 46. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss])
43 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/lintpkgsrc.1 47 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/lintpkgsrc.1
44. else 48. else
45 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1 49 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1
46. endif 50. endif
47.endif 51.endif
48.if !empty(MANINSTALL:Mmaninstall) 52.if !empty(MANINSTALL:Mmaninstall)
49 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1 53 ${INSTALL_MAN} ${WRKSRC}/lintpkgsrc.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1
50.endif 54.endif
51 55
52.include "../../mk/bsd.pkg.mk" 56.include "../../mk/bsd.pkg.mk"

cvs diff -r1.34 -r1.35 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl (switch to unified diff)

--- pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/07/30 09:37:21 1.34
+++ pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/07/30 10:11:45 1.35
@@ -1,1803 +1,1803 @@ @@ -1,1803 +1,1803 @@
1#!@PERL5@ 1#!@PERL5@
2 2
3# $NetBSD: lintpkgsrc.pl,v 1.34 2022/07/30 09:37:21 rillig Exp $ 3# $NetBSD: lintpkgsrc.pl,v 1.35 2022/07/30 10:11:45 rillig Exp $
4 4
5# Written by David Brownlee <abs@netbsd.org>. 5# Written by David Brownlee <abs@netbsd.org>.
6# 6#
7# Caveats: 7# Caveats:
8# The 'Makefile parsing' algorithm used to obtain package versions and 8# The 'Makefile parsing' algorithm used to obtain package versions and
9# DEPENDS information is geared towards speed rather than perfection, 9# DEPENDS information is geared towards speed rather than perfection,
10# though it has gotten somewhat better over time, it only parses the 10# though it has gotten somewhat better over time, it only parses the
11# simpler Makefile conditionals. 11# simpler Makefile conditionals.
12# 12#
13# TODO: Handle fun DEPENDS like avifile-devel with 13# TODO: Handle fun DEPENDS like avifile-devel with
14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} 14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1}
15 15
16use locale; 16use locale;
17use strict; 17use strict;
18use warnings; 18use warnings;
19use Getopt::Std; 19use Getopt::Std;
20use File::Find; 20use File::Find;
21use File::Basename; 21use File::Basename;
22use IPC::Open3; 22use IPC::Open3;
23use Cwd 'realpath', 'getcwd'; 23use Cwd 'realpath', 'getcwd';
24 24
25# PkgList is the master list of all packages in pkgsrc. 25# PkgList is the master list of all packages in pkgsrc.
26# 26#
27package PkgList; 27package PkgList;
28 28
29sub add($@) { 29sub add($@) {
30 my $self = shift; 30 my $self = shift;
31 31
32 if (!$self->pkgs($_[0])) { 32 if (!$self->pkgs($_[0])) {
33 $self->{_pkgs}{ $_[0] } = new Pkgs $_[0]; 33 $self->{_pkgs}{ $_[0] } = new Pkgs $_[0];
34 } 34 }
35 $self->pkgs($_[0])->add(@_); 35 $self->pkgs($_[0])->add(@_);
36} 36}
37 37
38sub new($) { 38sub new($) {
39 my $class = shift; 39 my $class = shift;
40 my $self = {}; 40 my $self = {};
41 bless $self, $class; 41 bless $self, $class;
42 return $self; 42 return $self;
43} 43}
44 44
45sub numpkgver($) { 45sub numpkgver($) {
46 my $self = shift; 46 my $self = shift;
47 scalar($self->pkgver); 47 scalar($self->pkgver);
48} 48}
49 49
50sub pkgver($@) { 50sub pkgver($@) {
51 my $self = shift; 51 my $self = shift;
52 52
53 if (@_ == 0) { 53 if (@_ == 0) {
54 my (@list); 54 my (@list);
55 foreach my $pkg ($self->pkgs) { 55 foreach my $pkg ($self->pkgs) {
56 push(@list, $pkg->pkgver); 56 push(@list, $pkg->pkgver);
57 } 57 }
58 return (@list); 58 return (@list);
59 } 59 }
60 60
61 if (defined $self->{_pkgs}{$_[0]}) { 61 if (defined $self->{_pkgs}{$_[0]}) {
62 return (@_ > 1) 62 return (@_ > 1)
63 ? $self->{_pkgs}{$_[0]}->pkgver($_[1]) 63 ? $self->{_pkgs}{$_[0]}->pkgver($_[1])
64 : $self->{_pkgs}{$_[0]}->pkgver(); 64 : $self->{_pkgs}{$_[0]}->pkgver();
65 } 65 }
66 return; 66 return;
67} 67}
68 68
69sub pkgs($@) { 69sub pkgs($@) {
70 my $self = shift; 70 my $self = shift;
71 71
72 if (@_) { 72 if (@_) {
73 return $self->{_pkgs}{$_[0]}; 73 return $self->{_pkgs}{$_[0]};
74 } else { 74 } else {
75 return (sort { $a->pkg cmp $b->pkg } values %{$self->{_pkgs}}); 75 return (sort { $a->pkg cmp $b->pkg } values %{$self->{_pkgs}});
76 } 76 }
77} 77}
78 78
79sub store($) { 79sub store($) {
80 my $self = shift; 80 my $self = shift;
81 my @pkgs = keys %{$self->{_pkgs}}; 81 my @pkgs = keys %{$self->{_pkgs}};
82 my ($cnt, $subcnt) = $self->count; 82 my ($cnt, $subcnt) = $self->count;
83 83
84 print("\$pkgcnt = $cnt;\n"); 84 print("\$pkgcnt = $cnt;\n");
85 print("\$subpkgcnt = $subcnt;\n"); 85 print("\$subpkgcnt = $subcnt;\n");
86 map($self->{_pkgs}{$_}->store, keys %{$self->{_pkgs}}); 86 map($self->{_pkgs}{$_}->store, keys %{$self->{_pkgs}});
87} 87}
88 88
89sub count($) { 89sub count($) {
90 my $self = shift; 90 my $self = shift;
91 my ($pkgcnt, $pkgsubcnt); 91 my ($pkgcnt, $pkgsubcnt);
92 92
93 map { 93 map {
94 $pkgcnt++; 94 $pkgcnt++;
95 $pkgsubcnt += $self->{_pkgs}{$_}->count; 95 $pkgsubcnt += $self->{_pkgs}{$_}->count;
96 } keys %{$self->{_pkgs}}; 96 } keys %{$self->{_pkgs}};
97 wantarray ? ($pkgcnt, $pkgsubcnt) : $pkgcnt; 97 wantarray ? ($pkgcnt, $pkgsubcnt) : $pkgcnt;
98} 98}
99 99
100# Pkgs is all versions of a given package (eg: apache-1.x and apache-2.x) 100# Pkgs is all versions of a given package (eg: apache-1.x and apache-2.x)
101# 101#
102package Pkgs; 102package Pkgs;
103 103
104sub add($@) { 104sub add($@) {
105 my $self = shift; 105 my $self = shift;
106 106
107 $self->{_pkgver}{$_[1]} = new PkgVer @_; 107 $self->{_pkgver}{$_[1]} = new PkgVer @_;
108} 108}
109 109
110sub new($@) { 110sub new($@) {
111 my $class = shift; 111 my $class = shift;
112 my $self = {}; 112 my $self = {};
113 113
114 bless $self, $class; 114 bless $self, $class;
115 $self->{_pkg} = $_[0]; 115 $self->{_pkg} = $_[0];
116 return $self; 116 return $self;
117} 117}
118 118
119sub versions($) { 119sub versions($) {
120 my $self = shift; 120 my $self = shift;
121 121
122 return sort { $b cmp $a } keys %{$self->{_pkgver}}; 122 return sort { $b cmp $a } keys %{$self->{_pkgver}};
123} 123}
124 124
125sub pkg($) { 125sub pkg($) {
126 my $self = shift; 126 my $self = shift;
127 $self->{_pkg}; 127 $self->{_pkg};
128} 128}
129 129
130sub pkgver($@) { 130sub pkgver($@) {
131 my $self = shift; 131 my $self = shift;
132 132
133 if (@_) { 133 if (@_) {
134 if ($self->{_pkgver}{$_[0]}) { 134 if ($self->{_pkgver}{$_[0]}) {
135 return ($self->{_pkgver}{$_[0]}); 135 return ($self->{_pkgver}{$_[0]});
136 } 136 }
137 return; 137 return;
138 } 138 }
139 return sort { $b->ver() cmp $a->ver() } values %{$self->{_pkgver}}; 139 return sort { $b->ver() cmp $a->ver() } values %{$self->{_pkgver}};
140} 140}
141 141
142sub latestver($) { 142sub latestver($) {
143 my $self = shift; 143 my $self = shift;
144 144
145 ($self->pkgver())[0]; 145 ($self->pkgver())[0];
146} 146}
147 147
148sub store($) { 148sub store($) {
149 my $self = shift; 149 my $self = shift;
150 150
151 print("\$pkgnum++;\n"); 151 print("\$pkgnum++;\n");
152 map($self->{_pkgver}{$_}->store, keys %{$self->{_pkgver}}); 152 map($self->{_pkgver}{$_}->store, keys %{$self->{_pkgver}});
153} 153}
154 154
155sub count($) { 155sub count($) {
156 my $self = shift; 156 my $self = shift;
157 157
158 scalar(keys %{$self->{_pkgver}}); 158 scalar(keys %{$self->{_pkgver}});
159} 159}
160 160
161# PkgVer is a unique package+version 161# PkgVer is a unique package+version
162# 162#
163package PkgVer; 163package PkgVer;
164 164
165sub new($$$) { 165sub new($$$) {
166 my $class = shift; 166 my $class = shift;
167 my $self = {}; 167 my $self = {};
168 168
169 bless $self, $class; 169 bless $self, $class;
170 $self->{_pkg} = $_[0]; 170 $self->{_pkg} = $_[0];
171 $self->{_ver} = $_[1]; 171 $self->{_ver} = $_[1];
172 return $self; 172 return $self;
173} 173}
174 174
175sub pkgname($) { 175sub pkgname($) {
176 my $self = shift; 176 my $self = shift;
177 177
178 $self->pkg . '-' . $self->ver; 178 $self->pkg . '-' . $self->ver;
179} 179}
180 180
181sub pkg($) { 181sub pkg($) {
182 my $self = shift; 182 my $self = shift;
183 183
184 $self->{_pkg}; 184 $self->{_pkg};
185} 185}
186 186
187sub var($$$) { 187sub var($$$) {
188 my $self = shift; 188 my $self = shift;
189 my ($key, $val) = @_; 189 my ($key, $val) = @_;
190 190
191 (defined $val) 191 (defined $val)
192 ? ($self->{$key} = $val) 192 ? ($self->{$key} = $val)
193 : $self->{$key}; 193 : $self->{$key};
194} 194}
195 195
196sub ver($) { 196sub ver($) {
197 my $self = shift; 197 my $self = shift;
198 198
199 $self->{_ver}; 199 $self->{_ver};
200} 200}
201 201
202sub vars($) { 202sub vars($) {
203 my $self = shift; 203 my $self = shift;
204 204
205 grep(!/^_(pkg|ver)$/, keys %{$self}); 205 grep(!/^_(pkg|ver)$/, keys %{$self});
206} 206}
207 207
208sub store($) { 208sub store($) {
209 my $self = shift; 209 my $self = shift;
210 my $data; 210 my $data;
211 211
212 ($data = $self->{_pkg}) =~ s/([\\\$\@\%\"])/\\$1/g; 212 ($data = $self->{_pkg}) =~ s/([\\\$\@\%\"])/\\$1/g;
213 print("\$pkgver = \$pkglist->add(\"$data\", \""); 213 print("\$pkgver = \$pkglist->add(\"$data\", \"");
214 214
215 ($data = $self->{_ver}) =~ s/([\\\$\@\%\"])/\\$1/g; 215 ($data = $self->{_ver}) =~ s/([\\\$\@\%\"])/\\$1/g;
216 print("$data\"); __pkgcount(1);\n"); 216 print("$data\"); __pkgcount(1);\n");
217 217
218 foreach ($self->vars) { 218 foreach ($self->vars) {
219 ($data = $self->{$_}) =~ s/([\\\$\@\%\"])/\\$1/g; 219 ($data = $self->{$_}) =~ s/([\\\$\@\%\"])/\\$1/g;
220 print("\$pkgver->var(\"$_\", \"$data\");\n"); 220 print("\$pkgver->var(\"$_\", \"$data\");\n");
221 } 221 }
222} 222}
223 223
224package main; 224package main;
225 225
226# Buildtime configuration 226# Buildtime configuration
227my $conf_make = '@MAKE@'; 227my $conf_make = '@MAKE@';
228my $conf_pkgsrcdir = '@PKGSRCDIR@'; 228my $conf_pkgsrcdir = '@PKGSRCDIR@';
229my $conf_prefix = '@PREFIX@'; 229my $conf_prefix = '@PREFIX@';
230my $conf_sysconfdir = '@PKG_SYSCONFDIR@'; 230my $conf_sysconfdir = '@PKG_SYSCONFDIR@';
231 231
232my ( 232my (
233 $pkglist, # list of Pkg packages 233 $pkglist, # list of Pkg packages
234 $pkg_installver, # installed version of pkg_install pseudo-pkg 234 $pkg_installver, # installed version of pkg_install pseudo-pkg
235 $default_vars, # Set for Makefiles, inc PACKAGES & PKGSRCDIR 235 $default_vars, # Set for Makefiles, inc PACKAGES & PKGSRCDIR
236 %opt, # Command line options 236 %opt, # Command line options
237 @matched_prebuiltpackages, # List of obsolete prebuilt package paths 237 @matched_prebuiltpackages, # List of obsolete prebuilt package paths
238 @prebuilt_pkgdirs, # Use to follow symlinks in prebuilt pkgdirs 238 @prebuilt_pkgdirs, # Use to follow symlinks in prebuilt pkgdirs
239 %prebuilt_pkgdir_cache, # To avoid symlink loops in prebuilt_pkgdirs 239 %prebuilt_pkgdir_cache, # To avoid symlink loops in prebuilt_pkgdirs
240); 240);
241 241
242# Horrible kludge to ensure we have a value for testing in conditionals, but 242# Horrible kludge to ensure we have a value for testing in conditionals, but
243# gets removed in the final evaluation 243# gets removed in the final evaluation
244my $magic_undefined = 'M_a_G_i_C_uNdEfInEd'; 244my $magic_undefined = 'M_a_G_i_C_uNdEfInEd';
245 245
246sub debug(@) { 246sub debug(@) {
247 247
248 ($opt{D}) && print STDERR 'DEBUG: ', @_; 248 ($opt{D}) && print STDERR 'DEBUG: ', @_;
249} 249}
250 250
251sub verbose(@) { 251sub verbose(@) {
252 252
253 if (-t STDERR) { 253 if (-t STDERR) {
254 print STDERR @_; 254 print STDERR @_;
255 } 255 }
256} 256}
257 257
258sub fail($) { 258sub fail($) {
259 259
260 print STDERR shift(), "\n"; 260 print STDERR shift(), "\n";
261 exit(3); 261 exit(3);
262} 262}
263 263
264# List (recursive) non directory contents of specified directory 264# List (recursive) non directory contents of specified directory
265# 265#
266#TODO this entire sub should be replaced with direct calls to 266#TODO this entire sub should be replaced with direct calls to
267# File::Find 267# File::Find
268sub listdir($$); 268sub listdir($$);
269sub listdir($$) { 269sub listdir($$) {
270 my ($base, $dir) = @_; 270 my ($base, $dir) = @_;
271 my ($thisdir); 271 my ($thisdir);
272 my (@list, @thislist); 272 my (@list, @thislist);
273 273
274 $thisdir = $base; 274 $thisdir = $base;
275 if (defined($dir)) { 275 if (defined($dir)) {
276 $thisdir .= "/$dir"; 276 $thisdir .= "/$dir";
277 $dir .= '/'; 277 $dir .= '/';
278 } else { 278 } else {
279 $dir = ''; 279 $dir = '';
280 } 280 }
281 281
282 opendir(DIR, $thisdir) || fail("Unable to opendir($thisdir): $!"); 282 opendir(DIR, $thisdir) || fail("Unable to opendir($thisdir): $!");
283 @thislist = grep(substr($_, 0, 1) ne '.' && $_ ne 'CVS', readdir(DIR)); 283 @thislist = grep(substr($_, 0, 1) ne '.' && $_ ne 'CVS', readdir(DIR));
284 closedir(DIR); 284 closedir(DIR);
285 foreach my $entry (@thislist) { 285 foreach my $entry (@thislist) {
286 if (-d "$thisdir/$entry") { 286 if (-d "$thisdir/$entry") {
287 push(@list, listdir($base, "$dir$entry")); 287 push(@list, listdir($base, "$dir$entry"));
288 } else { 288 } else {
289 push(@list, "$dir$entry"); 289 push(@list, "$dir$entry");
290 } 290 }
291 } 291 }
292 @list; 292 @list;
293} 293}
294 294
295sub canonicalize_pkgname($) { 295sub canonicalize_pkgname($) {
296 my ($pkgname) = @_; 296 my ($pkgname) = @_;
297 297
298 $pkgname =~ s,^py\d+(?:pth|)-,py-,; 298 $pkgname =~ s,^py\d+(?:pth|)-,py-,;
299 $pkgname =~ s,^ruby\d+-,ruby-,; 299 $pkgname =~ s,^ruby\d+-,ruby-,;
300 $pkgname =~ s,^php\d+-,php-,; 300 $pkgname =~ s,^php\d+-,php-,;
301 return $pkgname; 301 return $pkgname;
302} 302}
303 303
304sub convert_to_standard_pkgversion(@) { 304sub convert_to_standard_pkgversion(@) {
305 my ($elem, $underscore, @temp); 305 my ($elem, @temp);
306 306
307 # See pkg_install/lib/dewey.c. 307 # See pkg_install/lib/dewey.c.
308 # 'nb' has already been handled when we are here. 308 # 'nb' has already been handled when we are here.
309 foreach $elem (@_) { 309 foreach $elem (@_) {
310 if ($elem =~ /\d/) { 310 if ($elem =~ /\d/) {
311 push(@temp, $elem); 311 push(@temp, $elem);
312 } elsif ($elem eq "pl" || $elem eq "." || $elem eq "_") { 312 } elsif ($elem eq "pl" || $elem eq "." || $elem eq "_") {
313 push(@temp, 0); 313 push(@temp, 0);
314 } elsif ($elem eq "pre" || $elem eq "rc") { 314 } elsif ($elem eq "pre" || $elem eq "rc") {
315 push(@temp, -1); 315 push(@temp, -1);
316 } elsif ($elem eq "beta") { 316 } elsif ($elem eq "beta") {
317 push(@temp, -2); 317 push(@temp, -2);
318 } elsif ($elem eq "alpha") { 318 } elsif ($elem eq "alpha") {
319 push(@temp, -3); 319 push(@temp, -3);
320 } else { 320 } else {
321 push(@temp, 0); 321 push(@temp, 0);
322 push(@temp, ord($elem) - ord("a") + 1); 322 push(@temp, ord($elem) - ord("a") + 1);
323 } 323 }
324 } 324 }
325 @temp; 325 @temp;
326} 326}
327 327
328sub pkgversioncmp_extract($$) { 328sub pkgversioncmp_extract($$) {
329 my ($match, $val) = @_; 329 my ($match, $val) = @_;
330 my ($cmp, @matchlist, @vallist); 330 my ($cmp, @matchlist, @vallist);
331 331
332 @matchlist = convert_to_standard_pkgversion(split(/(\D+)/, lc($match))); 332 @matchlist = convert_to_standard_pkgversion(split(/(\D+)/, lc($match)));
333 @vallist = convert_to_standard_pkgversion(split(/(\D+)/, lc($val))); 333 @vallist = convert_to_standard_pkgversion(split(/(\D+)/, lc($val)));
334 $cmp = 0; 334 $cmp = 0;
335 while ($cmp == 0 && (@matchlist || @vallist)) { 335 while ($cmp == 0 && (@matchlist || @vallist)) {
336 $cmp = ((shift @matchlist || 0) <=> (shift @vallist || 0)); 336 $cmp = ((shift @matchlist || 0) <=> (shift @vallist || 0));
337 } 337 }
338 $cmp; 338 $cmp;
339} 339}
340 340
341# Package version number matching. 341# Package version number matching.
342# Also handles 'nb<N>' suffix (checked iff values otherwise identical). 342# Also handles 'nb<N>' suffix (checked iff values otherwise identical).
343sub pkgversioncmp($$$) { 343sub pkgversioncmp($$$) {
344 my ($match, $test, $val) = @_; 344 my ($match, $test, $val) = @_;
345 my ($cmp, $match_nb, $val_nb); 345 my ($cmp, $match_nb, $val_nb);
346 346
347 $match_nb = $val_nb = 0; 347 $match_nb = $val_nb = 0;
348 if ($match =~ /(.*)nb(.*)/) { 348 if ($match =~ /(.*)nb(.*)/) {
349 # Handle nb<N> suffix 349 # Handle nb<N> suffix
350 $match = $1; 350 $match = $1;
351 $match_nb = $2; 351 $match_nb = $2;
352 } 352 }
353 353
354 if ($val =~ /(.*)nb(.*)/) { 354 if ($val =~ /(.*)nb(.*)/) {
355 # Handle nb<N> suffix 355 # Handle nb<N> suffix
356 $val = $1; 356 $val = $1;
357 $val_nb = $2; 357 $val_nb = $2;
358 } 358 }
359 359
360 $cmp = pkgversioncmp_extract($match, $val); 360 $cmp = pkgversioncmp_extract($match, $val);
361 361
362 if (!$cmp) { 362 if (!$cmp) {
363 # Iff otherwise identical, check nb suffix 363 # Iff otherwise identical, check nb suffix
364 $cmp = pkgversioncmp_extract($match_nb, $val_nb); 364 $cmp = pkgversioncmp_extract($match_nb, $val_nb);
365 } 365 }
366 366
367 debug("eval pkgversioncmp $cmp $test 0\n"); 367 debug("eval pkgversioncmp $cmp $test 0\n");
368 eval "$cmp $test 0"; 368 eval "$cmp $test 0";
369} 369}
370 370
371sub parse_expand_vars($$) { 371sub parse_expand_vars($$) {
372 my ($line, $vars) = @_; 372 my ($line, $vars) = @_;
373 373
374 while ($line =~ /\$\{([-\w.]+)\}/) { 374 while ($line =~ /\$\{([-\w.]+)\}/) {
375 if (defined(${$vars}{$1})) { 375 if (defined(${$vars}{$1})) {
376 $line = $` . ${$vars}{$1} . $'; 376 $line = $` . ${$vars}{$1} . $';
377 } else { 377 } else {
378 $line = $` . $magic_undefined . $'; 378 $line = $` . $magic_undefined . $';
379 } 379 }
380 } 380 }
381 $line; 381 $line;
382} 382}
383 383
384sub parse_eval_make_false($$) { 384sub parse_eval_make_false($$) {
385 my ($line, $vars) = @_; 385 my ($line, $vars) = @_;
386 my ($false, $test); 386 my ($false, $test);
387 387
388 $false = 0; 388 $false = 0;
389 $test = parse_expand_vars($line, $vars); 389 $test = parse_expand_vars($line, $vars);
390 390
391 # XXX This is _so_ wrong - need to parse this correctly 391 # XXX This is _so_ wrong - need to parse this correctly
392 $test =~ s/""/\r/g; 392 $test =~ s/""/\r/g;
393 $test =~ s/"//g; # " 393 $test =~ s/"//g; # "
394 $test =~ s/\r/""/g; 394 $test =~ s/\r/""/g;
395 395
396 debug("conditional: $test\n"); 396 debug("conditional: $test\n");
397 397
398 # XXX Could do something with target 398 # XXX Could do something with target
399 while ($test =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/) { 399 while ($test =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/) {
400 my $testname = $1; 400 my $testname = $1;
401 my $varname = $2; 401 my $varname = $2;
402 my $var; 402 my $var;
403 403
404 # Implement (some of) make's :M modifier 404 # Implement (some of) make's :M modifier
405 if ($varname =~ /^([^:]+):M(.+)$/) { 405 if ($varname =~ /^([^:]+):M(.+)$/) {
406 $varname = $1; 406 $varname = $1;
407 my $match = $2; 407 my $match = $2;
408 408
409 $var = $${vars}{$varname}; 409 $var = $${vars}{$varname};
410 $var = parse_expand_vars($var, $vars) 410 $var = parse_expand_vars($var, $vars)
411 if defined $var; 411 if defined $var;
412 412
413 $match =~ s/([{.+])/\\$1/g; 413 $match =~ s/([{.+])/\\$1/g;
414 $match =~ s/\*/.*/g; 414 $match =~ s/\*/.*/g;
415 $match =~ s/\?/./g; 415 $match =~ s/\?/./g;
416 $match = '^' . $match . '$'; 416 $match = '^' . $match . '$';
417 $var = ($var =~ /$match/) 417 $var = ($var =~ /$match/)
418 if defined $var; 418 if defined $var;
419 } else { 419 } else {
420 $var = $${vars}{$varname}; 420 $var = $${vars}{$varname};
421 $var = parse_expand_vars($var, $vars) 421 $var = parse_expand_vars($var, $vars)
422 if defined $var; 422 if defined $var;
423 } 423 }
424 424
425 if (defined $var && $var eq $magic_undefined) { 425 if (defined $var && $var eq $magic_undefined) {
426 $var = undef; 426 $var = undef;
427 } 427 }
428 428
429 if ($testname eq 'exists') { 429 if ($testname eq 'exists') {
430 $_ = (-e $varname) ? 1 : 0; 430 $_ = (-e $varname) ? 1 : 0;
431 431
432 } elsif ($testname eq 'defined') { 432 } elsif ($testname eq 'defined') {
433 $_ = defined($var) ? 1 : 0; 433 $_ = defined($var) ? 1 : 0;
434 434
435 } elsif ($testname eq 'empty') { 435 } elsif ($testname eq 'empty') {
436 $_ = ((not defined($var) or (length($var) == 0)) ? 1 : 0); 436 $_ = ((not defined($var) or (length($var) == 0)) ? 1 : 0);
437 437
438 } else { 438 } else {
439 $_ = 0; 439 $_ = 0;
440 } 440 }
441 441
442 $test =~ s/$testname\s*\([^()]+\)/$_/; 442 $test =~ s/$testname\s*\([^()]+\)/$_/;
443 debug("conditional: update to $test\n"); 443 debug("conditional: update to $test\n");
444 } 444 }
445 445
446 while ($test =~ /([^\s()\|\&]+)\s+(!=|==)\s+([^\s()]+)/) { 446 while ($test =~ /([^\s()\|\&]+)\s+(!=|==)\s+([^\s()]+)/) {
447 if ($2 eq '==') { 447 if ($2 eq '==') {
448 $_ = ($1 eq $3) ? 1 : 0; 448 $_ = ($1 eq $3) ? 1 : 0;
449 } else { 449 } else {
450 $_ = ($1 ne $3) ? 1 : 0; 450 $_ = ($1 ne $3) ? 1 : 0;
451 } 451 }
452 $test =~ s/[^\s()\|\&]+\s+(!=|==)\s+[^\s()]+/$_/; 452 $test =~ s/[^\s()\|\&]+\s+(!=|==)\s+[^\s()]+/$_/;
453 } 453 }
454 454
455 if ($test !~ /[^<>\d()\s&|.!]/) { 455 if ($test !~ /[^<>\d()\s&|.!]/) {
456 debug("eval test $test\n"); 456 debug("eval test $test\n");
457 $false = eval "($test)?0:1"; 457 $false = eval "($test)?0:1";
458 if (!defined $false) { 458 if (!defined $false) {
459 fail("Eval failed $line - $test"); 459 fail("Eval failed $line - $test");
460 } 460 }
461 debug("conditional: evaluated to " . ($false ? 0 : 1) . "\n"); 461 debug("conditional: evaluated to " . ($false ? 0 : 1) . "\n");
462 462
463 } else { 463 } else {
464 $false = 0; 464 $false = 0;
465 debug("conditional: defaulting to 0\n"); 465 debug("conditional: defaulting to 0\n");
466 } 466 }
467 $false; 467 $false;
468} 468}
469 469
470# Extract variable assignments from Makefile 470# Extract variable assignments from Makefile
471# Much unpalatable magic to avoid having to use make (all for speed) 471# Much unpalatable magic to avoid having to use make (all for speed)
472# 472#
473sub parse_makefile_vars($$) { 473sub parse_makefile_vars($$) {
474 my ($file, $cwd) = @_; 474 my ($file, $cwd) = @_;
475 my ( 475 my (
476 $pkgname, %vars, $plus, $value, @data, 476 $pkgname, %vars, $plus, $value, @data,
477 %incfiles, # Cache of previously included fils 477 %incfiles, # Cache of previously included fils
478 %incdirs, # Directories in which to check for includes 478 %incdirs, # Directories in which to check for includes
479 @if_false 479 @if_false
480 ); # 0:true 1:false 2:nested-false&nomore-elsif 480 ); # 0:true 1:false 2:nested-false&nomore-elsif
481 481
482 if (!open(FILE, $file)) { 482 if (!open(FILE, $file)) {
483 return (undef); 483 return (undef);
484 } 484 }
485 @data = map { chomp; 485 @data = map { chomp;
486 $_; } <FILE>; 486 $_; } <FILE>;
487 close(FILE); 487 close(FILE);
488 488
489 $incdirs{"."} = 1; 489 $incdirs{"."} = 1;
490 $incdirs{dirname($file)} = 1; 490 $incdirs{dirname($file)} = 1;
491 491
492 # Some Makefiles depend on these being set 492 # Some Makefiles depend on these being set
493 if ($file eq '/etc/mk.conf') { 493 if ($file eq '/etc/mk.conf') {
494 $vars{LINTPKGSRC} = 'YES'; 494 $vars{LINTPKGSRC} = 'YES';
495 } else { 495 } else {
496 %vars = %{$default_vars}; 496 %vars = %{$default_vars};
497 } 497 }
498 $vars{BSD_PKG_MK} = 'YES'; 498 $vars{BSD_PKG_MK} = 'YES';
499 499
500 if ($cwd) { 500 if ($cwd) {
501 $vars{'.CURDIR'} = $cwd; 501 $vars{'.CURDIR'} = $cwd;
502 } elsif ($file =~ m#(.*)/#) { 502 } elsif ($file =~ m#(.*)/#) {
503 $vars{'.CURDIR'} = $1; 503 $vars{'.CURDIR'} = $1;
504 } else { 504 } else {
505 $vars{'.CURDIR'} = getcwd; 505 $vars{'.CURDIR'} = getcwd;
506 } 506 }
507 507
508 $incdirs{$vars{'.CURDIR'}} = 1; 508 $incdirs{$vars{'.CURDIR'}} = 1;
509 if ($opt{L}) { 509 if ($opt{L}) {
510 print "$file\n"; 510 print "$file\n";
511 } 511 }
512 512
513 while (defined($_ = shift(@data))) { 513 while (defined($_ = shift(@data))) {
514 s/\s*[^\\]#.*//; 514 s/\s*[^\\]#.*//;
515 515
516 # Continuation lines 516 # Continuation lines
517 # 517 #
518 while (substr($_, -1) eq "\\") { 518 while (substr($_, -1) eq "\\") {
519 substr($_, -2) = shift @data; 519 substr($_, -2) = shift @data;
520 } 520 }
521 521
522 # Conditionals 522 # Conditionals
523 # 523 #
524 if (m#^\.\s*if(|def|ndef)\s+(.*)#) { 524 if (m#^\.\s*if(|def|ndef)\s+(.*)#) {
525 my ($type, $false); 525 my ($type, $false);
526 526
527 $type = $1; 527 $type = $1;
528 if ($if_false[$#if_false]) { 528 if ($if_false[$#if_false]) {
529 push(@if_false, 2); 529 push(@if_false, 2);
530 530
531 } elsif ($type eq '') { 531 } elsif ($type eq '') {
532 # Straight if 532 # Straight if
533 push(@if_false, parse_eval_make_false($2, \%vars)); 533 push(@if_false, parse_eval_make_false($2, \%vars));
534 534
535 } else { 535 } else {
536 $false = !defined($vars{ parse_expand_vars($2, \%vars) }); 536 $false = !defined($vars{ parse_expand_vars($2, \%vars) });
537 if ($type eq 'ndef') { 537 if ($type eq 'ndef') {
538 $false = !$false; 538 $false = !$false;
539 } 539 }
540 push(@if_false, $false ? 1 : 0); 540 push(@if_false, $false ? 1 : 0);
541 } 541 }
542 debug("$file: .if$type (! @if_false)\n"); 542 debug("$file: .if$type (! @if_false)\n");
543 next; 543 next;
544 } 544 }
545 545
546 if (m#^\.\s*elif\s+(.*)# && @if_false) { 546 if (m#^\.\s*elif\s+(.*)# && @if_false) {
547 if ($if_false[$#if_false] == 0) { 547 if ($if_false[$#if_false] == 0) {
548 $if_false[$#if_false] = 2; 548 $if_false[$#if_false] = 2;
549 } elsif ($if_false[$#if_false] == 1 549 } elsif ($if_false[$#if_false] == 1
550 && !parse_eval_make_false($1, \%vars)) { 550 && !parse_eval_make_false($1, \%vars)) {
551 $if_false[$#if_false] = 0; 551 $if_false[$#if_false] = 0;
552 } 552 }
553 debug("$file: .elif (! @if_false)\n"); 553 debug("$file: .elif (! @if_false)\n");
554 next; 554 next;
555 } 555 }
556 556
557 if (m#^\.\s*else\b# && @if_false) { 557 if (m#^\.\s*else\b# && @if_false) {
558 $if_false[$#if_false] = $if_false[$#if_false] == 1 ? 0 : 1; 558 $if_false[$#if_false] = $if_false[$#if_false] == 1 ? 0 : 1;
559 debug("$file: .else (! @if_false)\n"); 559 debug("$file: .else (! @if_false)\n");
560 next; 560 next;
561 } 561 }
562 562
563 if (m#^\.\s*endif\b#) { 563 if (m#^\.\s*endif\b#) {
564 pop(@if_false); 564 pop(@if_false);
565 debug("$file: .endif (! @if_false)\n"); 565 debug("$file: .endif (! @if_false)\n");
566 next; 566 next;
567 } 567 }
568 568
569 $if_false[$#if_false] && next; 569 $if_false[$#if_false] && next;
570 570
571 # Included files (just unshift onto @data) 571 # Included files (just unshift onto @data)
572 # 572 #
573 if (m#^\.\s*include\s+"([^"]+)"#) { 573 if (m#^\.\s*include\s+"([^"]+)"#) {
574 my ($incfile) = parse_expand_vars($1, \%vars); 574 my ($incfile) = parse_expand_vars($1, \%vars);
575 575
576 # At this point just skip any includes which we were not able to 576 # At this point just skip any includes which we were not able to
577 # fully expand 577 # fully expand
578 if ($incfile =~ m#/mk/bsd# 578 if ($incfile =~ m#/mk/bsd#
579 || $incfile =~ /$magic_undefined/ 579 || $incfile =~ /$magic_undefined/
580 || $incfile =~ /\$\{/ 580 || $incfile =~ /\$\{/
581 || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) { 581 || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) {
582 debug("$file: .include \"$incfile\" skipped\n"); 582 debug("$file: .include \"$incfile\" skipped\n");
583 583
584 } else { 584 } else {
585 debug("$file: .include \"$incfile\"\n"); 585 debug("$file: .include \"$incfile\"\n");
586 586
587 # Expand any simple vars in $incfile 587 # Expand any simple vars in $incfile
588 # 588 #
589 589
590 if (substr($incfile, 0, 1) ne '/') { 590 if (substr($incfile, 0, 1) ne '/') {
591 foreach my $dir (keys %incdirs) { 591 foreach my $dir (keys %incdirs) {
592 if (-f "$dir/$incfile") { 592 if (-f "$dir/$incfile") {
593 $incfile = "$dir/$incfile"; 593 $incfile = "$dir/$incfile";
594 last; 594 last;
595 } 595 }
596 } 596 }
597 } 597 }
598 598
599 # perl 5.6.1 realpath() cannot handle files, only directories 599 # perl 5.6.1 realpath() cannot handle files, only directories
600 # If the last component is a symlink this will give a false 600 # If the last component is a symlink this will give a false
601 # negative, but that is not a problem as the duplicate check 601 # negative, but that is not a problem as the duplicate check
602 # is for performance 602 # is for performance
603 $incfile =~ m#^(.+)(/[^/]+)$#; 603 $incfile =~ m#^(.+)(/[^/]+)$#;
604 604
605 if (!-f $incfile) { 605 if (!-f $incfile) {
606 if (!$opt{L}) { 606 if (!$opt{L}) {
607 verbose("\n"); 607 verbose("\n");
608 } 608 }
609 609
610 verbose("$file: Cannot locate $incfile in " 610 verbose("$file: Cannot locate $incfile in "
611 . join(" ", sort keys %incdirs) 611 . join(" ", sort keys %incdirs)
612 . "\n"); 612 . "\n");
613 613
614 } else { 614 } else {
615 $incfile = realpath($1) . $2; 615 $incfile = realpath($1) . $2;
616 616
617 if (!$incfiles{$incfile}) { 617 if (!$incfiles{$incfile}) {
618 if ($opt{L}) { 618 if ($opt{L}) {
619 print "inc $incfile\n"; 619 print "inc $incfile\n";
620 } 620 }
621 $incfiles{$incfile} = 1; 621 $incfiles{$incfile} = 1;
622 622
623 if (!open(FILE, $incfile)) { 623 if (!open(FILE, $incfile)) {
624 verbose("Cannot open '$incfile' (from $file): $_ $!\n"); 624 verbose("Cannot open '$incfile' (from $file): $_ $!\n");
625 } else { 625 } else {
626 my $NEWCURDIR = $incfile; 626 my $NEWCURDIR = $incfile;
627 $NEWCURDIR =~ s#/[^/]*$##; 627 $NEWCURDIR =~ s#/[^/]*$##;
628 $incdirs{$NEWCURDIR} = 1; 628 $incdirs{$NEWCURDIR} = 1;
629 unshift(@data, ".CURDIR=$vars{'.CURDIR'}"); 629 unshift(@data, ".CURDIR=$vars{'.CURDIR'}");
630 unshift(@data, map { chomp; 630 unshift(@data, map { chomp;
631 $_ } <FILE>); 631 $_ } <FILE>);
632 unshift(@data, ".CURDIR=$NEWCURDIR"); 632 unshift(@data, ".CURDIR=$NEWCURDIR");
633 close(FILE); 633 close(FILE);
634 } 634 }
635 } 635 }
636 } 636 }
637 } 637 }
638 next; 638 next;
639 } 639 }
640 640
641 if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) { 641 if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) {
642 my ($key); 642 my ($key);
643 643
644 $key = $1; 644 $key = $1;
645 $plus = $2; 645 $plus = $2;
646 $value = $3; 646 $value = $3;
647 647
648 if ($plus eq ':') { 648 if ($plus eq ':') {
649 $vars{$key} = parse_expand_vars($value, \%vars); 649 $vars{$key} = parse_expand_vars($value, \%vars);
650 } elsif ($plus eq '+' && defined $vars{$key}) { 650 } elsif ($plus eq '+' && defined $vars{$key}) {
651 $vars{$key} .= " $value"; 651 $vars{$key} .= " $value";
652 } elsif ($plus ne '?' || !defined $vars{$key}) { 652 } elsif ($plus ne '?' || !defined $vars{$key}) {
653 $vars{$key} = $value; 653 $vars{$key} = $value;
654 } 654 }
655 debug("assignment: $key$plus=[$value] ($vars{$key})\n"); 655 debug("assignment: $key$plus=[$value] ($vars{$key})\n");
656 656
657 # Give python a little hand (XXX - do we wanna consider actually 657 # Give python a little hand (XXX - do we wanna consider actually
658 # implementing make .for loops, etc? 658 # implementing make .for loops, etc?
659 # 659 #
660 if ($key eq "PYTHON_VERSIONS_ACCEPTED") { 660 if ($key eq "PYTHON_VERSIONS_ACCEPTED") {
661 my ($pv); 661 my ($pv);
662 662
663 foreach $pv (split(/\s+/, $vars{PYTHON_VERSIONS_ACCEPTED})) { 663 foreach $pv (split(/\s+/, $vars{PYTHON_VERSIONS_ACCEPTED})) {
664 $vars{"_PYTHON_VERSION_FIRSTACCEPTED"} ||= $pv; 664 $vars{"_PYTHON_VERSION_FIRSTACCEPTED"} ||= $pv;
665 $vars{"_PYTHON_VERSION_${pv}_OK"} = "yes"; 665 $vars{"_PYTHON_VERSION_${pv}_OK"} = "yes";
666 } 666 }
667 } 667 }
668 } 668 }
669 } 669 }
670 670
671 debug("$file: expand\n"); 671 debug("$file: expand\n");
672 672
673 # Handle variable substitutions FRED = a-${JIM:S/-/-b-/} 673 # Handle variable substitutions FRED = a-${JIM:S/-/-b-/}
674 # 674 #
675 my ($loop); 675 my ($loop);
676 676
677 for ($loop = 1; $loop;) { 677 for ($loop = 1; $loop;) {
678 $loop = 0; 678 $loop = 0;
679 foreach my $key (keys %vars) { 679 foreach my $key (keys %vars) {
680 if (index($vars{$key}, '$') == -1) { 680 if (index($vars{$key}, '$') == -1) {
681 next; 681 next;
682 } 682 }
683 683
684 $_ = parse_expand_vars($vars{$key}, \%vars); 684 $_ = parse_expand_vars($vars{$key}, \%vars);
685 if ($_ ne $vars{$key}) { 685 if ($_ ne $vars{$key}) {
686 $vars{$key} = $_; 686 $vars{$key} = $_;
687 $loop = 1; 687 $loop = 1;
688 688
689 } elsif ($vars{$key} =~ m#\$\{([\w.]+):([CS]([^{}])[^{}\3]+\3[^{}\3]*\3[g1]*(|:[^{}]+)|U[^{}]+)\}#) { 689 } elsif ($vars{$key} =~ m#\$\{([\w.]+):([CS]([^{}])[^{}\3]+\3[^{}\3]*\3[g1]*(|:[^{}]+)|U[^{}]+)\}#) {
690 my ($left, $subvar, $right) = ($`, $1, $'); 690 my ($left, $subvar, $right) = ($`, $1, $');
691 my (@patterns) = split(':', $2); 691 my (@patterns) = split(':', $2);
692 my ($result); 692 my ($result);
693 693
694 $result = $vars{$subvar}; 694 $result = $vars{$subvar};
695 $result ||= ''; 695 $result ||= '';
696 696
697 # If $vars{$subvar} contains a $ skip it on this pass. 697 # If $vars{$subvar} contains a $ skip it on this pass.
698 # Hopefully it will get substituted and we can catch it 698 # Hopefully it will get substituted and we can catch it
699 # next time around. 699 # next time around.
700 if (index($result, '${') != -1) { 700 if (index($result, '${') != -1) {
701 next; 701 next;
702 } 702 }
703 703
704 debug("$file: substitutelist $key ($result) $subvar (@patterns)\n"); 704 debug("$file: substitutelist $key ($result) $subvar (@patterns)\n");
705 foreach (@patterns) { 705 foreach (@patterns) {
706 if (m#(U)(.*)#) { 706 if (m#(U)(.*)#) {
707 $result ||= $2; 707 $result ||= $2;
708 } elsif (m#([CS])(.)([^/@]+)\2([^/@]*)\2([1g]*)#) { 708 } elsif (m#([CS])(.)([^/@]+)\2([^/@]*)\2([1g]*)#) {
709 my ($how, $from, $to, $global) = ($1, $3, $4, $5); 709 my ($how, $from, $to, $global) = ($1, $3, $4, $5);
710 710
711 debug("$file: substituteglob $subvar, $how, $from, $to, $global\n"); 711 debug("$file: substituteglob $subvar, $how, $from, $to, $global\n");
712 if ($how eq 'S') { 712 if ($how eq 'S') {
713 # Limited substitution - keep ^ and $ 713 # Limited substitution - keep ^ and $
714 $from =~ s/([?.{}\]\[*+])/\\$1/g; 714 $from =~ s/([?.{}\]\[*+])/\\$1/g;
715 } 715 }
716 $to =~ s/\\(\d)/\$$1/g; # Change \1 etc to $1 716 $to =~ s/\\(\d)/\$$1/g; # Change \1 etc to $1
717 $to =~ s/\&/\$&/g; # Change & to $1 717 $to =~ s/\&/\$&/g; # Change & to $1
718 718
719 my ($notfirst); 719 my ($notfirst);
720 if ($global =~ s/1//) { 720 if ($global =~ s/1//) {
721 ($from, $notfirst) = split('\s', $from, 2); 721 ($from, $notfirst) = split('\s', $from, 2);
722 } 722 }
723 723
724 debug("$file: substituteperl $subvar, $how, $from, $to\n"); 724 debug("$file: substituteperl $subvar, $how, $from, $to\n");
725 debug("eval substitute <$from> <$to> <$global>\n"); 725 debug("eval substitute <$from> <$to> <$global>\n");
726 eval "\$result =~ s/$from/$to/$global"; 726 eval "\$result =~ s/$from/$to/$global";
727 if (defined $notfirst) { 727 if (defined $notfirst) {
728 $result .= " $notfirst"; 728 $result .= " $notfirst";
729 } 729 }
730 } else { 730 } else {
731 next; 731 next;
732 } 732 }
733 } 733 }
734 734
735 $vars{$key} = $left . $result . $right; 735 $vars{$key} = $left . $result . $right;
736 $loop = 1; 736 $loop = 1;
737 } 737 }
738 } 738 }
739 } 739 }
740 740
741 foreach my $key (keys %vars) { 741 foreach my $key (keys %vars) {
742 $vars{$key} =~ s/$magic_undefined//; 742 $vars{$key} =~ s/$magic_undefined//;
743 } 743 }
744 \%vars; 744 \%vars;
745} 745}
746 746
747sub get_default_makefile_vars() { 747sub get_default_makefile_vars() {
748 748
749 chomp($pkg_installver = `pkg_info -V 2>/dev/null || echo 20010302`); 749 chomp($pkg_installver = `pkg_info -V 2>/dev/null || echo 20010302`);
750 750
751 chomp($_ = `uname -srm`); 751 chomp($_ = `uname -srm`);
752 ( 752 (
753 $default_vars->{OPSYS}, 753 $default_vars->{OPSYS},
754 $default_vars->{OS_VERSION}, 754 $default_vars->{OS_VERSION},
755 $default_vars->{MACHINE} 755 $default_vars->{MACHINE}
756 ) = (split); 756 ) = (split);
757 if (!$default_vars->{MACHINE}) { 757 if (!$default_vars->{MACHINE}) {
758 die('Unable to extract machine from uname'); 758 die('Unable to extract machine from uname');
759 } 759 }
760 760
761 # Handle systems without uname -p (NetBSD pre 1.4) 761 # Handle systems without uname -p (NetBSD pre 1.4)
762 chomp($default_vars->{MACHINE_ARCH} = `uname -p 2>/dev/null`); 762 chomp($default_vars->{MACHINE_ARCH} = `uname -p 2>/dev/null`);
763 763
764 if (!$default_vars->{MACHINE_ARCH} 764 if (!$default_vars->{MACHINE_ARCH}
765 && $default_vars->{OS_VERSION} eq 'NetBSD') { 765 && $default_vars->{OS_VERSION} eq 'NetBSD') {
766 chomp($default_vars->{MACHINE_ARCH} = `sysctl -n hw.machine_arch`); 766 chomp($default_vars->{MACHINE_ARCH} = `sysctl -n hw.machine_arch`);
767 } 767 }
768 768
769 if (!$default_vars->{MACHINE_ARCH}) { 769 if (!$default_vars->{MACHINE_ARCH}) {
770 $default_vars->{MACHINE_ARCH} = $default_vars->{MACHINE}; 770 $default_vars->{MACHINE_ARCH} = $default_vars->{MACHINE};
771 } 771 }
772 772
773 $default_vars->{OBJECT_FMT} = 'x'; 773 $default_vars->{OBJECT_FMT} = 'x';
774 $default_vars->{LOWER_OPSYS} = lc($default_vars->{OPSYS}); 774 $default_vars->{LOWER_OPSYS} = lc($default_vars->{OPSYS});
775 775
776 if ($opt{P}) { 776 if ($opt{P}) {
777 $default_vars->{PKGSRCDIR} = realpath($opt{P}); 777 $default_vars->{PKGSRCDIR} = realpath($opt{P});
778 } else { 778 } else {
779 $default_vars->{PKGSRCDIR} = $conf_pkgsrcdir; 779 $default_vars->{PKGSRCDIR} = $conf_pkgsrcdir;
780 } 780 }
781 781
782 $default_vars->{DESTDIR} = ''; 782 $default_vars->{DESTDIR} = '';
783 $default_vars->{LOCALBASE} = '/usr/pkg'; 783 $default_vars->{LOCALBASE} = '/usr/pkg';
784 $default_vars->{X11BASE} = '/usr/X11R6'; 784 $default_vars->{X11BASE} = '/usr/X11R6';
785 785
786 my ($vars); 786 my ($vars);
787 if (-f '/etc/mk.conf' && ($vars = parse_makefile_vars('/etc/mk.conf', undef))) { 787 if (-f '/etc/mk.conf' && ($vars = parse_makefile_vars('/etc/mk.conf', undef))) {
788 foreach my $var (keys %{$vars}) { 788 foreach my $var (keys %{$vars}) {
789 $default_vars->{$var} = $vars->{$var}; 789 $default_vars->{$var} = $vars->{$var};
790 } 790 }
791 } elsif (-f "$conf_sysconfdir/mk.conf" && 791 } elsif (-f "$conf_sysconfdir/mk.conf" &&
792 ($vars = parse_makefile_vars("$conf_sysconfdir/mk.conf", undef))) { 792 ($vars = parse_makefile_vars("$conf_sysconfdir/mk.conf", undef))) {
793 foreach my $var (keys %{$vars}) { 793 foreach my $var (keys %{$vars}) {
794 $default_vars->{$var} = $vars->{$var}; 794 $default_vars->{$var} = $vars->{$var};
795 } 795 }
796 } 796 }
797 797
798 if ($opt{P}) { 798 if ($opt{P}) {
799 $default_vars->{PKGSRCDIR} = realpath($opt{P}); 799 $default_vars->{PKGSRCDIR} = realpath($opt{P});
800 } 800 }
801 801
802 if ($opt{M}) { 802 if ($opt{M}) {
803 $default_vars->{DISTDIR} = realpath($opt{M}); 803 $default_vars->{DISTDIR} = realpath($opt{M});
804 } else { 804 } else {
805 $default_vars->{DISTDIR} ||= $default_vars->{PKGSRCDIR} . '/distfiles'; 805 $default_vars->{DISTDIR} ||= $default_vars->{PKGSRCDIR} . '/distfiles';
806 } 806 }
807 807
808 if ($opt{K}) { 808 if ($opt{K}) {
809 $default_vars->{PACKAGES} = realpath($opt{K}); 809 $default_vars->{PACKAGES} = realpath($opt{K});
810 } 810 }
811 811
812 # Extract some variables from bsd.pkg.mk 812 # Extract some variables from bsd.pkg.mk
813 my ($mkvars); 813 my ($mkvars);
814 $mkvars = parse_makefile_vars( 814 $mkvars = parse_makefile_vars(
815 "$default_vars->{PKGSRCDIR}/mk/bsd.pkg.mk", 815 "$default_vars->{PKGSRCDIR}/mk/bsd.pkg.mk",
816 "$default_vars->{PKGSRCDIR}/mk/scripts" 816 "$default_vars->{PKGSRCDIR}/mk/scripts"
817 ); 817 );
818 foreach my $varname (keys %{$mkvars}) { 818 foreach my $varname (keys %{$mkvars}) {
819 if ($varname =~ /_REQD$/ || $varname eq 'EXTRACT_SUFX') { 819 if ($varname =~ /_REQD$/ || $varname eq 'EXTRACT_SUFX') {
820 $default_vars->{$varname} = $mkvars->{$varname}; 820 $default_vars->{$varname} = $mkvars->{$varname};
821 } 821 }
822 } 822 }
823 823
824 $default_vars->{PACKAGES} ||= $default_vars->{PKGSRCDIR} . '/packages'; 824 $default_vars->{PACKAGES} ||= $default_vars->{PKGSRCDIR} . '/packages';
825} 825}
826 826
827# Determine if a package version is current. If not, report correct version 827# Determine if a package version is current. If not, report correct version
828# if found 828# if found
829# 829#
830sub invalid_version($) { 830sub invalid_version($) {
831 my ($pkgmatch) = @_; 831 my ($pkgmatch) = @_;
832 my ($fail, $ok); 832 my ($fail, $ok);
833 my (@pkgmatches, @todo); 833 my (@pkgmatches, @todo);
834 834
835 @todo = ($pkgmatch); 835 @todo = ($pkgmatch);
836 836
837 # We handle {} here, everything else in package_globmatch 837 # We handle {} here, everything else in package_globmatch
838 while ($pkgmatch = shift @todo) { 838 while ($pkgmatch = shift @todo) {
839 if ($pkgmatch =~ /(.*)\{([^{}]+)}(.*)/) { 839 if ($pkgmatch =~ /(.*)\{([^{}]+)}(.*)/) {
840 foreach (split(',', $2)) { 840 foreach (split(',', $2)) {
841 push(@todo, "$1$_$3"); 841 push(@todo, "$1$_$3");
842 } 842 }
843 } else { 843 } else {
844 push(@pkgmatches, $pkgmatch); 844 push(@pkgmatches, $pkgmatch);
845 } 845 }
846 } 846 }
847 847
848 foreach $pkgmatch (@pkgmatches) { 848 foreach $pkgmatch (@pkgmatches) {
849 my ($pkg, $badver) = package_globmatch($pkgmatch); 849 my ($pkg, $badver) = package_globmatch($pkgmatch);
850 850
851 if (defined($badver)) { 851 if (defined($badver)) {
852 my ($pkgs); 852 my ($pkgs);
853 853
854 if ($pkgs = $pkglist->pkgs($pkg)) { 854 if ($pkgs = $pkglist->pkgs($pkg)) {
855 $fail .= 855 $fail .=
856 "Version mismatch: '$pkg' $badver vs " 856 "Version mismatch: '$pkg' $badver vs "
857 . join(',', $pkgs->versions) . "\n"; 857 . join(',', $pkgs->versions) . "\n";
858 } else { 858 } else {
859 $fail .= "Unknown package: '$pkg' version $badver\n"; 859 $fail .= "Unknown package: '$pkg' version $badver\n";
860 } 860 }
861 } else { 861 } else {
862 862
863 # If we find one match, don't bitch about others 863 # If we find one match, don't bitch about others
864 $ok = 1; 864 $ok = 1;
865 } 865 }
866 } 866 }
867 $ok && ($fail = undef); 867 $ok && ($fail = undef);
868 $fail; 868 $fail;
869} 869}
870 870
871# Use pkg_info to list installed packages 871# Use pkg_info to list installed packages
872# 872#
873sub list_installed_packages() { 873sub list_installed_packages() {
874 my (@pkgs); 874 my (@pkgs);
875 875
876 open(PKG_INFO, 'pkg_info -e "*" |') || fail("Unable to run pkg_info: $!"); 876 open(PKG_INFO, 'pkg_info -e "*" |') || fail("Unable to run pkg_info: $!");
877 while (defined(my $pkg = <PKG_INFO>)) { 877 while (defined(my $pkg = <PKG_INFO>)) {
878 chomp($pkg); 878 chomp($pkg);
879 push(@pkgs, canonicalize_pkgname($pkg)); 879 push(@pkgs, canonicalize_pkgname($pkg));
880 } 880 }
881 close(PKG_INFO); 881 close(PKG_INFO);
882 882
883 @pkgs; 883 @pkgs;
884} 884}
885 885
886# List top level pkgsrc categories 886# List top level pkgsrc categories
887# 887#
888sub list_pkgsrc_categories($) { 888sub list_pkgsrc_categories($) {
889 my ($pkgsrcdir) = @_; 889 my ($pkgsrcdir) = @_;
890 my (@categories); 890 my (@categories);
891 891
892 opendir(BASE, $pkgsrcdir) || die("Unable to opendir($pkgsrcdir): $!"); 892 opendir(BASE, $pkgsrcdir) || die("Unable to opendir($pkgsrcdir): $!");
893 @categories = 893 @categories =
894 grep(substr($_, 0, 1) ne '.' 894 grep(substr($_, 0, 1) ne '.'
895 && $_ ne 'CVS' 895 && $_ ne 'CVS'
896 && -f "$pkgsrcdir/$_/Makefile", 896 && -f "$pkgsrcdir/$_/Makefile",
897 readdir(BASE)); 897 readdir(BASE));
898 closedir(BASE); 898 closedir(BASE);
899 @categories; 899 @categories;
900} 900}
901 901
902# For a given category, list potentially valid pkgdirs 902# For a given category, list potentially valid pkgdirs
903# 903#
904sub list_pkgsrc_pkgdirs($$) { 904sub list_pkgsrc_pkgdirs($$) {
905 my ($pkgsrcdir, $cat) = @_; 905 my ($pkgsrcdir, $cat) = @_;
906 my (@pkgdirs); 906 my (@pkgdirs);
907 907
908 if (!opendir(CAT, "$pkgsrcdir/$cat")) { 908 if (!opendir(CAT, "$pkgsrcdir/$cat")) {
909 die("Unable to opendir($pkgsrcdir/$cat): $!"); 909 die("Unable to opendir($pkgsrcdir/$cat): $!");
910 } 910 }
911 @pkgdirs = 911 @pkgdirs =
912 sort grep($_ ne 'Makefile' 912 sort grep($_ ne 'Makefile'
913 && $_ ne 'pkg' 913 && $_ ne 'pkg'
914 && $_ ne 'CVS' 914 && $_ ne 'CVS'
915 && substr($_, 0, 1) ne '.', 915 && substr($_, 0, 1) ne '.',
916 readdir(CAT)); 916 readdir(CAT));
917 closedir(CAT); 917 closedir(CAT);
918 @pkgdirs; 918 @pkgdirs;
919} 919}
920 920
921sub glob2regex($) { 921sub glob2regex($) {
922 my ($glob) = @_; 922 my ($glob) = @_;
923 my (@chars, $in_alt); 923 my (@chars, $in_alt);
924 my ($regex); 924 my ($regex);
925 925
926 @chars = split(//, $glob); 926 @chars = split(//, $glob);
927 while (defined($_ = shift @chars)) { 927 while (defined($_ = shift @chars)) {
928 if ($_ eq '*') { 928 if ($_ eq '*') {
929 $regex .= '.*'; 929 $regex .= '.*';
930 } elsif ($_ eq '?') { 930 } elsif ($_ eq '?') {
931 $regex .= '.'; 931 $regex .= '.';
932 } elsif ($_ eq '+') { 932 } elsif ($_ eq '+') {
933 $regex .= '.'; 933 $regex .= '.';
934 } elsif ($_ eq '\\+') { 934 } elsif ($_ eq '\\+') {
935 $regex .= $_ . shift @chars; 935 $regex .= $_ . shift @chars;
936 } elsif ($_ eq '.' || $_ eq '|') { 936 } elsif ($_ eq '.' || $_ eq '|') {
937 $regex .= quotemeta; 937 $regex .= quotemeta;
938 } elsif ($_ eq '{') { 938 } elsif ($_ eq '{') {
939 $regex .= '('; 939 $regex .= '(';
940 ++$in_alt; 940 ++$in_alt;
941 } elsif ($_ eq '}') { 941 } elsif ($_ eq '}') {
942 if (!$in_alt) { 942 if (!$in_alt) {
943 # Error 943 # Error
944 return undef; 944 return undef;
945 } 945 }
946 $regex .= ')'; 946 $regex .= ')';
947 --$in_alt; 947 --$in_alt;
948 } elsif ($_ eq ',' && $in_alt) { 948 } elsif ($_ eq ',' && $in_alt) {
949 $regex .= '|'; 949 $regex .= '|';
950 } else { 950 } else {
951 $regex .= $_; 951 $regex .= $_;
952 } 952 }
953 } 953 }
954 954
955 if ($in_alt) { 955 if ($in_alt) {
956 # Error 956 # Error
957 return undef; 957 return undef;
958 } 958 }
959 if ($regex eq $glob) { 959 if ($regex eq $glob) {
960 return (''); 960 return ('');
961 } 961 }
962 if ($opt{D}) { 962 if ($opt{D}) {
963 print "glob2regex: $glob -> $regex\n"; 963 print "glob2regex: $glob -> $regex\n";
964 } 964 }
965 '^' . $regex . '$'; 965 '^' . $regex . '$';
966} 966}
967 967
968# Perform some (reasonable) subset of 'pkg_info -e' / glob(3) 968# Perform some (reasonable) subset of 'pkg_info -e' / glob(3)
969# Returns (sometimes best guess at) package name, 969# Returns (sometimes best guess at) package name,
970# and either 'problem version' or undef if all OK 970# and either 'problem version' or undef if all OK
971# 971#
972sub package_globmatch($) { 972sub package_globmatch($) {
973 my ($pkgmatch) = @_; 973 my ($pkgmatch) = @_;
974 my ($matchpkgname, $matchver, $regex); 974 my ($matchpkgname, $matchver, $regex);
975 975
976 if ($pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/) { 976 if ($pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/) {
977 977
978 # (package)(cmp)(pkgversion) 978 # (package)(cmp)(pkgversion)
979 my ($test, @pkgvers); 979 my ($test, @pkgvers);
980 980
981 ($matchpkgname, $test, $matchver) = ($1, $2, $3); 981 ($matchpkgname, $test, $matchver) = ($1, $2, $3);
982 if (@pkgvers = $pkglist->pkgver($matchpkgname)) { 982 if (@pkgvers = $pkglist->pkgver($matchpkgname)) {
983 foreach my $pkgver (@pkgvers) { 983 foreach my $pkgver (@pkgvers) {
984 if ($test eq '-') { 984 if ($test eq '-') {
985 if ($pkgver->ver eq $matchver) { 985 if ($pkgver->ver eq $matchver) {
986 $matchver = undef; 986 $matchver = undef;
987 last; 987 last;
988 } 988 }
989 } else { 989 } else {
990 if (pkgversioncmp($pkgver->ver, $test, $matchver)) { 990 if (pkgversioncmp($pkgver->ver, $test, $matchver)) {
991 $matchver = undef; 991 $matchver = undef;
992 last; 992 last;
993 } 993 }
994 } 994 }
995 } 995 }
996 996
997 if ($matchver && $test ne '-') { 997 if ($matchver && $test ne '-') {
998 $matchver = "$test$matchver"; 998 $matchver = "$test$matchver";
999 } 999 }
1000 } 1000 }
1001 1001
1002 } elsif ($pkgmatch =~ /^([^[]+)-([\d*?{[].*)$/) { 1002 } elsif ($pkgmatch =~ /^([^[]+)-([\d*?{[].*)$/) {
1003 1003
1004 # (package)-(globver) 1004 # (package)-(globver)
1005 my (@pkgnames); 1005 my (@pkgnames);
1006 1006
1007 ($matchpkgname, $matchver) = ($1, $2); 1007 ($matchpkgname, $matchver) = ($1, $2);
1008 1008
1009 if (defined $pkglist->pkgs($matchpkgname)) { 1009 if (defined $pkglist->pkgs($matchpkgname)) {
1010 push(@pkgnames, $matchpkgname); 1010 push(@pkgnames, $matchpkgname);
1011 1011
1012 } elsif ($regex = glob2regex($matchpkgname)) { 1012 } elsif ($regex = glob2regex($matchpkgname)) {
1013 foreach my $pkg ($pkglist->pkgs) { 1013 foreach my $pkg ($pkglist->pkgs) {
1014 ($pkg->pkg() =~ /$regex/) && push(@pkgnames, $pkg->pkg()); 1014 ($pkg->pkg() =~ /$regex/) && push(@pkgnames, $pkg->pkg());
1015 } 1015 }
1016 } 1016 }
1017 1017
1018 # Try to convert $matchver into regex version 1018 # Try to convert $matchver into regex version
1019 # 1019 #
1020 $regex = glob2regex($matchver); 1020 $regex = glob2regex($matchver);
1021 1021
1022 foreach my $pkg (@pkgnames) { 1022 foreach my $pkg (@pkgnames) {
1023 if (defined $pkglist->pkgver($pkg, $matchver)) { 1023 if (defined $pkglist->pkgver($pkg, $matchver)) {
1024 return ($matchver); 1024 return ($matchver);
1025 } 1025 }
1026 1026
1027 if ($regex) { 1027 if ($regex) {
1028 foreach my $ver ($pkglist->pkgs($pkg)->versions) { 1028 foreach my $ver ($pkglist->pkgs($pkg)->versions) {
1029 if ($ver =~ /$regex/) { 1029 if ($ver =~ /$regex/) {
1030 $matchver = undef; 1030 $matchver = undef;
1031 last; 1031 last;
1032 } 1032 }
1033 } 1033 }
1034 } 1034 }
1035 1035
1036 $matchver || last; 1036 $matchver || last;
1037 } 1037 }
1038 1038
1039 # last ditch attempt to handle the whole DEPENDS as a glob 1039 # last ditch attempt to handle the whole DEPENDS as a glob
1040 # 1040 #
1041 if ($matchver && ($regex = glob2regex($pkgmatch))) { 1041 if ($matchver && ($regex = glob2regex($pkgmatch))) {
1042 1042
1043 # (large-glob) 1043 # (large-glob)
1044 foreach my $pkgver ($pkglist->pkgver) { 1044 foreach my $pkgver ($pkglist->pkgver) {
1045 if ($pkgver->pkgname =~ /$regex/) { 1045 if ($pkgver->pkgname =~ /$regex/) {
1046 $matchver = undef; 1046 $matchver = undef;
1047 last; 1047 last;
1048 } 1048 }
1049 } 1049 }
1050 } 1050 }
1051 1051
1052 } else { 1052 } else {
1053 ($matchpkgname, $matchver) = ($pkgmatch, 'missing'); 1053 ($matchpkgname, $matchver) = ($pkgmatch, 'missing');
1054 } 1054 }
1055 1055
1056 ($matchpkgname, $matchver); 1056 ($matchpkgname, $matchver);
1057} 1057}
1058 1058
1059# Parse a pkgsrc package makefile and return the pkgname and set variables 1059# Parse a pkgsrc package makefile and return the pkgname and set variables
1060# 1060#
1061sub parse_makefile_pkgsrc($) { 1061sub parse_makefile_pkgsrc($) {
1062 my ($file) = @_; 1062 my ($file) = @_;
1063 my ($pkgname, $vars); 1063 my ($pkgname, $vars);
1064 1064
1065 $vars = parse_makefile_vars($file, undef); 1065 $vars = parse_makefile_vars($file, undef);
1066 1066
1067 if (!$vars) { 1067 if (!$vars) {
1068 1068
1069 # Missing Makefile 1069 # Missing Makefile
1070 return undef; 1070 return undef;
1071 } 1071 }
1072 1072
1073 if (defined $vars->{PKGNAME}) { 1073 if (defined $vars->{PKGNAME}) {
1074 $pkgname = $vars->{PKGNAME}; 1074 $pkgname = $vars->{PKGNAME};
1075 } elsif (defined $vars->{DISTNAME}) { 1075 } elsif (defined $vars->{DISTNAME}) {
1076 $pkgname = $vars->{DISTNAME}; 1076 $pkgname = $vars->{DISTNAME};
1077 } 1077 }
1078 1078
1079 if (defined $vars->{PKGNAME}) { 1079 if (defined $vars->{PKGNAME}) {
1080 debug("$file: PKGNAME=$vars->{PKGNAME}\n"); 1080 debug("$file: PKGNAME=$vars->{PKGNAME}\n");
1081 } 1081 }
1082 if (defined $vars->{DISTNAME}) { 1082 if (defined $vars->{DISTNAME}) {
1083 debug("$file: DISTNAME=$vars->{DISTNAME}\n"); 1083 debug("$file: DISTNAME=$vars->{DISTNAME}\n");
1084 } 1084 }
1085 1085
1086 if (!defined $pkgname || $pkgname =~ /\$/ || $pkgname !~ /(.*)-(\d.*)/) { 1086 if (!defined $pkgname || $pkgname =~ /\$/ || $pkgname !~ /(.*)-(\d.*)/) {
1087 1087
1088 # invoke make here as a last resort 1088 # invoke make here as a last resort
1089 my ($pkgsrcdir) = ($file =~ m:(/.*)/:); 1089 my ($pkgsrcdir) = ($file =~ m:(/.*)/:);
1090 debug("Running '$conf_make' in '$pkgsrcdir'\n"); 1090 debug("Running '$conf_make' in '$pkgsrcdir'\n");
1091 my $pid = open3(\*WTR, \*RDR, \*ERR, 1091 my $pid = open3(\*WTR, \*RDR, \*ERR,
1092 "cd $pkgsrcdir || exit 1; $conf_make show-vars VARNAMES=PKGNAME"); 1092 "cd $pkgsrcdir || exit 1; $conf_make show-vars VARNAMES=PKGNAME");
1093 if (!$pid) { 1093 if (!$pid) {
1094 warn "$file: Unable to run make: $!"; 1094 warn "$file: Unable to run make: $!";
1095 } else { 1095 } else {
1096 close(WTR); 1096 close(WTR);
1097 my @errors = <ERR>; 1097 my @errors = <ERR>;
1098 close(ERR); 1098 close(ERR);
1099 my ($makepkgname) = <RDR>; 1099 my ($makepkgname) = <RDR>;
1100 close(RDR); 1100 close(RDR);
1101 wait; 1101 wait;
1102 chomp @errors; 1102 chomp @errors;
1103 if (@errors) { warn "\n$file: @errors\n"; } 1103 if (@errors) { warn "\n$file: @errors\n"; }
1104 1104
1105 if ($makepkgname =~ /(.*)-(\d.*)/) { 1105 if ($makepkgname =~ /(.*)-(\d.*)/) {
1106 $pkgname = $makepkgname; 1106 $pkgname = $makepkgname;
1107 } 1107 }
1108 } 1108 }
1109 } 1109 }
1110 1110
1111 if (defined $pkgname) { 1111 if (defined $pkgname) {
1112 if ($pkgname =~ /^pkg_install-(\d+)$/ && $1 < $pkg_installver) { 1112 if ($pkgname =~ /^pkg_install-(\d+)$/ && $1 < $pkg_installver) {
1113 $pkgname = "pkg_install-$pkg_installver"; 1113 $pkgname = "pkg_install-$pkg_installver";
1114 } 1114 }
1115 1115
1116 $pkgname = canonicalize_pkgname($pkgname); 1116 $pkgname = canonicalize_pkgname($pkgname);
1117 1117
1118 if (defined $vars->{PKGREVISION} 1118 if (defined $vars->{PKGREVISION}
1119 and not $vars->{PKGREVISION} =~ /^\s*$/) { 1119 and not $vars->{PKGREVISION} =~ /^\s*$/) {
1120 if ($vars->{PKGREVISION} =~ /^\$\{(_(CVS|GIT|HG|SVN)_PKGVERSION):.*\}$/) { 1120 if ($vars->{PKGREVISION} =~ /^\$\{(_(CVS|GIT|HG|SVN)_PKGVERSION):.*\}$/) {
1121 # See wip/mk/*-package.mk. 1121 # See wip/mk/*-package.mk.
1122 } elsif ($vars->{PKGREVISION} =~ /\D/) { 1122 } elsif ($vars->{PKGREVISION} =~ /\D/) {
1123 print "\nBogus: PKGREVISION $vars->{PKGREVISION} (from $file)\n"; 1123 print "\nBogus: PKGREVISION $vars->{PKGREVISION} (from $file)\n";
1124 1124
1125 } elsif ($vars->{PKGREVISION}) { 1125 } elsif ($vars->{PKGREVISION}) {
1126 $pkgname .= "nb"; 1126 $pkgname .= "nb";
1127 $pkgname .= $vars->{PKGREVISION}; 1127 $pkgname .= $vars->{PKGREVISION};
1128 } 1128 }
1129 } 1129 }
1130 1130
1131 if ($pkgname =~ /\$/) { 1131 if ($pkgname =~ /\$/) {
1132 print "\nBogus: $pkgname (from $file)\n"; 1132 print "\nBogus: $pkgname (from $file)\n";
1133 1133
1134 } elsif ($pkgname =~ /(.*)-(\d.*)/) { 1134 } elsif ($pkgname =~ /(.*)-(\d.*)/) {
1135 if ($pkglist) { 1135 if ($pkglist) {
1136 my ($pkgver) = $pkglist->add($1, $2); 1136 my ($pkgver) = $pkglist->add($1, $2);
1137 1137
1138 debug("add $1 $2\n"); 1138 debug("add $1 $2\n");
1139 1139
1140 foreach my $var (qw(DEPENDS RESTRICTED OSVERSION_SPECIFIC BROKEN)) { 1140 foreach my $var (qw(DEPENDS RESTRICTED OSVERSION_SPECIFIC BROKEN)) {
1141 $pkgver->var($var, $vars->{$var}); 1141 $pkgver->var($var, $vars->{$var});
1142 } 1142 }
1143 1143
1144 if (defined $vars->{NO_BIN_ON_FTP}) { 1144 if (defined $vars->{NO_BIN_ON_FTP}) {
1145 $pkgver->var('RESTRICTED', 'NO_BIN_ON_FTP'); 1145 $pkgver->var('RESTRICTED', 'NO_BIN_ON_FTP');
1146 } 1146 }
1147 1147
1148 if ($file =~ m:([^/]+/[^/]+)/Makefile$:) { 1148 if ($file =~ m:([^/]+/[^/]+)/Makefile$:) {
1149 $pkgver->var('dir', $1); 1149 $pkgver->var('dir', $1);
1150 } else { 1150 } else {
1151 $pkgver->var('dir', 'unknown'); 1151 $pkgver->var('dir', 'unknown');
1152 } 1152 }
1153 } 1153 }
1154 } else { 1154 } else {
1155 print "Cannot extract $pkgname version ($file)\n"; 1155 print "Cannot extract $pkgname version ($file)\n";
1156 } 1156 }
1157 1157
1158 return ($pkgname, $vars); 1158 return ($pkgname, $vars);
1159 1159
1160 } else { 1160 } else {
1161 return (undef); 1161 return (undef);
1162 } 1162 }
1163} 1163}
1164 1164
1165 1165
1166# chdir() || fail() 1166# chdir() || fail()
1167# 1167#
1168sub safe_chdir($) { 1168sub safe_chdir($) {
1169 my ($dir) = @_; 1169 my ($dir) = @_;
1170 1170
1171 debug("chdir: $dir"); 1171 debug("chdir: $dir");
1172 if (!chdir($dir)) { 1172 if (!chdir($dir)) {
1173 fail("Unable to chdir($dir): $!"); 1173 fail("Unable to chdir($dir): $!");
1174 } 1174 }
1175} 1175}
1176 1176
1177sub load_pkgsrc_makefiles($) { 1177sub load_pkgsrc_makefiles($) {
1178 1178
1179 open(STORE, "<$_[0]") || die("Cannot read pkgsrc store from $_[0]: $!\n"); 1179 open(STORE, "<$_[0]") || die("Cannot read pkgsrc store from $_[0]: $!\n");
1180 my ($pkgver); 1180 my ($pkgver);
1181 our ($pkgcnt, $pkgnum, $subpkgcnt, $subpkgnum); 1181 our ($pkgcnt, $pkgnum, $subpkgcnt, $subpkgnum);
1182 $pkglist = new PkgList; 1182 $pkglist = new PkgList;
1183 while (<STORE>) { 1183 while (<STORE>) {
1184 debug("eval store $_"); 1184 debug("eval store $_");
1185 eval $_; 1185 eval $_;
1186 } 1186 }
1187 close(STORE); 1187 close(STORE);
1188} 1188}
1189 1189
1190# Generate pkgname->category/pkg mapping, optionally check DEPENDS 1190# Generate pkgname->category/pkg mapping, optionally check DEPENDS
1191# 1191#
1192sub scan_pkgsrc_makefiles($) { 1192sub scan_pkgsrc_makefiles($) {
1193 my ($pkgsrcdir) = @_; 1193 my ($pkgsrcdir) = @_;
1194 my (@categories); 1194 my (@categories);
1195 1195
1196 if ($pkglist) { 1196 if ($pkglist) {
1197 1197
1198 # Already done 1198 # Already done
1199 return; 1199 return;
1200 } 1200 }
1201 1201
1202 if ($opt{I}) { 1202 if ($opt{I}) {
1203 load_pkgsrc_makefiles($opt{I}); 1203 load_pkgsrc_makefiles($opt{I});
1204 return; 1204 return;
1205 } 1205 }
1206 1206
1207 $pkglist = new PkgList; 1207 $pkglist = new PkgList;
1208 @categories = list_pkgsrc_categories($pkgsrcdir); 1208 @categories = list_pkgsrc_categories($pkgsrcdir);
1209 verbose('Scan Makefiles: '); 1209 verbose('Scan Makefiles: ');
1210 1210
1211 if (!$opt{L}) { 1211 if (!$opt{L}) {
1212 verbose('_' x @categories . "\b" x @categories); 1212 verbose('_' x @categories . "\b" x @categories);
1213 } else { 1213 } else {
1214 verbose("\n"); 1214 verbose("\n");
1215 } 1215 }
1216 1216
1217 foreach my $cat (sort @categories) { 1217 foreach my $cat (sort @categories) {
1218 foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) { 1218 foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) {
1219 my ($pkg, $vars) = parse_makefile_pkgsrc("$pkgsrcdir/$cat/$pkgdir/Makefile"); 1219 my ($pkg, $vars) = parse_makefile_pkgsrc("$pkgsrcdir/$cat/$pkgdir/Makefile");
1220 } 1220 }
1221 1221
1222 if (!$opt{L}) { 1222 if (!$opt{L}) {
1223 verbose('.'); 1223 verbose('.');
1224 } 1224 }
1225 } 1225 }
1226 1226
1227 if (!$opt{L}) { 1227 if (!$opt{L}) {
1228 my ($len); 1228 my ($len);
1229 1229
1230 $_ = $pkglist->numpkgver() . ' packages'; 1230 $_ = $pkglist->numpkgver() . ' packages';
1231 $len = @categories - length($_); 1231 $len = @categories - length($_);
1232 verbose("\b" x @categories, $_, ' ' x $len, "\b" x $len, "\n"); 1232 verbose("\b" x @categories, $_, ' ' x $len, "\b" x $len, "\n");
1233 } 1233 }
1234} 1234}
1235 1235
1236# Cross reference all depends 1236# Cross reference all depends
1237# 1237#
1238sub pkgsrc_check_depends() { 1238sub pkgsrc_check_depends() {
1239 1239
1240 foreach my $pkgver ($pkglist->pkgver) { 1240 foreach my $pkgver ($pkglist->pkgver) {
1241 my ($err, $msg); 1241 my ($err, $msg);
1242 1242
1243 defined $pkgver->var('DEPENDS') || next; 1243 defined $pkgver->var('DEPENDS') || next;
1244 foreach my $depend (split(" ", $pkgver->var('DEPENDS'))) { 1244 foreach my $depend (split(" ", $pkgver->var('DEPENDS'))) {
1245 1245
1246 $depend =~ s/:.*// || next; 1246 $depend =~ s/:.*// || next;
1247 1247
1248 $depend = canonicalize_pkgname($depend); 1248 $depend = canonicalize_pkgname($depend);
1249 if (($msg = invalid_version($depend))) { 1249 if (($msg = invalid_version($depend))) {
1250 if (!defined($err)) { 1250 if (!defined($err)) {
1251 print $pkgver->pkgname . " DEPENDS errors:\n"; 1251 print $pkgver->pkgname . " DEPENDS errors:\n";
1252 } 1252 }
1253 $err = 1; 1253 $err = 1;
1254 $msg =~ s/(\n)(.)/$1\t$2/g; 1254 $msg =~ s/(\n)(.)/$1\t$2/g;
1255 print "\t$msg"; 1255 print "\t$msg";
1256 } 1256 }
1257 } 1257 }
1258 } 1258 }
1259} 1259}
1260 1260
1261# Extract all distinfo entries, then verify contents of distfiles 1261# Extract all distinfo entries, then verify contents of distfiles
1262# 1262#
1263sub scan_pkgsrc_distfiles_vs_distinfo($$$$) { 1263sub scan_pkgsrc_distfiles_vs_distinfo($$$$) {
1264 my ($pkgsrcdir, $pkgdistdir, $check_unref, $check_distinfo) = @_; 1264 my ($pkgsrcdir, $pkgdistdir, $check_unref, $check_distinfo) = @_;
1265 my (@categories); 1265 my (@categories);
1266 my (%distfiles, %sumfiles, @distwarn, $numpkg); 1266 my (%distfiles, %sumfiles, @distwarn, $numpkg);
1267 my (%bad_distfiles); 1267 my (%bad_distfiles);
1268 1268
1269 @categories = list_pkgsrc_categories($pkgsrcdir); 1269 @categories = list_pkgsrc_categories($pkgsrcdir);
1270 1270
1271 verbose('Scan distinfo: ' . '_' x @categories . "\b" x @categories); 1271 verbose('Scan distinfo: ' . '_' x @categories . "\b" x @categories);
1272 $numpkg = 0; 1272 $numpkg = 0;
1273 foreach my $cat (sort @categories) { 1273 foreach my $cat (sort @categories) {
1274 foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) { 1274 foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) {
1275 if (open(DISTINFO, "$pkgsrcdir/$cat/$pkgdir/distinfo")) { 1275 if (open(DISTINFO, "$pkgsrcdir/$cat/$pkgdir/distinfo")) {
1276 ++$numpkg; 1276 ++$numpkg;
1277 while (<DISTINFO>) { 1277 while (<DISTINFO>) {
1278 if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) { 1278 if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) {
1279 my ($dn, $ds, $dt); 1279 my ($dn, $ds, $dt);
1280 $dt = $1; 1280 $dt = $1;
1281 $dn = $2; 1281 $dn = $2;
1282 $ds = $3; 1282 $ds = $3;
1283 if ($dn =~ /^patch-[\w.+\-]+$/) { 1283 if ($dn =~ /^patch-[\w.+\-]+$/) {
1284 next; 1284 next;
1285 } 1285 }
1286 1286
1287 # Strip leading ./ which sometimes gets added 1287 # Strip leading ./ which sometimes gets added
1288 # because of DISTSUBDIR=. 1288 # because of DISTSUBDIR=.
1289 $dn =~ s/^(\.\/)*//; 1289 $dn =~ s/^(\.\/)*//;
1290 if (!defined $distfiles{$dn}) { 1290 if (!defined $distfiles{$dn}) {
1291 $distfiles{$dn}{sumtype} = $dt; 1291 $distfiles{$dn}{sumtype} = $dt;
1292 $distfiles{$dn}{sum} = $ds; 1292 $distfiles{$dn}{sum} = $ds;
1293 $distfiles{$dn}{path} = "$cat/$pkgdir"; 1293 $distfiles{$dn}{path} = "$cat/$pkgdir";
1294 1294
1295 } elsif ($distfiles{$dn}{sumtype} eq $dt && $distfiles{$dn}{sum} ne $ds) { 1295 } elsif ($distfiles{$dn}{sumtype} eq $dt && $distfiles{$dn}{sum} ne $ds) {
1296 push(@distwarn, 1296 push(@distwarn,
1297 "checksum mismatch between '$dt' for '$dn' " 1297 "checksum mismatch between '$dt' for '$dn' "
1298 . "in $cat/$pkgdir and $distfiles{$dn}{path}\n" 1298 . "in $cat/$pkgdir and $distfiles{$dn}{path}\n"
1299 ); 1299 );
1300 } 1300 }
1301 } 1301 }
1302 } 1302 }
1303 close(DISTINFO); 1303 close(DISTINFO);
1304 } 1304 }
1305 } 1305 }
1306 verbose('.'); 1306 verbose('.');
1307 } 1307 }
1308 verbose(" ($numpkg packages)\n"); 1308 verbose(" ($numpkg packages)\n");
1309 1309
1310 # check each file in $pkgdistdir 1310 # check each file in $pkgdistdir
1311 find({ wanted => sub { 1311 find({ wanted => sub {
1312 my ($dist); 1312 my ($dist);
1313 if (-f $File::Find::name) { 1313 if (-f $File::Find::name) {
1314 my $distn = $File::Find::name; 1314 my $distn = $File::Find::name;
1315 $distn =~ s/$pkgdistdir\/?//g; 1315 $distn =~ s/$pkgdistdir\/?//g;
1316 #pkg/47516 ignore cvs dirs 1316 #pkg/47516 ignore cvs dirs
1317 return if $distn =~ m/^\.cvsignore/; 1317 return if $distn =~ m/^\.cvsignore/;
1318 return if $distn =~ m/^CVS\//; 1318 return if $distn =~ m/^CVS\//;
1319 if (!defined($dist = $distfiles{$distn})) { 1319 if (!defined($dist = $distfiles{$distn})) {
1320 $bad_distfiles{$distn} = 1; 1320 $bad_distfiles{$distn} = 1;
1321 } elsif ($dist->{sum} ne 'IGNORE') { 1321 } elsif ($dist->{sum} ne 'IGNORE') {
1322 push(@{$sumfiles{ $dist->{sumtype} }}, $distn); 1322 push(@{$sumfiles{ $dist->{sumtype} }}, $distn);
1323 } 1323 }
1324 } 1324 }
1325 } }, 1325 } },
1326 ($pkgdistdir)); 1326 ($pkgdistdir));
1327 1327
1328 if ($check_unref && %bad_distfiles) { 1328 if ($check_unref && %bad_distfiles) {
1329 verbose(scalar(keys %bad_distfiles), 1329 verbose(scalar(keys %bad_distfiles),
1330 " unreferenced file(s) in '$pkgdistdir':\n"); 1330 " unreferenced file(s) in '$pkgdistdir':\n");
1331 print join("\n", sort keys %bad_distfiles), "\n"; 1331 print join("\n", sort keys %bad_distfiles), "\n";
1332 } 1332 }
1333 1333
1334 if ($check_distinfo) { 1334 if ($check_distinfo) {
1335 if (@distwarn) { 1335 if (@distwarn) {
1336 verbose(@distwarn); 1336 verbose(@distwarn);
1337 } 1337 }
1338 1338
1339 verbose("checksum mismatches\n"); 1339 verbose("checksum mismatches\n");
1340 safe_chdir($pkgdistdir); 1340 safe_chdir($pkgdistdir);
1341 foreach my $sum (keys %sumfiles) { 1341 foreach my $sum (keys %sumfiles) {
1342 if ($sum eq 'Size') { 1342 if ($sum eq 'Size') {
1343 foreach my $file (@{$sumfiles{$sum}}) { 1343 foreach my $file (@{$sumfiles{$sum}}) {
1344 if (!-f $file || -S $file != $distfiles{$file}{sum}) { 1344 if (!-f $file || -S $file != $distfiles{$file}{sum}) {
1345 print $file, " (Size)\n"; 1345 print $file, " (Size)\n";
1346 $bad_distfiles{$file} = 1; 1346 $bad_distfiles{$file} = 1;
1347 } 1347 }
1348 } 1348 }
1349 next; 1349 next;
1350 } 1350 }
1351 1351
1352 my $pid = open3(my $in, my $out, undef, "xargs", "digest", $sum); 1352 my $pid = open3(my $in, my $out, undef, "xargs", "digest", $sum);
1353 defined($pid) || fail "fork"; 1353 defined($pid) || fail "fork";
1354 my $pid2 = fork(); 1354 my $pid2 = fork();
1355 defined($pid2) || fail "fork"; 1355 defined($pid2) || fail "fork";
1356 if ($pid2) { 1356 if ($pid2) {
1357 close($in); 1357 close($in);
1358 } else { 1358 } else {
1359 print $in "@{$sumfiles{$sum}}"; 1359 print $in "@{$sumfiles{$sum}}";
1360 exit 0; 1360 exit 0;
1361 } 1361 }
1362 while (<$out>) { 1362 while (<$out>) {
1363 if (m/^$sum ?\(([^\)]+)\) = (\S+)/) { 1363 if (m/^$sum ?\(([^\)]+)\) = (\S+)/) {
1364 if ($distfiles{$1}{sum} ne $2) { 1364 if ($distfiles{$1}{sum} ne $2) {
1365 print $1, " ($sum)\n"; 1365 print $1, " ($sum)\n";
1366 $bad_distfiles{$1} = 1; 1366 $bad_distfiles{$1} = 1;
1367 } 1367 }
1368 } 1368 }
1369 } 1369 }
1370 close($out); 1370 close($out);
1371 waitpid($pid, 0) || fail "xargs digest $sum"; 1371 waitpid($pid, 0) || fail "xargs digest $sum";
1372 waitpid($pid2, 0) || fail "pipe write to xargs"; 1372 waitpid($pid2, 0) || fail "pipe write to xargs";
1373 } 1373 }
1374 safe_chdir('/'); # Do not want to stay in $pkgdistdir 1374 safe_chdir('/'); # Do not want to stay in $pkgdistdir
1375 } 1375 }
1376 (sort keys %bad_distfiles); 1376 (sort keys %bad_distfiles);
1377} 1377}
1378 1378
1379sub store_pkgsrc_makefiles($) { 1379sub store_pkgsrc_makefiles($) {
1380 open(STORE, ">$_[0]") || die("Cannot save pkgsrc store to $_[0]: $!\n"); 1380 open(STORE, ">$_[0]") || die("Cannot save pkgsrc store to $_[0]: $!\n");
1381 my $was = select(STORE); 1381 my $was = select(STORE);
1382 print( 1382 print(
1383 'sub __pkgcount { $subpkgnum += $_[0]; ', 1383 'sub __pkgcount { $subpkgnum += $_[0]; ',
1384 'verbose("\rReading pkgsrc database: ', 1384 'verbose("\rReading pkgsrc database: ',
1385 '$pkgnum / $pkgcnt ($subpkgnum / $subpkgcnt) pkgs"); }', 1385 '$pkgnum / $pkgcnt ($subpkgnum / $subpkgcnt) pkgs"); }',
1386 "\n" 1386 "\n"
1387 ); 1387 );
1388 $pkglist->store; 1388 $pkglist->store;
1389 print("verbose(\"...done\\n\");\n"); 1389 print("verbose(\"...done\\n\");\n");
1390 select($was); 1390 select($was);
1391 close(STORE); 1391 close(STORE);
1392} 1392}
1393 1393
1394# Remember to update manual page when modifying option list 1394# Remember to update manual page when modifying option list
1395# 1395#
1396sub usage_and_exit() { 1396sub usage_and_exit() {
1397 print "Usage: lintpkgsrc [opts] [makefiles] 1397 print "Usage: lintpkgsrc [opts] [makefiles]
1398opts: 1398opts:
1399 -h : This help. [see lintpkgsrc(1) for more information] 1399 -h : This help. [see lintpkgsrc(1) for more information]
1400 1400
1401Installed package options: Distfile options: 1401Installed package options: Distfile options:
1402 -i : Check version against pkgsrc -m : List distinfo mismatches 1402 -i : Check version against pkgsrc -m : List distinfo mismatches
1403 -u : As -i + fetch dist (may change) -o : List obsolete (no distinfo) 1403 -u : As -i + fetch dist (may change) -o : List obsolete (no distinfo)
1404 -y : Remove orphan distfiles 1404 -y : Remove orphan distfiles
1405 -z : Remove installed distfiles 1405 -z : Remove installed distfiles
1406 1406
1407Prebuilt package options: Makefile options: 1407Prebuilt package options: Makefile options:
1408 -p : List old/obsolete -B : List packages marked as 'BROKEN' 1408 -p : List old/obsolete -B : List packages marked as 'BROKEN'
1409 -O : List OSVERSION_SPECIFIC -d : Check 'DEPENDS' up to date 1409 -O : List OSVERSION_SPECIFIC -d : Check 'DEPENDS' up to date
1410 -R : List NO_BIN_ON_FTP/RESTRICTED -S : List packages not in 'SUBDIRS' 1410 -R : List NO_BIN_ON_FTP/RESTRICTED -S : List packages not in 'SUBDIRS'
1411 1411
1412Misc: 1412Misc:
1413 -E file : Export the internal pkgsrc database to file 1413 -E file : Export the internal pkgsrc database to file
1414 -I file : Import the internal pkgsrc database to file (for use with -i) 1414 -I file : Import the internal pkgsrc database to file (for use with -i)
1415 -g file : Generate 'pkgname pkgdir pkgver' map in file 1415 -g file : Generate 'pkgname pkgdir pkgver' map in file
1416 -r : Remove bad files (Without -m -o -p or -V implies all, can use -R) 1416 -r : Remove bad files (Without -m -o -p or -V implies all, can use -R)
1417 1417
1418Modifiers: 1418Modifiers:
1419 -K path : Set PACKAGES basedir (default PKGSRCDIR/packages) 1419 -K path : Set PACKAGES basedir (default PKGSRCDIR/packages)
1420 -M path : Set DISTDIR (default PKGSRCDIR/distfiles) 1420 -M path : Set DISTDIR (default PKGSRCDIR/distfiles)
1421 -P path : Set PKGSRCDIR (default $conf_pkgsrcdir) 1421 -P path : Set PKGSRCDIR (default $conf_pkgsrcdir)
1422 -D : Debug makefile and glob parsing 1422 -D : Debug makefile and glob parsing
1423 -L : List each Makefile when scanned 1423 -L : List each Makefile when scanned
1424"; 1424";
1425 exit; 1425 exit;
1426} 1426}
1427 1427
1428# Could speed up by building a cache of package names to paths, then processing 1428# Could speed up by building a cache of package names to paths, then processing
1429# each package name once against the tests. 1429# each package name once against the tests.
1430sub check_prebuilt_packages() { 1430sub check_prebuilt_packages() {
1431 1431
1432 if ($_ eq 'distfiles' || $_ eq 'pkgsrc') { 1432 if ($_ eq 'distfiles' || $_ eq 'pkgsrc') {
1433 # Skip these subdirs if present 1433 # Skip these subdirs if present
1434 $File::Find::prune = 1; 1434 $File::Find::prune = 1;
1435 1435
1436 } elsif (/(.+)-(\d.*)\.t[bg]z$/) { 1436 } elsif (/(.+)-(\d.*)\.t[bg]z$/) {
1437 my ($pkg, $ver) = ($1, $2); 1437 my ($pkg, $ver) = ($1, $2);
1438 1438
1439 $pkg = canonicalize_pkgname($pkg); 1439 $pkg = canonicalize_pkgname($pkg);
1440 1440
1441 my ($pkgs); 1441 my ($pkgs);
1442 if ($pkgs = $pkglist->pkgs($pkg)) { 1442 if ($pkgs = $pkglist->pkgs($pkg)) {
1443 my ($pkgver) = $pkgs->pkgver($ver); 1443 my ($pkgver) = $pkgs->pkgver($ver);
1444 1444
1445 if (!defined $pkgver) { 1445 if (!defined $pkgver) {
1446 if ($opt{p}) { 1446 if ($opt{p}) {
1447 print "$File::Find::dir/$_\n"; 1447 print "$File::Find::dir/$_\n";
1448 push(@matched_prebuiltpackages, "$File::Find::dir/$_"); 1448 push(@matched_prebuiltpackages, "$File::Find::dir/$_");
1449 } 1449 }
1450 1450
1451 # Pick probably the last version 1451 # Pick probably the last version
1452 $pkgver = $pkgs->latestver; 1452 $pkgver = $pkgs->latestver;
1453 } 1453 }
1454 1454
1455 if ($opt{R} && $pkgver->var('RESTRICTED')) { 1455 if ($opt{R} && $pkgver->var('RESTRICTED')) {
1456 print "$File::Find::dir/$_\n"; 1456 print "$File::Find::dir/$_\n";
1457 push(@matched_prebuiltpackages, "$File::Find::dir/$_"); 1457 push(@matched_prebuiltpackages, "$File::Find::dir/$_");
1458 } 1458 }
1459 1459
1460 if ($opt{O} && $pkgver->var('OSVERSION_SPECIFIC')) { 1460 if ($opt{O} && $pkgver->var('OSVERSION_SPECIFIC')) {
1461 print "$File::Find::dir/$_\n"; 1461 print "$File::Find::dir/$_\n";
1462 push(@matched_prebuiltpackages, "$File::Find::dir/$_"); 1462 push(@matched_prebuiltpackages, "$File::Find::dir/$_");
1463 } 1463 }
1464 } 1464 }
1465 1465
1466 } elsif (-d $_) { 1466 } elsif (-d $_) {
1467 if ($prebuilt_pkgdir_cache{"$File::Find::dir/$_"}) { 1467 if ($prebuilt_pkgdir_cache{"$File::Find::dir/$_"}) {
1468 $File::Find::prune = 1; 1468 $File::Find::prune = 1;
1469 return; 1469 return;
1470 } 1470 }
1471 1471
1472 $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} = 1; 1472 $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} = 1;
1473 if (-l $_) { 1473 if (-l $_) {
1474 my ($dest) = readlink($_); 1474 my ($dest) = readlink($_);
1475 1475
1476 if (substr($dest, 0, 1) ne '/') { 1476 if (substr($dest, 0, 1) ne '/') {
1477 $dest = "$File::Find::dir/$dest"; 1477 $dest = "$File::Find::dir/$dest";
1478 } 1478 }
1479 if (!$prebuilt_pkgdir_cache{$dest}) { 1479 if (!$prebuilt_pkgdir_cache{$dest}) {
1480 push(@prebuilt_pkgdirs, $dest); 1480 push(@prebuilt_pkgdirs, $dest);
1481 } 1481 }
1482 } 1482 }
1483 } 1483 }
1484} 1484}
1485 1485
1486sub main() { 1486sub main() {
1487 1487
1488 $ENV{PATH} .= 1488 $ENV{PATH} .=
1489 ":/bin:/usr/bin:/sbin:/usr/sbin:$conf_prefix/sbin:$conf_prefix/bin"; 1489 ":/bin:/usr/bin:/sbin:/usr/sbin:$conf_prefix/sbin:$conf_prefix/bin";
1490 1490
1491 if ( 1491 if (
1492 !getopts('BDE:I:K:LM:OP:RSVdg:himopruyz', \%opt) 1492 !getopts('BDE:I:K:LM:OP:RSVdg:himopruyz', \%opt)
1493 || $opt{h} 1493 || $opt{h}
1494 || !(defined $opt{d} 1494 || !(defined $opt{d}
1495 || defined $opt{g} 1495 || defined $opt{g}
1496 || defined $opt{i} 1496 || defined $opt{i}
1497 || defined $opt{m} 1497 || defined $opt{m}
1498 || defined $opt{o} 1498 || defined $opt{o}
1499 || defined $opt{p} 1499 || defined $opt{p}
1500 || defined $opt{r} 1500 || defined $opt{r}
1501 || defined $opt{u} 1501 || defined $opt{u}
1502 || defined $opt{B} 1502 || defined $opt{B}
1503 || defined $opt{D} 1503 || defined $opt{D}
1504 || defined $opt{R} 1504 || defined $opt{R}
1505 || defined $opt{O} 1505 || defined $opt{O}
1506 || defined $opt{S} 1506 || defined $opt{S}
1507 || defined $opt{E} 1507 || defined $opt{E}
1508 || defined $opt{y} 1508 || defined $opt{y}
1509 || defined $opt{z})) { 1509 || defined $opt{z})) {
1510 usage_and_exit(); 1510 usage_and_exit();
1511 } 1511 }
1512 $| = 1; 1512 $| = 1;
1513 1513
1514 get_default_makefile_vars(); # $default_vars 1514 get_default_makefile_vars(); # $default_vars
1515 1515
1516 if ($opt{D} && @ARGV) { 1516 if ($opt{D} && @ARGV) {
1517 foreach my $file (@ARGV) { 1517 foreach my $file (@ARGV) {
1518 if (-d $file) { 1518 if (-d $file) {
1519 $file .= "/Makefile"; 1519 $file .= "/Makefile";
1520 } 1520 }
1521 if (!-f $file) { 1521 if (!-f $file) {
1522 fail("No such file: $file"); 1522 fail("No such file: $file");
1523 } 1523 }
1524 my ($pkgname, $vars) = parse_makefile_pkgsrc($file); 1524 my ($pkgname, $vars) = parse_makefile_pkgsrc($file);
1525 $pkgname ||= 'uNDEFINEd'; 1525 $pkgname ||= 'uNDEFINEd';
1526 print "$file -> $pkgname\n"; 1526 print "$file -> $pkgname\n";
1527 foreach my $varname (sort keys %{$vars}) { 1527 foreach my $varname (sort keys %{$vars}) {
1528 print "\t$varname = $vars->{$varname}\n"; 1528 print "\t$varname = $vars->{$varname}\n";
1529 } 1529 }
1530 1530
1531 #if ($opt{d}) { 1531 #if ($opt{d}) {
1532 # pkgsrc_check_depends(); 1532 # pkgsrc_check_depends();
1533 #} 1533 #}
1534 } 1534 }
1535 exit; 1535 exit;
1536 } 1536 }
1537 1537
1538 my $pkgsrcdir = $default_vars->{PKGSRCDIR}; 1538 my $pkgsrcdir = $default_vars->{PKGSRCDIR};
1539 my $pkgdistdir = $default_vars->{DISTDIR}; 1539 my $pkgdistdir = $default_vars->{DISTDIR};
1540 1540
1541 if ($opt{r} && !$opt{o} && !$opt{m} && !$opt{p}) { 1541 if ($opt{r} && !$opt{o} && !$opt{m} && !$opt{p}) {
1542 $opt{o} = $opt{m} = $opt{p} = 1; 1542 $opt{o} = $opt{m} = $opt{p} = 1;
1543 } 1543 }
1544 if ($opt{o} || $opt{m}) { 1544 if ($opt{o} || $opt{m}) {
1545 my (@baddist); 1545 my (@baddist);
1546 1546
1547 @baddist = scan_pkgsrc_distfiles_vs_distinfo( 1547 @baddist = scan_pkgsrc_distfiles_vs_distinfo(
1548 $pkgsrcdir, $pkgdistdir, $opt{o}, $opt{m}); 1548 $pkgsrcdir, $pkgdistdir, $opt{o}, $opt{m});
1549 if ($opt{r}) { 1549 if ($opt{r}) {
1550 verbose("Unlinking 'bad' distfiles\n"); 1550 verbose("Unlinking 'bad' distfiles\n");
1551 foreach my $distfile (@baddist) { 1551 foreach my $distfile (@baddist) {
1552 unlink("$pkgdistdir/$distfile"); 1552 unlink("$pkgdistdir/$distfile");
1553 } 1553 }
1554 } 1554 }
1555 } 1555 }
1556 1556
1557 # Remove all distfiles that are / are not part of an installed package 1557 # Remove all distfiles that are / are not part of an installed package
1558 if ($opt{y} || $opt{z}) { 1558 if ($opt{y} || $opt{z}) {
1559 my (@pkgs, @installed, %distfiles, @pkgdistfiles, @dldistfiles); 1559 my (@pkgs, @installed, %distfiles, @pkgdistfiles, @dldistfiles);
1560 my (@tmpdistfiles, @orphan, $found, @parent); 1560 my (@tmpdistfiles, @orphan, $found, @parent);
1561 1561
1562 @pkgs = list_installed_packages(); 1562 @pkgs = list_installed_packages();
1563 scan_pkgsrc_makefiles($pkgsrcdir); 1563 scan_pkgsrc_makefiles($pkgsrcdir);
1564 1564
1565 # list the installed packages and the directory they live in 1565 # list the installed packages and the directory they live in
1566 foreach my $pkgname (sort @pkgs) { 1566 foreach my $pkgname (sort @pkgs) {
1567 if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) { 1567 if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) {
1568 foreach my $pkgver ($pkglist->pkgver($1)) { 1568 foreach my $pkgver ($pkglist->pkgver($1)) {
1569 $pkgver->var('dir') =~ /-current/ && next; 1569 $pkgver->var('dir') =~ /-current/ && next;
1570 push(@installed, $pkgver); 1570 push(@installed, $pkgver);
1571 last; 1571 last;
1572 } 1572 }
1573 } 1573 }
1574 } 1574 }
1575 1575
1576 # distfiles belonging to the currently installed packages 1576 # distfiles belonging to the currently installed packages
1577 foreach my $pkgver (sort @installed) { 1577 foreach my $pkgver (sort @installed) {
1578 if (open(DISTINFO, "$pkgsrcdir/" . $pkgver->var('dir') . "/distinfo")) { 1578 if (open(DISTINFO, "$pkgsrcdir/" . $pkgver->var('dir') . "/distinfo")) {
1579 while (<DISTINFO>) { 1579 while (<DISTINFO>) {
1580 if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) { 1580 if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) {
1581 my ($dn); 1581 my ($dn);
1582 if ($2 =~ /^patch-[\w.+\-]+$/) { next; } 1582 if ($2 =~ /^patch-[\w.+\-]+$/) { next; }
1583 $dn = $2; 1583 $dn = $2;
1584 # Strip leading ./ which sometimes gets added 1584 # Strip leading ./ which sometimes gets added
1585 # because of DISTSUBDIR=. 1585 # because of DISTSUBDIR=.
1586 $dn =~ s/^(\.\/)*//; 1586 $dn =~ s/^(\.\/)*//;
1587 if (!defined $distfiles{$dn}) { 1587 if (!defined $distfiles{$dn}) {
1588 $distfiles{$dn}{name} = $dn; 1588 $distfiles{$dn}{name} = $dn;
1589 push(@pkgdistfiles, $dn); 1589 push(@pkgdistfiles, $dn);
1590 } 1590 }
1591 } 1591 }
1592 } 1592 }
1593 close(DISTINFO); 1593 close(DISTINFO);
1594 } 1594 }
1595 } 1595 }
1596 1596
1597 # distfiles downloaded on the current system 1597 # distfiles downloaded on the current system
1598 @tmpdistfiles = listdir("$pkgdistdir", undef); 1598 @tmpdistfiles = listdir("$pkgdistdir", undef);
1599 foreach my $tmppkg (@tmpdistfiles) { 1599 foreach my $tmppkg (@tmpdistfiles) {
1600 if ($tmppkg ne "pkg-vulnerabilities") { 1600 if ($tmppkg ne "pkg-vulnerabilities") {
1601 push(@dldistfiles, $tmppkg); 1601 push(@dldistfiles, $tmppkg);
1602 } 1602 }
1603 } 1603 }
1604 1604
1605 # sort the two arrays to make searching a bit faster 1605 # sort the two arrays to make searching a bit faster
1606 @dldistfiles = sort { $a cmp $b } @dldistfiles; 1606 @dldistfiles = sort { $a cmp $b } @dldistfiles;
1607 @pkgdistfiles = sort { $a cmp $b } @pkgdistfiles; 1607 @pkgdistfiles = sort { $a cmp $b } @pkgdistfiles;
1608 1608
1609 if ($opt{y}) { 1609 if ($opt{y}) {
1610 # looking for files that are downloaded on the current system 1610 # looking for files that are downloaded on the current system
1611 # but do not belong to any currently installed package i.e. orphaned 1611 # but do not belong to any currently installed package i.e. orphaned
1612 $found = 0; 1612 $found = 0;
1613 foreach my $dldf (@dldistfiles) { 1613 foreach my $dldf (@dldistfiles) {
1614 foreach my $pkgdf (@pkgdistfiles) { 1614 foreach my $pkgdf (@pkgdistfiles) {
1615 if ($dldf eq $pkgdf) { 1615 if ($dldf eq $pkgdf) {
1616 $found = 1; 1616 $found = 1;
1617 } 1617 }
1618 } 1618 }
1619 if ($found != 1) { 1619 if ($found != 1) {
1620 push(@orphan, $dldf); 1620 push(@orphan, $dldf);
1621 print "Orphaned file: $dldf\n"; 1621 print "Orphaned file: $dldf\n";
1622 } 1622 }
1623 $found = 0; 1623 $found = 0;
1624 } 1624 }
1625 1625
1626 if ($opt{r}) { 1626 if ($opt{r}) {
1627 safe_chdir("$pkgdistdir"); 1627 safe_chdir("$pkgdistdir");
1628 verbose("Unlinking 'orphaned' distfiles\n"); 1628 verbose("Unlinking 'orphaned' distfiles\n");
1629 foreach my $distfile (@orphan) { 1629 foreach my $distfile (@orphan) {
1630 unlink($distfile) 1630 unlink($distfile)
1631 } 1631 }
1632 } 1632 }
1633 } 1633 }
1634 1634
1635 if ($opt{z}) { 1635 if ($opt{z}) {
1636 # looking for files that are downloaded on the current system 1636 # looking for files that are downloaded on the current system
1637 # but belong to a currently installed package i.e. parented 1637 # but belong to a currently installed package i.e. parented
1638 $found = 0; 1638 $found = 0;
1639 foreach my $pkgdf (@pkgdistfiles) { 1639 foreach my $pkgdf (@pkgdistfiles) {
1640 foreach my $dldf (@dldistfiles) { 1640 foreach my $dldf (@dldistfiles) {
1641 if ($pkgdf eq $dldf) { 1641 if ($pkgdf eq $dldf) {
1642 $found = 1; 1642 $found = 1;
1643 } 1643 }
1644 } 1644 }
1645 if ($found == 1) { 1645 if ($found == 1) {
1646 push(@parent, $pkgdf); 1646 push(@parent, $pkgdf);
1647 print "Parented file: $pkgdf\n"; 1647 print "Parented file: $pkgdf\n";
1648 } 1648 }
1649 $found = 0; 1649 $found = 0;
1650 } 1650 }
1651 } 1651 }
1652 1652
1653 if ($opt{r}) { 1653 if ($opt{r}) {
1654 safe_chdir("$pkgdistdir"); 1654 safe_chdir("$pkgdistdir");
1655 verbose("Unlinking 'parented' distfiles\n"); 1655 verbose("Unlinking 'parented' distfiles\n");
1656 foreach my $distfile (@parent) { 1656 foreach my $distfile (@parent) {
1657 unlink($distfile); 1657 unlink($distfile);
1658 } 1658 }
1659 } 1659 }
1660 } 1660 }
1661 1661
1662 # List BROKEN packages 1662 # List BROKEN packages
1663 if ($opt{B}) { 1663 if ($opt{B}) {
1664 scan_pkgsrc_makefiles($pkgsrcdir); 1664 scan_pkgsrc_makefiles($pkgsrcdir);
1665 foreach my $pkgver ($pkglist->pkgver) { 1665 foreach my $pkgver ($pkglist->pkgver) {
1666 $pkgver->var('BROKEN') || next; 1666 $pkgver->var('BROKEN') || next;
1667 print $pkgver->pkgname . ': ' . $pkgver->var('BROKEN') . "\n"; 1667 print $pkgver->pkgname . ': ' . $pkgver->var('BROKEN') . "\n";
1668 } 1668 }
1669 } 1669 }
1670 1670
1671 # List obsolete or NO_BIN_ON_FTP/RESTRICTED prebuilt packages 1671 # List obsolete or NO_BIN_ON_FTP/RESTRICTED prebuilt packages
1672 # 1672 #
1673 if ($opt{p} || $opt{O} || $opt{R}) { 1673 if ($opt{p} || $opt{O} || $opt{R}) {
1674 scan_pkgsrc_makefiles($pkgsrcdir); 1674 scan_pkgsrc_makefiles($pkgsrcdir);
1675 1675
1676 @prebuilt_pkgdirs = ($default_vars->{PACKAGES}); 1676 @prebuilt_pkgdirs = ($default_vars->{PACKAGES});
1677 %prebuilt_pkgdir_cache = (); 1677 %prebuilt_pkgdir_cache = ();
1678 1678
1679 while (@prebuilt_pkgdirs) { 1679 while (@prebuilt_pkgdirs) {
1680 find(\&check_prebuilt_packages, shift @prebuilt_pkgdirs); 1680 find(\&check_prebuilt_packages, shift @prebuilt_pkgdirs);
1681 } 1681 }
1682 1682
1683 if ($opt{r}) { 1683 if ($opt{r}) {
1684 verbose("Unlinking listed prebuilt packages\n"); 1684 verbose("Unlinking listed prebuilt packages\n");
1685 foreach my $pkgfile (@matched_prebuiltpackages) { 1685 foreach my $pkgfile (@matched_prebuiltpackages) {
1686 unlink($pkgfile); 1686 unlink($pkgfile);
1687 } 1687 }
1688 } 1688 }
1689 } 1689 }
1690 1690
1691 if ($opt{S}) { 1691 if ($opt{S}) {
1692 my (%in_subdir); 1692 my (%in_subdir);
1693 1693
1694 foreach my $cat (list_pkgsrc_categories($pkgsrcdir)) { 1694 foreach my $cat (list_pkgsrc_categories($pkgsrcdir)) {
1695 my $vars = parse_makefile_vars("$pkgsrcdir/$cat/Makefile", undef); 1695 my $vars = parse_makefile_vars("$pkgsrcdir/$cat/Makefile", undef);
1696 1696
1697 if (!$vars->{SUBDIR}) { 1697 if (!$vars->{SUBDIR}) {
1698 print "Warning - no SUBDIR for $cat\n"; 1698 print "Warning - no SUBDIR for $cat\n";
1699 next; 1699 next;
1700 } 1700 }
1701 foreach my $pkgdir (split(/\s+/, $vars->{SUBDIR})) { 1701 foreach my $pkgdir (split(/\s+/, $vars->{SUBDIR})) {
1702 $in_subdir{"$cat/$pkgdir"} = 1; 1702 $in_subdir{"$cat/$pkgdir"} = 1;
1703 } 1703 }
1704 } 1704 }
1705 1705
1706 scan_pkgsrc_makefiles($pkgsrcdir); 1706 scan_pkgsrc_makefiles($pkgsrcdir);
1707 foreach my $pkgver ($pkglist->pkgver) { 1707 foreach my $pkgver ($pkglist->pkgver) {
1708 if (!defined $in_subdir{ $pkgver->var('dir') }) { 1708 if (!defined $in_subdir{ $pkgver->var('dir') }) {
1709 print $pkgver->var('dir') . ": Not in SUBDIR\n"; 1709 print $pkgver->var('dir') . ": Not in SUBDIR\n";
1710 } 1710 }
1711 } 1711 }
1712 } 1712 }
1713 1713
1714 if ($opt{g}) { 1714 if ($opt{g}) {
1715 my $tmpfile = "$opt{g}.tmp.$$"; 1715 my $tmpfile = "$opt{g}.tmp.$$";
1716 1716
1717 scan_pkgsrc_makefiles($pkgsrcdir); 1717 scan_pkgsrc_makefiles($pkgsrcdir);
1718 if (!open(TABLE, ">$tmpfile")) { 1718 if (!open(TABLE, ">$tmpfile")) {
1719 fail("Unable to write '$tmpfile': $!"); 1719 fail("Unable to write '$tmpfile': $!");
1720 } 1720 }
1721 foreach my $pkgver ($pkglist->pkgver) { 1721 foreach my $pkgver ($pkglist->pkgver) {
1722 print TABLE $pkgver->pkg . "\t" 1722 print TABLE $pkgver->pkg . "\t"
1723 . $pkgver->var('dir') . "\t" 1723 . $pkgver->var('dir') . "\t"
1724 . $pkgver->ver . "\n"; 1724 . $pkgver->ver . "\n";
1725 } 1725 }
1726 if (!close(TABLE)) { 1726 if (!close(TABLE)) {
1727 fail("Error while writing '$tmpfile': $!"); 1727 fail("Error while writing '$tmpfile': $!");
1728 } 1728 }
1729 if (!rename($tmpfile, $opt{g})) { 1729 if (!rename($tmpfile, $opt{g})) {
1730 fail("Error in rename('$tmpfile','$opt{g}'): $!"); 1730 fail("Error in rename('$tmpfile','$opt{g}'): $!");
1731 } 1731 }
1732 } 1732 }
1733 1733
1734 if ($opt{d}) { 1734 if ($opt{d}) {
1735 scan_pkgsrc_makefiles($pkgsrcdir); 1735 scan_pkgsrc_makefiles($pkgsrcdir);
1736 pkgsrc_check_depends(); 1736 pkgsrc_check_depends();
1737 } 1737 }
1738 1738
1739 if ($opt{i} || $opt{u}) { 1739 if ($opt{i} || $opt{u}) {
1740 my (@pkgs, @update); 1740 my (@pkgs, @update);
1741 1741
1742 @pkgs = list_installed_packages(); 1742 @pkgs = list_installed_packages();
1743 scan_pkgsrc_makefiles($pkgsrcdir); 1743 scan_pkgsrc_makefiles($pkgsrcdir);
1744 1744
1745 foreach my $pkgname (sort @pkgs) { 1745 foreach my $pkgname (sort @pkgs) {
1746 if ($_ = invalid_version($pkgname)) { 1746 if ($_ = invalid_version($pkgname)) {
1747 print $_; 1747 print $_;
1748 1748
1749 if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) { 1749 if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) {
1750 foreach my $pkgver ($pkglist->pkgver($1)) { 1750 foreach my $pkgver ($pkglist->pkgver($1)) {
1751 $pkgver->var('dir') =~ /-current/ && next; 1751 $pkgver->var('dir') =~ /-current/ && next;
1752 push(@update, $pkgver); 1752 push(@update, $pkgver);
1753 last; 1753 last;
1754 } 1754 }
1755 } 1755 }
1756 } 1756 }
1757 } 1757 }
1758 1758
1759 if ($opt{u}) { 1759 if ($opt{u}) {
1760 print "\nREQUIRED details for packages that could be updated:\n"; 1760 print "\nREQUIRED details for packages that could be updated:\n";
1761 1761
1762 foreach my $pkgver (@update) { 1762 foreach my $pkgver (@update) {
1763 print $pkgver->pkg . ':'; 1763 print $pkgver->pkg . ':';
1764 if (open(PKGINFO, 'pkg_info -R ' . $pkgver->pkg . '|')) { 1764 if (open(PKGINFO, 'pkg_info -R ' . $pkgver->pkg . '|')) {
1765 my ($list); 1765 my ($list);
1766 1766
1767 while (<PKGINFO>) { 1767 while (<PKGINFO>) {
1768 if (/Required by:/) { 1768 if (/Required by:/) {
1769 $list = 1; 1769 $list = 1;
1770 } elsif ($list) { 1770 } elsif ($list) {
1771 chomp; 1771 chomp;
1772 s/-\d.*//; 1772 s/-\d.*//;
1773 print " $_"; 1773 print " $_";
1774 } 1774 }
1775 } 1775 }
1776 close(PKGINFO); 1776 close(PKGINFO);
1777 } 1777 }
1778 print "\n"; 1778 print "\n";
1779 } 1779 }
1780 1780
1781 print "\nRunning '$conf_make fetch-list | sh' for each package:\n"; 1781 print "\nRunning '$conf_make fetch-list | sh' for each package:\n";
1782 foreach my $pkgver (@update) { 1782 foreach my $pkgver (@update) {
1783 my ($pkgdir); 1783 my ($pkgdir);
1784 1784
1785 $pkgdir = $pkgver->var('dir'); 1785 $pkgdir = $pkgver->var('dir');
1786 if (!defined($pkgdir)) { 1786 if (!defined($pkgdir)) {
1787 fail('Unable to determine ' . $pkgver->pkg . ' directory'); 1787 fail('Unable to determine ' . $pkgver->pkg . ' directory');
1788 } 1788 }
1789 1789
1790 print "$pkgsrcdir/$pkgdir\n"; 1790 print "$pkgsrcdir/$pkgdir\n";
1791 safe_chdir("$pkgsrcdir/$pkgdir"); 1791 safe_chdir("$pkgsrcdir/$pkgdir");
1792 system("$conf_make fetch-list | sh"); 1792 system("$conf_make fetch-list | sh");
1793 } 1793 }
1794 } 1794 }
1795 } 1795 }
1796 1796
1797 if ($opt{E}) { 1797 if ($opt{E}) {
1798 scan_pkgsrc_makefiles($pkgsrcdir); 1798 scan_pkgsrc_makefiles($pkgsrcdir);
1799 store_pkgsrc_makefiles($opt{E}); 1799 store_pkgsrc_makefiles($opt{E});
1800 } 1800 }
1801} 1801}
1802 1802
1803main(); 1803main() unless $ENV{'TESTING_LINTPKGSRC'} eq 'yes';

File Added: pkgsrc/pkgtools/lintpkgsrc/files/t/pkgversion.t
# $NetBSD: pkgversion.t,v 1.1 2022/07/30 10:11:45 rillig Exp $
use strict;
use warnings;
use Test;

BEGIN { plan tests => 5; }

$ENV{'TESTING_LINTPKGSRC'} = 'yes';
require('../lintpkgsrc.pl');

ok(pkgversioncmp('3.4', '<', '3.4'), '');
ok(pkgversioncmp('3.4', '<=', '3.4'), 1);
ok(pkgversioncmp('3.4', '>=', '3.4.0.0.0'), 1);
ok(pkgversioncmp('3.4nb13', '>=', '3.4'), 1);
ok(pkgversioncmp('3.4nb13', '<', '3.4'), '');