| @@ -1,15 +1,15 @@ | | | @@ -1,15 +1,15 @@ |
1 | #!@PERL5@ | | 1 | #!@PERL5@ |
2 | # $NetBSD: lintpkgsrc.pl,v 1.89 2022/08/14 03:06:41 rillig Exp $ | | 2 | # $NetBSD: lintpkgsrc.pl,v 1.90 2022/08/14 03:12:02 rillig Exp $ |
3 | | | 3 | |
4 | # Written by David Brownlee <abs@netbsd.org>. | | 4 | # Written by David Brownlee <abs@netbsd.org>. |
5 | # | | 5 | # |
6 | # Caveats: | | 6 | # Caveats: |
7 | # The 'Makefile parsing' algorithm used to obtain package versions and | | 7 | # The 'Makefile parsing' algorithm used to obtain package versions and |
8 | # DEPENDS information is geared towards speed rather than perfection, | | 8 | # DEPENDS information is geared towards speed rather than perfection, |
9 | # though it has gotten somewhat better over time, it only parses the | | 9 | # though it has gotten somewhat better over time, it only parses the |
10 | # simpler Makefile conditionals. | | 10 | # simpler Makefile conditionals. |
11 | # | | 11 | # |
12 | # TODO: Handle fun DEPENDS like avifile-devel with | | 12 | # TODO: Handle fun DEPENDS like avifile-devel with |
13 | # {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} | | 13 | # {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} |
14 | | | 14 | |
15 | use v5.36; | | 15 | use v5.36; |
| @@ -297,56 +297,55 @@ sub eval_mk_cond_func($func, $arg, $vars | | | @@ -297,56 +297,55 @@ sub eval_mk_cond_func($func, $arg, $vars |
297 | } elsif ($func eq 'exists') { | | 297 | } elsif ($func eq 'exists') { |
298 | my $fname = expand_exprs($arg, $vars); | | 298 | my $fname = expand_exprs($arg, $vars); |
299 | -e $fname ? 1 : 0; | | 299 | -e $fname ? 1 : 0; |
300 | | | 300 | |
301 | } elsif ($func eq 'make') { | | 301 | } elsif ($func eq 'make') { |
302 | 0; | | 302 | 0; |
303 | | | 303 | |
304 | } else { # $func eq 'target' | | 304 | } else { # $func eq 'target' |
305 | 0; | | 305 | 0; |
306 | } | | 306 | } |
307 | } | | 307 | } |
308 | | | 308 | |
309 | sub eval_mk_cond($line, $vars) { | | 309 | sub eval_mk_cond($line, $vars) { |
310 | my $test = expand_exprs($line, $vars); | | 310 | my $cond = expand_exprs($line, $vars); |
311 | | | 311 | |
312 | # XXX This is _so_ wrong - need to parse this correctly | | 312 | # XXX This is _so_ wrong - need to parse this correctly |
313 | $test =~ s/""/\r/g; | | 313 | $cond =~ s/""/\r/g; |
314 | $test =~ s/"//g; | | 314 | $cond =~ s/"//g; |
315 | $test =~ s/\r/""/g; | | 315 | $cond =~ s/\r/""/g; |
316 | | | 316 | |
317 | debug("conditional: $test"); | | 317 | debug("conditional: $cond"); |
318 | | | 318 | |
319 | while ($test =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/) { | | 319 | while ($cond =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/) { |
320 | my ($func, $arg) = ($1, $2); | | 320 | my ($func, $arg) = ($1, $2); |
321 | my $result = eval_mk_cond_func($func, $arg, $vars); | | 321 | my $result = eval_mk_cond_func($func, $arg, $vars); |
322 | $test =~ s/$func\s*\([^()]+\)/$result/; | | 322 | $cond =~ s/$func\s*\([^()]+\)/$result/; |
323 | debug("conditional: update to $test"); | | 323 | debug("conditional: update to $cond"); |
324 | } | | 324 | } |
325 | | | 325 | |
326 | while ($test =~ /([^\s()\|\&]+) \s+ (!=|==) \s+ ([^\s()]+)/x) { | | 326 | while ($cond =~ /([^\s()\|\&]+) \s+ (!=|==) \s+ ([^\s()]+)/x) { |
327 | my $result = 0 + (($2 eq '==') ? ($1 eq $3) : ($1 ne $3)); | | 327 | my $result = 0 + (($2 eq '==') ? ($1 eq $3) : ($1 ne $3)); |
328 | $test =~ s/[^\s()\|\&]+ \s+ (!=|==) \s+ [^\s()]+/$result/x; | | 328 | $cond =~ s/[^\s()\|\&]+ \s+ (!=|==) \s+ [^\s()]+/$result/x; |
329 | } | | 329 | } |
330 | | | 330 | |
331 | if ($test =~ /^[ <> \d () \s & | . ! ]+$/xx) { | | 331 | if ($cond =~ /^[ <> \d () \s & | . ! ]+$/xx) { |
332 | debug("eval test $test"); | | 332 | my $result = eval "($cond) ? 1 : 0"; |
333 | my $result = eval "($test) ? 1 : 0"; | | 333 | defined $result or fail("Eval '$cond' failed in '$line': $@"); |
334 | defined $result or fail("Eval '$test' failed in '$line': $@"); | | | |
335 | debug("conditional: evaluated to " . ($result ? 'true' : 'false')); | | 334 | debug("conditional: evaluated to " . ($result ? 'true' : 'false')); |
336 | $result; | | 335 | $result; |
337 | | | 336 | |
338 | } else { | | 337 | } else { |
339 | debug("conditional: defaulting '$test' to true"); | | 338 | debug("conditional: defaulting '$cond' to true"); |
340 | 1; | | 339 | 1; |
341 | } | | 340 | } |
342 | } | | 341 | } |
343 | | | 342 | |
344 | sub parse_makefile_line_include($file, $incfile, | | 343 | sub parse_makefile_line_include($file, $incfile, |
345 | $incdirs, $included, $lines, $vars) { | | 344 | $incdirs, $included, $lines, $vars) { |
346 | | | 345 | |
347 | # At this point just skip any includes which we were | | 346 | # At this point just skip any includes which we were |
348 | # not able to fully expand. | | 347 | # not able to fully expand. |
349 | if ($incfile =~ m#/mk/bsd# | | 348 | if ($incfile =~ m#/mk/bsd# |
350 | || $incfile =~ /$magic_undefined/ | | 349 | || $incfile =~ /$magic_undefined/ |
351 | || $incfile =~ /\$\{/ | | 350 | || $incfile =~ /\$\{/ |
352 | || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) { | | 351 | || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) { |
| @@ -1136,110 +1135,110 @@ sub load_distinfo($pkgsrcdir, $cat, $pkg | | | @@ -1136,110 +1135,110 @@ sub load_distinfo($pkgsrcdir, $cat, $pkg |
1136 | . "in $cat/$pkgdir " | | 1135 | . "in $cat/$pkgdir " |
1137 | . "and $distfiles->{$distfile}{path}\n"; | | 1136 | . "and $distfiles->{$distfile}{path}\n"; |
1138 | } | | 1137 | } |
1139 | } | | 1138 | } |
1140 | close(DISTINFO) or die; | | 1139 | close(DISTINFO) or die; |
1141 | } | | 1140 | } |
1142 | | | 1141 | |
1143 | # Extract all distinfo entries, then verify contents of distfiles | | 1142 | # Extract all distinfo entries, then verify contents of distfiles |
1144 | # | | 1143 | # |
1145 | sub scan_pkgsrc_distfiles_vs_distinfo($pkgsrcdir, $pkgdistdir, $check_unref, | | 1144 | sub scan_pkgsrc_distfiles_vs_distinfo($pkgsrcdir, $pkgdistdir, $check_unref, |
1146 | $check_distinfo) { | | 1145 | $check_distinfo) { |
1147 | my (@categories); | | 1146 | my (@categories); |
1148 | my (%distfiles, %sumfiles, @distwarn, $numpkg); | | 1147 | my (%distfiles, %sumfiles, @distwarn, $numpkg); |
1149 | my (%bad_distfiles); | | 1148 | my (%unref_distfiles); |
1150 | | | 1149 | |
1151 | @categories = list_pkgsrc_categories($pkgsrcdir); | | 1150 | @categories = list_pkgsrc_categories($pkgsrcdir); |
1152 | | | 1151 | |
1153 | verbose('Scan distinfo: ' . '_' x @categories . "\b" x @categories); | | 1152 | verbose('Scan distinfo: ' . '_' x @categories . "\b" x @categories); |
1154 | $numpkg = 0; | | 1153 | $numpkg = 0; |
1155 | foreach my $cat (sort @categories) { | | 1154 | foreach my $cat (sort @categories) { |
1156 | foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) { | | 1155 | foreach my $pkgdir (list_pkgsrc_pkgdirs($pkgsrcdir, $cat)) { |
1157 | ++$numpkg; | | 1156 | ++$numpkg; |
1158 | load_distinfo($pkgsrcdir, $cat, $pkgdir, | | 1157 | load_distinfo($pkgsrcdir, $cat, $pkgdir, |
1159 | \%distfiles, \@distwarn); | | 1158 | \%distfiles, \@distwarn); |
1160 | } | | 1159 | } |
1161 | verbose('.'); | | 1160 | verbose('.'); |
1162 | } | | 1161 | } |
1163 | verbose(" ($numpkg packages)\n"); | | 1162 | verbose(" ($numpkg packages)\n"); |
1164 | | | 1163 | |
1165 | # check each file in $pkgdistdir | | 1164 | # check each file in $pkgdistdir |
1166 | find({ wanted => sub { | | 1165 | find({ wanted => sub { |
1167 | my ($dist); | | 1166 | my ($dist); |
1168 | if (-f $File::Find::name) { | | 1167 | if (-f $File::Find::name) { |
1169 | my $distn = $File::Find::name; | | 1168 | my $distn = $File::Find::name; |
1170 | $distn =~ s/$pkgdistdir\/?//g; | | 1169 | $distn =~ s/$pkgdistdir\/?//g; |
1171 | #pkg/47516 ignore cvs dirs | | 1170 | #pkg/47516 ignore cvs dirs |
1172 | return if $distn =~ m/^\.cvsignore/; | | 1171 | return if $distn =~ m/^\.cvsignore/; |
1173 | return if $distn =~ m/^CVS\//; | | 1172 | return if $distn =~ m/^CVS\//; |
1174 | if (!defined($dist = $distfiles{$distn})) { | | 1173 | if (!defined($dist = $distfiles{$distn})) { |
1175 | $bad_distfiles{$distn} = 1; | | 1174 | $unref_distfiles{$distn} = 1; |
1176 | } elsif ($dist->{sum} ne 'IGNORE') { | | 1175 | } elsif ($dist->{sum} ne 'IGNORE') { |
1177 | push @{$sumfiles{ $dist->{sumtype} }}, $distn; | | 1176 | push @{$sumfiles{ $dist->{sumtype} }}, $distn; |
1178 | } | | 1177 | } |
1179 | } | | 1178 | } |
1180 | } }, | | 1179 | } }, |
1181 | ($pkgdistdir)); | | 1180 | ($pkgdistdir)); |
1182 | | | 1181 | |
1183 | if ($check_unref && %bad_distfiles) { | | 1182 | if ($check_unref && %unref_distfiles) { |
1184 | verbose(scalar(keys %bad_distfiles), | | 1183 | verbose(scalar(keys %unref_distfiles), |
1185 | " unreferenced file(s) in '$pkgdistdir':\n"); | | 1184 | " unreferenced file(s) in '$pkgdistdir':\n"); |
1186 | print join("\n", sort keys %bad_distfiles), "\n"; | | 1185 | print join("\n", sort keys %unref_distfiles), "\n"; |
1187 | } | | 1186 | } |
1188 | | | 1187 | |
1189 | if ($check_distinfo) { | | 1188 | if ($check_distinfo) { |
1190 | if (@distwarn) { | | 1189 | if (@distwarn) { |
1191 | verbose(@distwarn); | | 1190 | verbose(@distwarn); |
1192 | } | | 1191 | } |
1193 | | | 1192 | |
1194 | verbose("checksum mismatches\n"); | | 1193 | verbose("checksum mismatches\n"); |
1195 | chdir_or_fail($pkgdistdir); | | 1194 | chdir_or_fail($pkgdistdir); |
1196 | foreach my $sum (keys %sumfiles) { | | 1195 | foreach my $sum (keys %sumfiles) { |
1197 | if ($sum eq 'Size') { | | 1196 | if ($sum eq 'Size') { |
1198 | foreach my $file (@{$sumfiles{$sum}}) { | | 1197 | foreach my $file (@{$sumfiles{$sum}}) { |
1199 | if (!-f $file || -S $file != $distfiles{$file}{sum}) { | | 1198 | if (!-f $file || -S $file != $distfiles{$file}{sum}) { |
1200 | print $file, " (Size)\n"; | | 1199 | print $file, " (Size)\n"; |
1201 | $bad_distfiles{$file} = 1; | | 1200 | $unref_distfiles{$file} = 1; |
1202 | } | | 1201 | } |
1203 | } | | 1202 | } |
1204 | next; | | 1203 | next; |
1205 | } | | 1204 | } |
1206 | | | 1205 | |
1207 | my $pid = open3(my $in, my $out, undef, 'xargs', 'digest', $sum); | | 1206 | my $pid = open3(my $in, my $out, undef, 'xargs', 'digest', $sum); |
1208 | defined $pid || fail 'fork'; | | 1207 | defined $pid || fail 'fork'; |
1209 | my $pid2 = fork(); | | 1208 | my $pid2 = fork(); |
1210 | defined $pid2 || fail 'fork'; | | 1209 | defined $pid2 || fail 'fork'; |
1211 | if ($pid2) { | | 1210 | if ($pid2) { |
1212 | close($in); | | 1211 | close($in); |
1213 | } else { | | 1212 | } else { |
1214 | print $in "@{$sumfiles{$sum}}"; | | 1213 | print $in "@{$sumfiles{$sum}}"; |
1215 | exit 0; | | 1214 | exit 0; |
1216 | } | | 1215 | } |
1217 | while (<$out>) { | | 1216 | while (<$out>) { |
1218 | if (m/^$sum ?\(([^\)]+)\) = (\S+)/) { | | 1217 | if (m/^$sum ?\(([^\)]+)\) = (\S+)/) { |
1219 | if ($distfiles{$1}{sum} ne $2) { | | 1218 | if ($distfiles{$1}{sum} ne $2) { |
1220 | print $1, " ($sum)\n"; | | 1219 | print $1, " ($sum)\n"; |
1221 | $bad_distfiles{$1} = 1; | | 1220 | $unref_distfiles{$1} = 1; |
1222 | } | | 1221 | } |
1223 | } | | 1222 | } |
1224 | } | | 1223 | } |
1225 | close($out); | | 1224 | close($out); |
1226 | waitpid($pid, 0) || fail "xargs digest $sum"; | | 1225 | waitpid($pid, 0) || fail "xargs digest $sum"; |
1227 | waitpid($pid2, 0) || fail 'pipe write to xargs'; | | 1226 | waitpid($pid2, 0) || fail 'pipe write to xargs'; |
1228 | } | | 1227 | } |
1229 | chdir_or_fail('/'); # Do not want to stay in $pkgdistdir | | 1228 | chdir_or_fail('/'); # Do not want to stay in $pkgdistdir |
1230 | } | | 1229 | } |
1231 | | | 1230 | |
1232 | sort keys %bad_distfiles; | | 1231 | sort keys %unref_distfiles; |
1233 | } | | 1232 | } |
1234 | | | 1233 | |
1235 | sub store_pkgdb_in_cache($db, $fname) { | | 1234 | sub store_pkgdb_in_cache($db, $fname) { |
1236 | open(STORE, '>', $fname) | | 1235 | open(STORE, '>', $fname) |
1237 | or die("Cannot save package data to $fname: $!\n"); | | 1236 | or die("Cannot save package data to $fname: $!\n"); |
1238 | foreach my $pkgver ($db->pkgvers_all) { | | 1237 | foreach my $pkgver ($db->pkgvers_all) { |
1239 | my $pkgbase = $pkgver->pkgbase; | | 1238 | my $pkgbase = $pkgver->pkgbase; |
1240 | my $pkgversion = $pkgver->pkgversion; | | 1239 | my $pkgversion = $pkgver->pkgversion; |
1241 | | | 1240 | |
1242 | $pkgbase =~ /^\S+$/ | | 1241 | $pkgbase =~ /^\S+$/ |
1243 | or die "cannot store package name '$pkgbase'\n"; | | 1242 | or die "cannot store package name '$pkgbase'\n"; |
1244 | $pkgversion =~ /^\S+$/ | | 1243 | $pkgversion =~ /^\S+$/ |
1245 | or die "cannot store package version '$pkgversion'\n"; | | 1244 | or die "cannot store package version '$pkgversion'\n"; |
| @@ -1360,32 +1359,32 @@ sub debug_parse_makefiles(@args) { | | | @@ -1360,32 +1359,32 @@ sub debug_parse_makefiles(@args) { |
1360 | | | 1359 | |
1361 | print "$file -> $pkgname\n"; | | 1360 | print "$file -> $pkgname\n"; |
1362 | foreach my $varname (sort keys %$vars) { | | 1361 | foreach my $varname (sort keys %$vars) { |
1363 | print "\t$varname = $vars->{$varname}\n"; | | 1362 | print "\t$varname = $vars->{$varname}\n"; |
1364 | } | | 1363 | } |
1365 | | | 1364 | |
1366 | #if ($opt{d}) { | | 1365 | #if ($opt{d}) { |
1367 | # pkgsrc_check_depends(); | | 1366 | # pkgsrc_check_depends(); |
1368 | #} | | 1367 | #} |
1369 | } | | 1368 | } |
1370 | } | | 1369 | } |
1371 | | | 1370 | |
1372 | sub check_distfiles($pkgsrcdir, $pkgdistdir) { | | 1371 | sub check_distfiles($pkgsrcdir, $pkgdistdir) { |
1373 | my @baddist = scan_pkgsrc_distfiles_vs_distinfo( | | 1372 | my @unref_distfiles = scan_pkgsrc_distfiles_vs_distinfo( |
1374 | $pkgsrcdir, $pkgdistdir, $opt{o}, $opt{m}); | | 1373 | $pkgsrcdir, $pkgdistdir, $opt{o}, $opt{m}); |
1375 | | | 1374 | |
1376 | return unless $opt{r}; | | 1375 | return unless $opt{r}; |
1377 | verbose("Unlinking 'bad' distfiles\n"); | | 1376 | verbose("Unlinking unreferenced distfiles\n"); |
1378 | foreach my $distfile (@baddist) { | | 1377 | foreach my $distfile (@unref_distfiles) { |
1379 | unlink("$pkgdistdir/$distfile"); | | 1378 | unlink("$pkgdistdir/$distfile"); |
1380 | } | | 1379 | } |
1381 | } | | 1380 | } |
1382 | | | 1381 | |
1383 | sub remove_distfiles($pkgsrcdir, $pkgdistdir) { | | 1382 | sub remove_distfiles($pkgsrcdir, $pkgdistdir) { |
1384 | my @pkgs = list_installed_packages(); | | 1383 | my @pkgs = list_installed_packages(); |
1385 | scan_pkgsrc_makefiles($pkgsrcdir); | | 1384 | scan_pkgsrc_makefiles($pkgsrcdir); |
1386 | | | 1385 | |
1387 | # list the installed packages and the directory they live in | | 1386 | # list the installed packages and the directory they live in |
1388 | my @installed; | | 1387 | my @installed; |
1389 | foreach my $pkgname (sort @pkgs) { | | 1388 | foreach my $pkgname (sort @pkgs) { |
1390 | if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) { | | 1389 | if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) { |
1391 | foreach my $pkgver ($pkgdb->pkgvers_by_pkgbase($1)) { | | 1390 | foreach my $pkgver ($pkgdb->pkgvers_by_pkgbase($1)) { |