ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/mports/trunk/ports-mgmt/portlint/src/portlint.pl
Revision: 23730
Committed: Fri Aug 17 22:30:54 2018 UTC (5 years, 8 months ago) by laffer1
Content type: text/plain
File size: 110353 byte(s)
Log Message:
fix a few bugs

File Contents

# Content
1 #! /usr/bin/perl -w
2 # ex:ts=4
3 #
4 # portlint - lint for port directory
5 # implemented by:
6 # Jun-ichiro itojun Hagino <itojun@itojun.org>
7 # Yoshishige Arai <ryo2@on.rim.or.jp>
8 #
9 # Copyright(c) 1997 by Jun-ichiro Hagino <itojun@itojun.org>.
10 # All rights reserved.
11 # Freely redistributable. Absolutely no warranty.
12 #
13 # Please note that this perl code used to be able to handle (Open|Net|Free)BSD
14 # bsd.port.mk. There are significant differences in those so non-FreeBSD code
15 # was removed.
16 #
17 # $MidnightBSD: mports/ports-mgmt/portlint/src/portlint.pl,v 1.11 2013/01/18 03:56:21 laffer1 Exp $
18 # $FreeBSD: ports/devel/portlint/src/portlint.pl,v 1.91 2006/08/06 22:36:45 marcus Exp $
19 #
20
21 use strict;
22 use warnings;
23
24 use Getopt::Std;
25 use File::Find;
26 use IPC::Open2;
27 use File::Basename;
28 use POSIX qw(strftime);
29
30 sub perror($$$$);
31 our ($opt_a, $opt_A, $opt_b, $opt_C, $opt_c, $opt_g, $opt_h, $opt_m, $opt_t, $opt_v, $opt_M, $opt_N, $opt_B, $opt_V, @ALLOWED_FULL_PATHS);
32
33 my ($err, $warn);
34 my ($extrafile, $parenwarn, $committer, $verbose, $usetabs, $newport,
35 $grouperrs, $checkmfiles);
36 my $contblank;
37 my $portdir;
38 my $makeenv = "";
39 my @errlst = ();
40 my %errcache = ();
41
42 $err = $warn = 0;
43 $extrafile = $parenwarn = $committer = $verbose = $usetabs = $newport = 0;
44 $checkmfiles = 0;
45 $contblank = 1;
46 $portdir = '.';
47
48 @ALLOWED_FULL_PATHS = qw(/boot/loader.conf /compat/ /dev/null /etc/inetd.conf);
49
50 # version variables
51 my $major = 2;
52 my $minor = 18;
53 my $micro = 3;
54
55 # default setting - for MidnightBSD
56 my $portsdir = '/usr/mports';
57 my $rcsidstr = 'MidnightBSD';
58 my $localbase = '/usr/local';
59 my $numpitems = 6;
60
61 my %lang_pref = qw(
62 arabic ar
63 chinese zh
64 french fr
65 german de
66 hebrew iw
67 hungarian hu
68 japanese ja
69 korean ko
70 polish pl
71 portuguese pt
72 russian ru
73 ukrainian uk
74 vietnamese vi
75 );
76 my @lang_cat = keys %lang_pref;
77 my @lang_short = values %lang_pref;
78 my $re_lang_short = '(' . join('|', @lang_short) . ')-';
79
80 my ($prog) = ($0 =~ /([^\/]+)$/);
81 sub usage {
82 print STDERR <<EOF;
83 usage: $prog [-AabCcghmvtN] [-M ENV] [-B#] [port_directory]
84 -a additional check for scripts/* and pkg-*
85 -A turn on all additional checks (equivalent to -abcmNt)
86 -b warn \$(VARIABLE)
87 -c committer mode (implies -m)
88 -C pedantic committer mode (equivalent to -abcmt)
89 -g group errors together to avoid duplication (disabled if -v is specified)
90 -h show summary of command line options
91 -v verbose mode
92 -t nit pick about use of spaces
93 -m check \${PORTSDIR}/MOVED, UIDs, and GIDs files
94 -N writing a new port
95 -V print the version and exit
96 -M ENV set make variables to ENV (ex. PORTSDIR=/usr/mports.work)
97 -B# allow # contiguous blank lines (default: $contblank line)
98 EOF
99 exit 0;
100 }
101
102 sub version {
103 print "$prog version $major.$minor.$micro\n";
104 exit $major;
105 }
106
107 getopts('AabCcghmtvB:M:NV');
108
109 &usage if $opt_h;
110 &version if $opt_V;
111 $extrafile = 1 if $opt_a || $opt_A || $opt_C;
112 $parenwarn = 1 if $opt_b || $opt_A || $opt_C;
113 $committer = 1 if $opt_c || $opt_A || $opt_C;
114 $verbose = 1 if $opt_v;
115 $grouperrs = 1 if $opt_g && !$opt_v;
116 $checkmfiles = 1 if $opt_m || $opt_c || $opt_A || $opt_C;
117 $newport = 1 if $opt_N || $opt_A;
118 $usetabs = 1 if $opt_t || $opt_A || $opt_C;
119 $contblank = $opt_B if $opt_B;
120 $makeenv = $opt_M if $opt_M;
121
122 $portdir = $ARGV[0] ? $ARGV[0] : '.';
123
124 # The PORTSDIR environment variable overrides our defaults.
125 $portsdir = $ENV{PORTSDIR} if ( defined $ENV{'PORTSDIR'} );
126 $ENV{'PL_SVN_IGNORE'} //= '';
127 my $mfile_moved = "${portsdir}/MOVED";
128 my $mfile_uids = "${portsdir}/UIDs";
129 my $mfile_gids = "${portsdir}/GIDs";
130
131 if ($verbose) {
132 print "OK: config: portsdir: \"$portsdir\" ".
133 "rcsidstr: \"$rcsidstr\" ".
134 "localbase: $localbase ".
135 "\n";
136 }
137
138 #
139 # just for safety.
140 #
141 if (! -d $portdir) {
142 print STDERR "FATAL: invalid directory $portdir specified.\n";
143 exit 1;
144 }
145
146 chdir "$portdir" || die "$portdir: $!";
147
148 # get make vars
149 my @varlist = qw(
150 PORTNAME PORTVERSION PORTREVISION PORTEPOCH PKGNAME PKGNAMEPREFIX
151 PKGNAMESUFFIX DISTVERSIONPREFIX DISTVERSION DISTVERSIONSUFFIX
152 DISTNAME DISTFILES CATEGORIES MASTERDIR MAINTAINER MASTER_SITES
153 WRKDIR WRKSRC NO_WRKSUBDIR SCRIPTDIR FILESDIR
154 PKGDIR COMMENT DESCR PLIST PKGCATEGORY PKGINSTALL PKGDEINSTALL
155 PKGREQ PKGMESSAGE DISTINFO_FILE .CURDIR USE_LDCONFIG USE_AUTOTOOLS
156 USE_GNOME USE_PERL5 USE_QT5 INDEXFILE PKGORIGIN CONFLICTS PKG_VERSION
157 PLIST_FILES PLIST_DIRS PORTDOCS PORTEXAMPLES
158 OPTIONS_DEFINE OPTIONS_RADIO OPTIONS_SINGLE OPTIONS_MULTI
159 OPTIONS_GROUP OPTIONS_SUB INSTALLS_OMF USE_RC_SUBR USES DIST_SUBDIR
160 ALLFILES CHECKSUM_ALGORITHMS INSTALLS_ICONS GNU_CONFIGURE
161 CONFIGURE_ARGS MASTER_SITE_SUBDIR LICENSE LICENSE_COMB NO_STAGE
162 DEVELOPER SUB_FILES SHEBANG_LANG MASTER_SITES_SUBDIRS FLAVORS
163 USE_PYTHON
164 );
165
166 my %makevar;
167 my $i = 0;
168 for (split(/\n/, get_makevar(@varlist))) {
169 $_ =~ s/\0//;
170 print "OK: makevar: $varlist[$i] = $_\n" if ($verbose);
171 $makevar{$varlist[$i]} = $_;
172 $i++;
173 }
174
175 #
176 # variables for global checks.
177 #
178 my $sharedocused = 0;
179
180 my %predefined = ();
181
182 my @popt = ();
183
184 # historical, no longer in FreeBSD's bsd.sites.mk
185 foreach my $i (split(/\n/, <<EOF)) {
186 GNU ftp://prep.ai.mit.edu/pub/gnu/%SUBDIR%/
187 SUNSITE ftp://sunsite.unc.edu/pub/Linux/%SUBDIR%/
188 EOF
189 my ($j, $k) = split(/\t+/, $i);
190 $predefined{$k} = $j;
191 }
192
193 # Read bsd.sites.mk
194 my $sites_mk = "$portsdir/Mk/components/sites.mk";
195 open(MK, $sites_mk) || die "$sites_mk: $!";
196 my @site_groups = grep($_ = /^MASTER_SITE_(\w+)/ && $1, <MK>);
197 close(MK);
198
199 my $cmd = join(' -V MASTER_SITE_', "make $makeenv ", @site_groups);
200
201 $i = 0;
202
203 open2(\*IN, \*OUT, $cmd);
204
205 close(OUT);
206
207 while (<IN>) {
208 my $g = $site_groups[$i];
209 for my $s (split()) {
210 $predefined{$s} = $g;
211 }
212 $i++;
213 }
214
215 close(IN);
216
217 open(MK, 'Makefile') || die "Makefile: $!";
218 my $ulineno = -1;
219 my $uulineno = -1;
220 my @muses = ();
221 while (my $mline = <MK>) {
222 if ($uulineno == -1 && $mline =~ /^USE_/) {
223 $uulineno = $.;
224 }
225 if ($mline =~ /^USES[?+]?=\s*(.*)/) {
226 if ($ulineno == -1) {
227 $ulineno = $.;
228 }
229 if ($1) {
230 push @muses, split(/\s+/, $1);
231 }
232 }
233 }
234 if ($uulineno > -1 && $ulineno > -1 && $uulineno < $ulineno) {
235 &perror("WARN", 'Makefile', $uulineno, "USE_* seen before USES. ".
236 "According to the porters-handbook, USES must appear first.");
237 }
238 foreach my $muse (@muses) {
239 $makevar{USES} .= " " . $muse;
240 }
241
242 #
243 # check for files.
244 #
245 my @checker = ($makevar{DESCR}, 'Makefile', $makevar{DISTINFO_FILE});
246 my %checker = (
247 $makevar{DESCR} => \&checkdescr,
248 'Makefile' => \&checkmakefile,
249 $makevar{DISTINFO_FILE} => \&checkdistinfo
250 );
251 if ($extrafile) {
252 my @files = (
253 <$makevar{SCRIPTDIR}/*>,
254 @makevar{qw(DESCR PLIST PKGINSTALL PKGDEINSTALL PKGREQ PKGMESSAGE)}
255 );
256
257 foreach my $i (@files) {
258 next if (! -T $i);
259 next if (defined $checker{$i});
260 if ($i =~ /\bpkg-plist/) {
261 unshift(@checker, $i);
262 $checker{$i} = \&checkplist;
263 } else {
264 push(@checker, $i);
265 $checker{$i} = \&checkpathname;
266 }
267 }
268 }
269 if ($checkmfiles) {
270 foreach my $i ($mfile_moved, $mfile_uids, $mfile_gids) {
271 next if (! -T $i);
272 next if (defined $checker{$i});
273 push(@checker, $i);
274 $checker{$i} = \&checkmfile;
275 }
276 }
277 foreach my $i (<$makevar{FILESDIR}/patch-*>) {
278 next if (! -T $i);
279 next if (defined $checker{$i});
280 push(@checker, $i);
281 $checker{$i} = \&checkpatch;
282 }
283 foreach my $i (@checker) {
284 print "OK: checking $i.\n" if ($verbose);
285 if (! -f "$i") {
286 &perror("FATAL", "", -1, "no $i in \"$portdir\".") unless $i eq $makevar{DISTINFO_FILE} && $makevar{DISTFILES} eq "";
287 } else {
288 my $proc = $checker{$i};
289 &$proc($i) || &perror("", "", -1, "Cannot open the file $i\n");
290 if ($proc ne \&checkpatch) {
291 &checklastline($i)
292 || &perror("", "", -1, "Cannot open the file $i\n");
293 }
294 }
295 }
296
297 if ($committer) {
298 sub find_proc {
299 return if /^\.\.?$/;
300
301 (my $fullname = $File::Find::name) =~ s#^\./##;
302
303 print "OK: checking the file name of $fullname.\n" if ($verbose);
304
305 if ($fullname eq 'work') {
306 &perror("FATAL", $fullname, -1, "be sure to cleanup the working directory ".
307 "before committing the port.");
308
309 $File::Find::prune = 1;
310 } elsif (-l) {
311 &perror("WARN", $fullname, -1, "this is a symlink. ".
312 "Please remove it.");
313 } elsif (-z) {
314 &perror("FATAL", $fullname, -1, "empty file and should be removed. ".
315 "If it still needs to be there, put a dummy comment ".
316 "to state that the file is intentionally left empty.");
317 } elsif (-d && scalar(my @x = <$_/{*,.?*}>) <= 1) {
318 &perror("FATAL", $fullname, -1, "empty directory should be removed.") unless ($fullname =~ /^\.svn/ || $fullname =~ /^\.git/);
319 } elsif (/^\./) {
320 &perror("WARN", $fullname, -1, "dotfiles are not preferred. ".
321 "If this file is a dotfile to be installed as an example, ".
322 "consider importing it as \"dot$_\".") unless
323 (-d && ($_ eq '.svn' || $_ eq '.git'));
324 } elsif (/[^-.a-zA-Z0-9_\+]/) {
325 &perror("WARN", $fullname, -1, "only use characters ".
326 "[-_.a-zA-Z0-9+] for patch or script names.");
327 } elsif (/\.(orig|rej|bak)$/ || /~$/ || /^\#/) {
328 &perror("FATAL", $fullname, -1, "for safety, be sure to cleanup ".
329 "backup files before committing the port.");
330 } elsif (/(^|\.)core$/) {
331 &perror("FATAL", $fullname, -1, "for safety, be sure to cleanup ".
332 "core files before committing the port.");
333 } elsif (/README.html/) {
334 &perror("FATAL", $fullname, -1, "for safety, be sure to cleanup ".
335 "README.html files before committing the port.");
336 } elsif (($_ eq '.svn' || $_ eq '.git') && -d) {
337 &perror("FATAL", $fullname, -1, "for safety, be sure to cleanup ".
338 "Subversion files before committing the port.");
339
340 $File::Find::prune = 1;
341 } elsif ($_ eq 'CVS' && -d) {
342 if ($newport) {
343 &perror("FATAL", $fullname, -1, "for safety, be sure to cleanup ".
344 "CVS directories before importing the new port.");
345 }
346
347 $File::Find::prune = 1;
348 } elsif (-f) {
349 my $fullpath = $makevar{'.CURDIR'}.'/'.$fullname;
350 my $result = `type svn >/dev/null 2>&1 && svn -q status $fullpath`;
351
352 chomp $result;
353 if (substr($result, 0, 1) eq '?') {
354 &perror("FATAL", "", -1, "$fullname not under SVN.")
355 unless (eval { /$ENV{'PL_SVN_IGNORE'}/, 1 } &&
356 /$ENV{'PL_SVN_IGNORE'}/);
357 }
358 }
359 }
360
361 find(\&find_proc, '.');
362
363 # Check for ports that may break INDEX
364 my $indexerr = `env LOCALBASE=/nonexistentlocal make $makeenv describe 2>&1 >/dev/null`;
365 chomp $indexerr;
366 $indexerr =~ tr/\n/ /s;
367 &perror("FATAL", "", -1, "breaks INDEX ($indexerr).")
368 if ($indexerr);
369 # Suggest to set MPORT_MAINTAINER_MODE knob in /etc/make.conf
370 if (!$makevar{MPORT_MAINTAINER_MODE}) {
371 &perror("WARN", "", -1, "Consider to set MPORT_MAINTAINER_MODE=yes in /etc/make.conf");
372 }
373 }
374 if ($err || $warn) {
375 my($errtext, $warntext) = ("error", "warning");
376 $errtext .= "s" unless ($err == 1);
377 $warntext .= "s" unless ($warn == 1);
378 if ($grouperrs) {
379 foreach my $msg (@errlst) {
380 my $lines;
381 if ($errcache{$msg} && scalar(@{$errcache{$msg}})) {
382 $lines = "[" . (join(",", @{$errcache{$msg}})) . "]: ";
383 } else {
384 $lines = "";
385 }
386 $msg =~ s/%%LINES%%/$lines/;
387 print $msg, "\n";
388 }
389 }
390 printf("%d fatal %s and %d %s found.\n", $err, $errtext, $warn, $warntext);
391 } else {
392 print "looks fine.\n";
393 }
394 exit $err;
395
396 #
397 # distinfo
398 #
399 sub checkdistinfo {
400 my($file) = @_;
401 my($dist_subdir) = $makevar{DIST_SUBDIR};
402 my(@allfiles) = split (/\s+/, $makevar{ALLFILES});
403 my %algorithms = ();
404 my %records = ();
405
406 foreach my $i (split (/\s+/, uc ($makevar{CHECKSUM_ALGORITHMS}))) {
407 $algorithms{$i} = 1;
408 }
409
410 open(IN, "< $file") || return 0;
411 while (<IN>) {
412 if (/^\s*$/) {
413 &perror("FATAL", $file, $., "found blank line.");
414 next;
415 }
416 if (/^TIMESTAMP\s+=\s+(\d+)$/) {
417 my $now = time;
418 if ($1 > $now) {
419 &perror("FATAL", $file, $., "TIMESTAMP is in the future");
420 }
421 next;
422 }
423 if (/(\S+)\s+\((\S+)\)\s+=\s+(\S+)/) {
424 my ($tag, $path, $value) = ($1, $2, $3);
425 $records{$path}{$tag} = $value;
426
427 if (!$algorithms{$tag} && $tag ne "SIZE") {
428 &perror("FATAL", $file, $., "unsupported checksum algorithm ".
429 "found: $tag.");
430 }
431 } else {
432 &perror("FATAL", $file, $., "line format error.");
433 }
434 }
435 close(IN);
436
437 # For all files check SIZE and checksums
438 foreach my $f (@allfiles) {
439 # Remove hindering chars from DISTNAME
440 $f =~ s/['\\]//g;
441
442 my $path = $f;
443 $path = "$dist_subdir/$f" if $dist_subdir;
444 if (!defined($records{$path}{SIZE})) {
445 &perror("FATAL", $file, -1, "has no SIZE record for $path.");
446 }
447 my $n = 0;
448 foreach my $alg (keys %algorithms) {
449 $n++ if exists($records{$path}{$alg});
450 }
451 if ($n == 0) {
452 &perror("FATAL", $file, -1, "no checksum record for $path.");
453 }
454 if ($n < scalar(keys %algorithms)) {
455 &perror("WARN", $file, -1, "no checksum records for all ".
456 "supported algorithms (".join(" ",keys %algorithms).") for ".
457 "$path.");
458 }
459 }
460 return 1;
461 }
462
463 #
464 # pkg-descr
465 #
466 sub checkdescr {
467 my($file) = @_;
468 my(%maxchars) = ($makevar{DESCR}, 80);
469 my(%maxlines) = ($makevar{DESCR}, 24);
470 my(%minlines) = ($makevar{DESCR}, 3);
471 my(%toolongerrmsg) = ($makevar{DESCR},
472 "exceeds $maxlines{$makevar{DESCR}} ".
473 "lines, make it shorter if possible.");
474 my(%tooshorterrmsg) = ($makevar{DESCR},
475 "contains less than $minlines{$makevar{DESCR}} ".
476 "lines, make it longer if possible.");
477 my($longlines, $linecnt, $tmp) = (0, 0, "");
478
479 open(IN, "< $file") || return 0;
480 while (<IN>) {
481 $tmp .= $_;
482 chomp || &perror("WARN", $file, -1, "lines should terminate with a ".
483 "newline (i.e. '\\n').");
484 if (/
485 $/) {
486 &perror("WARN", $file, -1, "lines should not contain carriage ".
487 "returns. Strip all carriage returns (e.g. run dos2unix) ".
488 "in $file.");
489 }
490 if (/^WWW:(\s+)(\S*)/) {
491 my $wwwurl = $2;
492 if ($1 ne ' ') {
493 &perror("WARN", $file, -1, "use WWW: with a single space, ".
494 "then $wwwurl");
495 }
496 if ($wwwurl !~ m|^https?://|) {
497 &perror("WARN", $file, -1, "WWW URL, $wwwurl should begin ".
498 "with \"http://\" or \"https://\".");
499 }
500 if ($wwwurl =~ m|^http://search.cpan.org/~|) {
501 &perror("WARN", $file, -1, "consider changing WWW URL to ".
502 "http://search.cpan.org/dist/$makevar{PORTNAME}/");
503 }
504 }
505 $linecnt++;
506 $longlines++ if ($maxchars{$file} < length);
507 }
508 if ($linecnt > $maxlines{$file}) {
509 &perror("WARN", $file, -1, "$toolongerrmsg{$file}".
510 "(currently $linecnt lines)");
511 } elsif ($linecnt < $minlines{$file}) {
512 &perror("WARN", $file, -1, "$tooshorterrmsg{$file}".
513 "(currently $linecnt ".($linecnt > 1 ? "lines" : "line").")");
514 } else {
515 print "OK: $file: has $linecnt lines.\n" if ($verbose);
516 }
517 if ($longlines > 0) {
518 &perror("WARN", $file, -1, "includes lines that exceed $maxchars{$file} ".
519 "characters.");
520 }
521 if ($tmp =~ /[\033\200-\377]/) {
522 &perror("WARN", $file, -1, "includes iso-8859-1, or ".
523 "other local characters. files should be in ".
524 "plain 7-bit ASCII");
525 }
526 if ($file =~ /\bpkg-descr/ && $tmp =~ m,https?://,) {
527 my $has_url = 0;
528 my $has_www = 0;
529 my $cpan_url = 0;
530 my $has_endslash = 0;
531 foreach my $line (grep($_ =~ "https?://", split(/\n+/, $tmp))) {
532 $has_url = 1;
533 if ($line =~ m,WWW:[ \t]+https?://,) {
534 $has_www = 1;
535 if ($line =~ m,search.cpan.org,) {
536 $cpan_url = 1;
537 if ($line =~ m,/$,) {
538 $has_endslash = 1;
539 }
540 }
541 }
542 }
543
544 if (!$has_url) {
545 &perror("WARN", $file, -1, "add \"WWW: URL:\" for this port if possible");
546 }
547
548 if ($cpan_url && !$has_endslash) {
549 &perror("WARN", $file, -1, "end WWW CPAN URL with a \"/\"");
550 }
551
552 if ($has_url && ! $has_www) {
553 &perror("FATAL", $file, -1, "contains a URL but no \"WWW:\"");
554 }
555 }
556 close(IN);
557 }
558
559 #
560 # pkg-plist
561 #
562 sub checkplist {
563 my($file) = @_;
564 my($curdir) = ($localbase);
565 my($rcsidseen) = (0);
566
567 my $seen_special = 0;
568 my $item_count = 0;
569 my $owner_seen = 0;
570 my $group_seen = 0;
571 my $found_so = 0;
572
573 # Variables that are allowed to be out-of-sync in the XXXDIR check.
574 # E.g., %%PORTDOCS%%%%RUBY_MODDOCDIR%% will be OK because there is
575 # no %%PORTRUBY_MODDOC%% substitution.
576 my %check_xxxdir_ok = (
577 "DOCS" => "DOCS",
578 "EXAMPLES" => "EXAMPLES",
579 "DATA" => "DATA",
580 "RUBY_DOC" => "DOCS",
581 "RUBY_EXAMPLES" => "EXAMPLES",
582 "RUBY_MODDOC" => "DOCS",
583 "RUBY_MODEXAMPLES" => "EXAMPLES",
584 );
585
586 open(IN, "< $file") || return 0;
587 while (<IN>) {
588 $item_count++;
589 if ($_ =~ /[ \t]+\n?$/) {
590 &perror("WARN", $file, $., "whitespace before end ".
591 "of line.");
592 }
593
594 # make it easier to handle.
595 $_ =~ s/\s+$//;
596 $_ =~ s/\n$//;
597
598 if ($_ eq "") {
599 &perror("WARN", $file, $., "empty line found in plist.");
600 }
601
602 # store possible OPTIONS knobs for OPTIONS_SUB
603 if ($makevar{OPTIONS_SUB}) {
604 while (/\%\%([^%]+)\%\%/g) {
605 if ($1 =~ /PORTDOCS/) {
606 push @popt, "DOCS";
607 } elsif ($1 =~ /PORTEXAMPLES/) {
608 push @popt, "EXAMPLES";
609 } else {
610 push @popt, $1;
611 }
612 }
613 }
614
615 if ($_ =~ /\.DS_Store/) {
616 &perror("WARN", $file, $., ".DS_Store meta data files must not ".
617 "be installed.");
618 }
619
620 if (m'lib/perl5/site_perl/mach/%%PERL_VER%%') {
621 &perror("WARN", $file, $., "use \%\%SITE_ARCH\%\% ".
622 "instead of lib/perl5/site_perl/mach/\%\%PERL_VER\%\%");
623 } elsif (m'lib/perl5/site_perl') {
624 &perror("WARN", $file, $., "use \%\%SITE_PERL\%\% ".
625 "instead of lib/perl5/site_perl.");
626 }
627
628 if (m'([\w\d]+-portbld-freebsd\d+\.\d+)') {
629 &perror("WARN", $file, $., "possible direct use of the ".
630 "CONFIGURE_TARGET value ($1). Consider using the plist ".
631 "substitution %%CONFIGURE_TARGET%% instead.");
632 }
633
634 if (m'\@dirrm(try)?\s+libdata/pkgconfig') {
635 &perror("FATAL", $file, $., "libdata/pkgconfig should not be ".
636 "removed. It is listed in BSD.local.dist.");
637 }
638
639 if (m'\@dirrm(try)?\s') {
640 &perror("WARN", $file, $., "\@dirrm[try] is deprecated. If you ".
641 "require special directory handling, use \@dir instead and ".
642 "consult the porter's handbook.");
643 }
644
645 if (m'\@cwd') {
646 &perror("WARN", $file, $., "\@cwd is deprecated. Please use ".
647 "absolute pathnames instead.");
648 }
649
650 if (m'\@stopdaemon\s') {
651 &perror("WARN", $file, $., "\@stopdaemon is deprecated. The ".
652 "pkg(8) has a generic mechanism to provide the same function, ".
653 "see HANDLE_RC_SCRIPTS in pkg.conf(5).");
654 }
655
656 if (m'^\@(un)?exec') {
657 &perror("WARN", $file, $., "@[un]exec is deprecated in ".
658 "favor of \@<pre|post>[un]exec as the latter specifies ".
659 "the exact part of the pkg lifecycle the commands need ".
660 "to run");
661 }
662
663 $seen_special++ if /[\%\@]/;
664 if ($_ =~ /^\@/) {
665 if ($_ =~ /^\@(cwd|cd)[ \t]+(\S+)/) {
666 $curdir = $2;
667 } elsif ($_ =~ /^\@unexec[ \t]+rm[ \t]/) {
668 if ($_ !~ /%[DB]/) {
669 &perror("WARN", $file, $., "use \"%D\" or \"%B\" to ".
670 "specify prefix.");
671 }
672 if ($_ !~ /true$/ && $_ !~ /rm -f/) {
673 &perror("WARN", $file, $., "add \"2>&1 ".
674 ">/dev/null || true\" ".
675 "to \"\@unexec rm\".");
676 }
677 } elsif ($_ =~ /^\@unexec[ \t]+rmdir/) {
678 if ($_ !~ /%[DB]/) {
679 &perror("WARN", $file, $., "use \"%D\" or \"%B\" to ".
680 "specify prefix.");
681 }
682 &perror("WARN", $file, $., "use \"\@dirrmtry\" ".
683 "instead of \"\@unexec rmdir\".");
684 } elsif ($_ =~ /^\@unexec[ \t]+install-info[ \t]+--delete\s+(.+)\s+(.+)$/) {
685 &perror("WARN", $file, $., "\@unexec install-info is deprecated in favor of adding info files into the Makefile using the INFO macro.");
686 } elsif ($_ =~ /^\@(pre|post)?(exec|unexec|)/) {
687 if (/ldconfig/) {
688 &perror("WARN", $file, $., "possible ".
689 "direct use of ldconfig ".
690 "in PLIST found. use ".
691 "USE_LDCONFIG instead.");
692 }
693 if (/scrollkeeper/) {
694 &perror("WARN", $file, $., "possible ".
695 "direct use of scrollkeeper commands ".
696 "in PLIST found. Use ".
697 "INSTALLS_OMF instead ".
698 "(see http://www.FreeBSD.org/gnome/docs/porting.html ".
699 "for more details).");
700 }
701 } elsif ($_ =~ /^\@(comment)/) {
702 $rcsidseen++ if (/\$$rcsidstr[:\$]/);
703 } elsif ($_ =~ m!^\@(dirrm|dirrmtry)\s+/!) {
704 &perror("WARN", $file, $., "Using \@$1 with absolute path ".
705 "will not work as you expected in most cases. Use ".
706 "\@dir... if you want to remove a directory such as ".
707 "/var/\${PORTNAME}");
708 } elsif ($_ eq "\@cwd") {
709 ; # @cwd by itself means change directory back to the original
710 # PREFIX.
711 } elsif ($_ =~ /^\@\(/) {
712 if ($_ !~ /^\@\([^,]*,[^,]*,[^\),]*(,[^\)]*)?\)/) {
713 &perror("WARN", $file, $., "Invalid use of \@(...). ".
714 "Arguments should be owner,group,perms[,fflags]");
715 }
716 } elsif ($_ =~ /^\@sample\s+(.+)/) {
717 my $sl = $.;
718 my @sampleparts = split(/\s+/, $1);
719 if (scalar @sampleparts == 1 && $sampleparts[0] !~ /\.sample$/) {
720 &perror("WARN", $file, $sl, "\@sample directive references".
721 " file that does not end in ``.sample''. Sample".
722 " files must end in ``.sample''.");
723 }
724 } elsif ($_ =~ /^\@owner/) {
725 if ($_ =~ /^\@owner\s+.+/) {
726 if ($owner_seen > 0) {
727 &perror("WARN", $file, $., "Nested setting of \@owner ".
728 "found. Reset \@owner before setting it again.");
729 }
730 $owner_seen++;
731 } else {
732 if ($owner_seen == 0) {
733 &perror("WARN", $file, $., "\@owner reset seen before ".
734 "a new owner section was started.");
735 }
736 $owner_seen--;
737 }
738 } elsif ($_ =~ /^\@group/) {
739 if ($_ =~ /^\@group\s+.+/) {
740 if ($group_seen > 0) {
741 &perror("WARN", $file, $., "Nested setting of \@group ".
742 "found. Reset \@group before setting it again.");
743 }
744 $group_seen++;
745 } else {
746 if ($group_seen == 0) {
747 &perror("WARN", $file, $., "\@group reset seen before ".
748 "a new group section was started.");
749 }
750 $group_seen--;
751 }
752 } elsif ($_ =~ /^\@(dir|dirrm|dirrmtry|rmtry|option|stopdaemon|owner|group|mode|fc|fcfontsdir|fontsdir|info|shell)\b/) {
753 ; # no check made
754 } else {
755 &perror("WARN", $file, $.,
756 "unknown pkg-plist directive \"$_\"");
757 }
758 next;
759 }
760
761 if ($_ =~ /charset\.alias$/ || $_ =~ /locale\.alias$/) {
762 &perror("WARN", $file, $., "installing charset.alias or locale.alias, ".
763 "please add USES[+]=gettext and use libintl from devel/gettext ".
764 "instead of from outdated bundled one if possible. ".
765 "See http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/71531 ".
766 "for more details.");
767 }
768
769 if ($_ =~ /\%gconf.*\.xml/ || $_ =~ /gconf.*\.schemas?/) {
770 &perror("FATAL", $file, $., "explicitly listing \%gconf key files ".
771 "or GConf schema files in the plist is not supported. ".
772 "Use GCONF_SCHEMAS in the Makefile instead. ".
773 "See http://www.FreeBSD.org/gnome/docs/porting.html ".
774 "for more details.");
775 }
776
777 if ($_ =~ m|lib/pkgconfig/[^\/]+.pc$|) {
778 &perror("FATAL", $file, $., "installing pkg-config files into ".
779 "lib/pkgconfig. All pkg-config files must be installed ".
780 "into libdata/pkgconfig for them to be found by pkg-config.");
781 }
782
783 if ($_ =~ m|lib[^\/]+\.so(\.\d+)?$| &&
784 $makevar{USE_LDCONFIG} eq '') {
785 &perror("WARN", $file, $., "installing shared libraries, ".
786 "please define USE_LDCONFIG as appropriate");
787 } elsif ($_ =~ m|lib[^\/]+\.so(\.\d+)?$|) {
788 $found_so++;
789 }
790
791 if ($_ =~ m|^share/icons/.*/| &&
792 $makevar{INSTALLS_ICONS} eq '' &&
793 needs_installs_icons()) {
794 &perror("WARN", $file, $., "installing icons, ".
795 "please define INSTALLS_ICONS as appropriate");
796 }
797
798 if ($_ =~ m|\.omf$| && $makevar{INSTALLS_OMF} eq '') {
799 &perror("WARN", $file, $., "installing OMF files, ".
800 "please define INSTALLS_OMF (see the FreeBSD GNOME ".
801 "porting guide at ".
802 "http://www.FreeBSD.org/gnome/docs/porting.html ".
803 "for more details)");
804 }
805
806 if ($_ =~ m|^(%%([^%]+)%%)?.*\.mo$| && $makevar{USES} !~ /\bgettext\b/) {
807 my $show_nls_warn = 1;
808 if ($2) {
809 my $mv = get_makevar($2."_USES");
810 if ($mv =~ /\bgettext\b/) {
811 $show_nls_warn = 0;
812 }
813 }
814 if ($show_nls_warn) {
815 &perror("WARN", $file, $., "installing gettext translation files, ".
816 "please define USES[+]=gettext as appropriate");
817 }
818 }
819
820 if ($_ =~ m|\.core$| && $_ !~ /^\@/) {
821 &perror("WARN", $file, $., "this port installs a file which ends ".
822 "in \".core\". This file may be deleted if ".
823 "daily_clean_disks_enable=\"YES\" in /etc/periodic.conf. ".
824 "If possible, install this file with a different name.");
825 }
826
827 if ($_ =~ m|/a\.out$| && $_ !~ /^\@/) {
828 &perror("WARN", $file, $., "this port installs a file named ".
829 "\"a.out\". This file may be deleted if ".
830 "daily_clean_disks_enable=\"YES\" in /etc/periodic.conf. ".
831 "If possible, install this file with a different name.");
832 }
833
834 if ($_ =~ /\.info$/) {
835 &perror("WARN", $file, $., "enumerating info files in the plist is deprecated in favor of adding info files into the Makefile using the INFO macro.");
836 }
837
838 if ($_ =~ /\.info-\d+$/) {
839 &perror("FATAL", $file, $., "numbered info files are obsolete and not portable; add info files using the INFO macro in the Makefile.");
840 }
841
842 if ($_ =~ /^(\%\%PORTDOCS\%\%)?share\/doc\//) {
843 &perror("WARN", $file, $., "If and only if your port is ".
844 "DOCSDIR-safe (that is, a user can override DOCSDIR ".
845 "when building this port and the port will still work ".
846 "correctly) consider using DOCSDIR macro; if you are ".
847 "unsure if this port is DOCSDIR-safe, then ignore ".
848 "this warning");
849 $sharedocused++;
850 } elsif ($_ =~ /^(\%\%PORTDOCS\%\%)?\%\%DOCSDIR\%\%/) {
851 $sharedocused++;
852 }
853
854 if ($_ =~ /^share\/examples\//) {
855 &perror("WARN", $file, $., "If and only if your port is ".
856 "EXAMPLESDIR-safe (that is, a user can override EXAMPLESDIR ".
857 "when building this port and the port will still work ".
858 "correctly) consider using EXAMPLESDIR macro; if you are ".
859 "unsure if this port is EXAMPLESDIR-safe, then ignore this ".
860 "warning");
861 }
862
863 {
864 my $tmpportname = quotemeta($makevar{PORTNAME});
865 if ($_ =~ /^share\/$tmpportname\//) {
866 &perror("WARN", $file, $., "If and only if your port is ".
867 "DATADIR-safe (that is, a user can override DATADIR when ".
868 "building this port and the port will still work ".
869 "correctly) consider using DATADIR macro; if you are ".
870 "unsure if this port is DATADIR-safe, then ignore this ".
871 "warning");
872 }
873 }
874
875 if ($_ =~ m{^%%PORT(\w+)%%(.*?)%%(\w+)DIR%%(.*)$} and $1 ne $3 and
876 defined($check_xxxdir_ok{$3})) {
877 &perror("WARN", $file, $., "Do not mix %%PORT$1%% with %%$3DIR%%. ".
878 "Use '%%PORT$check_xxxdir_ok{$3}%%$2%%$3DIR%%$4' instead and update Makefile ".
879 "accordingly.") unless ($check_xxxdir_ok{$3} eq $1);
880 }
881
882 if ($_ =~ m#share/man/#) {
883 &perror("FATAL", $file, $., "Man pages must be installed into ".
884 "``man'' not ``share/man''.");
885 }
886
887 if ($_ =~ m#man/([^/]+/)?man[1-9ln]/([^\.]+\.[1-9ln])(\.gz)?$#) {
888 if (!$3) {
889 &perror("FATAL", $file, $., "Unpacked man file $2 listed. ".
890 "Must be gzipped.");
891 }
892 }
893
894 if ($curdir !~ m#^$localbase#) {
895 &perror("WARN", $file, $., "installing to ".
896 "directory $curdir discouraged. ".
897 "could you please avoid it?");
898 }
899
900 if ("$curdir/$_" =~ m#^$localbase/share/doc/#) {
901 print "OK: $file [$.]: seen installation to share/doc. ".
902 "($curdir/$_)\n" if ($verbose);
903 $sharedocused++;
904 }
905 }
906
907 if ($owner_seen > 0) {
908 &perror("WARN", $file, -1, "A \@owner section was started but never ".
909 "reset. USe \@owner without any arguments to reset the owner");
910 }
911
912 if ($group_seen > 0) {
913 &perror("WARN", $file, -1, "A \@group section was started but never ".
914 "reset. Use \@group without any arguments to reset the group");
915 }
916
917 if (!$seen_special && $item_count < $numpitems) {
918 &perror("WARN", $file, -1, "There are only $item_count items in the plist. Consider using PLIST_FILES instead of pkg-plist when installing less than $numpitems items.");
919 }
920
921 if ($makevar{USE_LDCONFIG} ne '' && !$found_so) {
922 &perror("WARN", $file, -1, "You have defined USE_LDCONFIG, but this ".
923 "port does not install any shared objects.");
924 }
925
926 close(IN);
927 1;
928 }
929 #
930 # ${PORTSDIR}/MOVED, UIDs, GIDs files
931 #
932 sub checkmfile {
933 my ($file) = @_;
934 my $line = 0;
935 my $format;
936 my @entries;
937 my @sorted;
938 my $dosort;
939
940 if ($file =~ m/MOVED$/) {
941 $format = '^[^|]*\|[^|]*\|[^|]*\|[^|]*$';
942 $dosort = 0;
943 } elsif ($file =~ m/UIDs$/) {
944 $format = '^[^:]+:\*:[0-9]+:[0-9]+:[^:]*:0:0:[^:]+:[^:]+:[^:]+$';
945 $dosort = 1;
946 } elsif ($file =~ m/GIDs$/) {
947 $format = '^[^:]+:\*:[0-9]+:[^:]*$';
948 $dosort = 1;
949 } else {
950 &perror("FATAL", $file, -1, "Internal error. ".
951 "Invalid name for mfiles.");
952 }
953
954 open(IN, "<$file") || return 0;
955 while (<IN>) {
956 chomp;
957 $line++;
958 next if (m,^\s*#,);
959
960 if (!m,${format},) {
961 &perror("FATAL", $file, -1,
962 "malformed line at ".
963 "${line}.\n => $_");
964 } else {
965 push @entries, "$line:$_";
966 next;
967 }
968 }
969 if ($dosort) {
970 my $errline;
971 @sorted = sort {(split /:/, $a)[3] <=> (split /:/, $b)[3] } @entries;
972
973 for (my $n = 0; $n < @entries; $n++) {
974 if (!defined($sorted[$n]) or
975 $entries[$n] ne $sorted[$n]) {
976 ($line, $errline) = ($entries[$n] =~ m/([0-9]+):(.*)/);
977 &perror("WARN", $file, -1,
978 "malformed sorting order at " .
979 "${line}.\n => $errline");
980 }
981 }
982 }
983 close(IN);
984 }
985 #
986 # misc files
987 #
988 sub checkpathname {
989 my($file) = @_;
990 my($whole);
991
992 open(IN, "< $file") || return 0;
993 $whole = '';
994 while (<IN>) {
995 $whole .= $_;
996 }
997 &abspathname($whole, $file);
998 close(IN);
999 }
1000
1001 sub checklastline {
1002 my($file) = @_;
1003 my($whole);
1004
1005 open(IN, "< $file") || return 0;
1006 $whole = '';
1007 while (<IN>) {
1008 $whole .= $_;
1009 }
1010 if ($whole !~ /\n$/) {
1011 &perror("FATAL", $file, -1, "the last line has to be ".
1012 "terminated by \\n.");
1013 }
1014 if ($whole =~ /\n([ \t]*\n)+$/) {
1015 &perror("WARN", $file, -1, "seems to have unnecessary blank lines ".
1016 "at the last part.");
1017 }
1018
1019 close(IN);
1020 }
1021
1022 sub checkpatch {
1023 my($file) = @_;
1024 my($whole);
1025
1026 if (-z "$file") {
1027 &perror("FATAL", $file, -1, "has no content. should be removed ".
1028 "from repository.");
1029 return;
1030 }
1031
1032 my $bfile = basename($file);
1033
1034 if (length $bfile > 100) {
1035 &perror("FATAL", $file, -1, "make sure patch file names contain no ".
1036 "more than 100 characters.");
1037 }
1038
1039 open(IN, "< $file") || return 0;
1040 $whole = '';
1041 my $checked_header = 0;
1042 while (<IN>) {
1043 $whole .= $_;
1044 if (/^--- / && !$checked_header) {
1045 $checked_header = 1;
1046 if ($_ !~ /UTC\s*$/) {
1047 &perror("WARN", $file, -1, "patch was not generated using ".
1048 "``make makepatch''. It is recommended to use ".
1049 "``make makepatch'' when you need to [re-]generate a ".
1050 "patch to ensure proper patch format.");
1051 }
1052 }
1053 }
1054
1055 if ($committer && $whole =~ /\wjavavm\w/) {
1056 my $lineno = &linenumber($`);
1057 &perror("WARN", $file, $lineno, "since javavmwrapper 2.0, the ".
1058 "``javavm'' command to invoke a JVM is deprecated. Use ".
1059 "``java'' instead");
1060 }
1061
1062 if ($whole =~ /
1063 /) {
1064 my $lineno = &linenumber($`);
1065 &perror("WARN", $file, $lineno, "patch contains ^M characters. ".
1066 "Consider defining USES=dos2unix to remove DOS line endings ".
1067 "from source files.");
1068 }
1069
1070 if ($whole !~ /\n$/s) {
1071 &perror("FATAL", $file, -1, "patch does not end with a newline, and the commit check ".
1072 "hook will fail.");
1073 }
1074
1075 close(IN);
1076 }
1077
1078 sub check_depends_syntax {
1079 my $tmp = shift;
1080 my $file = shift;
1081 my (%seen_depends, $j);
1082
1083 $ENV{'PORTSDIR'} //= $portsdir;
1084
1085 foreach my $i (grep(/^(PATCH_|EXTRACT_|LIB_|BUILD_|RUN_|TEST_|FETCH_)*DEPENDS[?+]?=/, split(/\n/, $tmp))) {
1086 $i =~ s/^((PATCH_|EXTRACT_|LIB_|BUILD_|RUN_|TEST_|FETCH_)*DEPENDS)[?+]?=[ \t]*//;
1087 $j = $1;
1088 $seen_depends{$j}++;
1089 if ($j ne 'DEPENDS' &&
1090 $i =~ /^\$\{([A-Z_]+DEPENDS)}\s*$/ &&
1091 $seen_depends{$1} &&
1092 $j ne $1)
1093 {
1094 print "OK: $j refers to $1, skipping checks.\n"
1095 if ($verbose);
1096 next;
1097 }
1098 print "OK: checking ports listed in $j.\n" if ($verbose);
1099 my @ks = split(/\s+/, $i);
1100 while (@ks) {
1101 my $k = shift @ks;
1102 if ($k =~ /^#/) {
1103 last;
1104 }
1105 my $ok = $k;
1106 if ($k =~ /^\$\{(\w+)\}$/) {
1107 $k = get_makevar($1);
1108 push @ks, split(/\s+/, $k);
1109 next;
1110 }
1111 if ($k eq '') {
1112 next;
1113 }
1114 my @l = split(':', $k);
1115
1116 print "OK: checking dependency value for $j.\n"
1117 if ($verbose);
1118 if ($ok =~ /\$\{((PATCH_|EXTRACT_|LIB_|BUILD_|RUN_|TEST_|FETCH_)*DEPENDS)}/) {
1119 &perror("WARN", $file, -1, "do not set $j to $ok. ".
1120 "Instead, explicity list out required $j dependencies.");
1121 }
1122
1123 if (($j ne 'DEPENDS'
1124 && scalar(@l) != 2 && scalar(@l) != 3)) {
1125 &perror("WARN", $file, -1, "wrong dependency value ".
1126 "for $j. $j requires ".
1127 "2 or 3 ".
1128 "colon-separated tuples.");
1129 next;
1130 }
1131 my %m = ();
1132 $m{'dep'} = $l[0];
1133 my ($di, $fl) = split(/\@/, $l[1]);
1134 $m{'dir'} = $di;
1135 $m{'fla'} = $fl // '';
1136 $m{'tgt'} = $l[2] // '';
1137 my %depmvars = ();
1138 foreach my $dv ($m{'dep'}, $m{'dir'}, $m{'tgt'}) {
1139 foreach my $mv ($dv =~ /\$\{([^}]+)\}/g) {
1140 if (defined($depmvars{$mv})) {
1141 next;
1142 }
1143 if (defined($makevar{$mv})) {
1144 $depmvars{$mv} = $makevar{$mv};
1145 } else {
1146 $depmvars{$mv} = &get_makevar($mv);
1147 }
1148 }
1149 }
1150
1151 # check Python flavor
1152 my $bdir = basename($m{'dir'});
1153 if ($bdir =~ /^py-/) {
1154 if ($m{'fla'} ne '${PY_FLAVOR}') {
1155 &perror("WARN", $file, -1, "you may want directory for ".
1156 "dependency $m{'dep'} to be $m{'dir'}\@\${PY_FLAVOR}");
1157 }
1158 }
1159
1160 # check JAVALIBDIR
1161 if ($m{'dep'} =~ m|share/java/classes|) {
1162 &perror("FATAL", $file, -1, "you should use \${JAVALIBDIR} ".
1163 "in BUILD_DEPENDS/RUN_DEPENDS to define ".
1164 "dependencies on JAR files installed in ".
1165 "\${JAVAJARDIR}");
1166 }
1167
1168 foreach my $dv ($m{'dep'}, $m{'dir'}, $m{'tgt'}) {
1169 foreach my $dmv (keys %depmvars) {
1170 $dv =~ s/\$\{$dmv\}/$depmvars{$dmv}/g;
1171 }
1172 }
1173
1174 print "OK: dep=\"$m{'dep'}\", ".
1175 "dir=\"$m{'dir'}\", tgt=\"$m{'tgt'}\"\n"
1176 if ($verbose);
1177
1178 # check USES=perl5
1179 if ($m{'dep'} =~ /^perl5(\.\d+)?$/) {
1180 &perror("WARN", $file, -1, "dependency to perl5 ".
1181 "listed in $j. consider using ".
1182 "USES[+]=perl5.");
1183 }
1184
1185 # Check for ${SITE_PERL} in depends
1186 if ($m{'dep'} =~ m|^(\$\{SITE_PERL}/.*)$|) {
1187 &perror("WARN", $file, -1, "dependency to $1 ".
1188 "listed in $j. consider using p5-Example-Package-Name>=0. See ".
1189 "http://www.freebsd.org/doc/en/books/porters-handbook/using-perl.html".
1190 " for more details.");
1191 }
1192
1193 # check USES=iconv
1194 if ($m{'dep'} =~ /^(iconv\.\d+)$/) {
1195 &perror("WARN", $file, -1, "dependency to $1 ".
1196 "listed in $j. consider using ".
1197 "USES[+]=iconv.");
1198 }
1199
1200 # check USES=gettext
1201 if ($m{'dep'} =~ /^(intl\.\d+)$/) {
1202 &perror("WARN", $file, -1, "dependency to $1 ".
1203 "listed in $j. consider using ".
1204 "USES[+]=gettext.");
1205 }
1206
1207 # check USES=gmake
1208 if ($m{'dep'} =~ /^(gmake|\$\{GMAKE})$/) {
1209 &perror("WARN", $file, -1, "dependency to $1 ".
1210 "listed in $j. consider using ".
1211 "USES[+]=gmake.");
1212 }
1213
1214 my %udeps = (
1215 'bison' => 'bison',
1216 'fmake' => 'fmake',
1217 );
1218 foreach my $udep (keys %udeps) {
1219 if ($m{'dep'} =~ /^$udep/) {
1220 &perror("WARN", $file, -1, "dependency to $udep ".
1221 "listed in $j. consider using ".
1222 "USES[+]=$udeps{$udep}.");
1223 }
1224 }
1225
1226 # check USE_QT
1227 if ($m{'dep'} =~ /^(qt\d)+$/) {
1228 &perror("WARN", $file, -1, "dependency to $1 ".
1229 "listed in $j. consider using ".
1230 "USE_QT.");
1231 }
1232
1233 # check LIBLTDL
1234 if ($m{'dep'} =~ /^(ltdl\.\d)+$/) {
1235 &perror("WARN", $file, -1, "dependency to $1 ".
1236 "listed in $j. consider using ".
1237 "USE_LIBLTDL.");
1238 }
1239
1240 # check GHOSTSCRIPT
1241 if ($m{'dep'} eq "gs") {
1242 &perror("WARN", $file, -1, "dependency to gs ".
1243 "listed in $j. consider using ".
1244 "USE_GHOSTSCRIPT(_BUILD|_RUN).");
1245 }
1246
1247
1248 # check for PREFIX
1249 if ($m{'dep'} =~ /\$\{PREFIX}/) {
1250 &perror("FATAL", $file, -1, "\${PREFIX} must not be ".
1251 "contained in *_DEPENDS. ".
1252 "use \${LOCALBASE} instead.");
1253 }
1254
1255 # Check for direct dependency on apache.
1256 if ($m{'dep'} =~ /\/www\/apache\d*\//) {
1257 &perror("FATAL", $file, -1, "do not depend on any apache ".
1258 "port in *_DEPENDS directly. ".
1259 "Instead use USE_APACHE=VERSION, where VERSION can be ".
1260 "found in \${PORTSDIR}/Mk/bsd.apache.mk.");
1261 }
1262
1263 # Check for over-specific shared library dependencies
1264 if ($j eq 'LIB_DEPENDS' && $m{'dep'} =~ m/(\.\d+$)/) {
1265 &perror("WARN", $file, -1, "$j don't specify the " .
1266 "ABI version number $1 in $m{'dep'} unless it is " .
1267 "really necessary.");
1268 }
1269
1270 # Check for old-style LIB_DEPENDS
1271 if ($j eq 'LIB_DEPENDS' && $m{'dep'} !~ m/^lib.*\.so$/) {
1272 &perror("WARN", $file, -1, "$j the new format is ".
1273 "libFOO.so (e.g., lib$m{'dep'}.so).");
1274 }
1275
1276 # Check port dir existence
1277 $k = $ENV{'PORTSDIR'}.'/'.$m{'dir'};
1278 if (! -d $k) {
1279 &perror("WARN", $file, -1, "no port directory $k ".
1280 "found, even though it is ".
1281 "listed in $j.");
1282 } else {
1283 print "OK: port directory $k found.\n"
1284 if ($verbose);
1285 }
1286
1287 # Check for relative path
1288 if ($k =~ /\/\.\.\//) {
1289 &perror("FATAL", $file, -1, "use absolute path".
1290 "instead of $k in *_DEPENDS.");
1291 } else {
1292 print "OK: path for port directory $k is absolute.\n"
1293 if ($verbose);
1294 }
1295 }
1296 }
1297 }
1298
1299 #
1300 # Makefile
1301 #
1302 sub checkmakefile {
1303 my($file) = @_;
1304 my($rawwhole, $whole, $idx, @sections);
1305 my($i, $j, $k, $l);
1306 my @cat = ();
1307 my $has_lang_cat = 0;
1308 my $port_lang = '';
1309 my $tmp;
1310 my $bogusdistfiles = 0;
1311 my @varnames = ();
1312 my($portname, $portversion, $distfiles, $distversionprefix, $distversion, $distversionsuffix, $distname, $extractsufx) = ('') x 8;
1313 my $masterport = 0;
1314 my $slaveport = 0;
1315 my $use_gnome_hack = 0;
1316 my $use_java = 0;
1317 my $use_ant = 0;
1318 my($realwrksrc, $wrksrc, $nowrksubdir) = ('', '', '');
1319 my(@mman, @pman);
1320 my(@aopt, @mopt, @opt);
1321 my($pkg_version, $versiondir, $versionfile) = ('', '', '');
1322 my $useindex = 0;
1323 my %deprecated = ();
1324 my @deplist = ();
1325 my %autocmdnames = ();
1326 my $pre_mk_line = 0;
1327 my $options_mk_line = 0;
1328 my $docsused = 0;
1329 my $optused = 0;
1330 my $desktop_entries = '';
1331
1332 my $masterdir = $makevar{MASTERDIR};
1333 if ($masterdir ne '' && $masterdir ne $makevar{'.CURDIR'}) {
1334 $slaveport = 1;
1335 }
1336
1337 open(IN, "< $file") || return 0;
1338 $rawwhole = '';
1339 $tmp = 0;
1340 while (<IN>) {
1341 if ($_ =~ /[ \t]+\n?$/) {
1342 &perror("WARN", $file, $., "whitespace before ".
1343 "end of line.");
1344 }
1345 if ($_ =~ /^ /) { # 8 spaces here!
1346 &perror("WARN", $file, $., "use tab (not space) to make ".
1347 "indentation");
1348 }
1349 if ($usetabs) {
1350 if (m/^[A-Za-z0-9_-]+.?=\t*? \t*?/) {
1351 if (m/[?+]=/) {
1352 &perror("WARN", $file, $., "use a tab (not space) after a ".
1353 "variable name");
1354 } else {
1355 &perror("FATAL", $file, $., "use a tab (not space) after a ".
1356 "variable name");
1357 }
1358 }
1359 }
1360 $rawwhole .= $_;
1361 }
1362 close(IN);
1363
1364 #
1365 # whole file: blank lines.
1366 #
1367 $whole = "\n" . $rawwhole;
1368 study $whole;
1369 print "OK: checking contiguous blank lines in $file.\n"
1370 if ($verbose);
1371 $i = "\n" x ($contblank + 2);
1372 if ($whole =~ /$i/) {
1373 my $lineno = &linenumber($`);
1374 &perror("FATAL", $file, $lineno, "contiguous blank lines ".
1375 "(> $contblank lines) found.");
1376 }
1377
1378 #
1379 # whole file: header
1380 #
1381 my @lines = split("\n", $whole);
1382 print "OK: checking header in $file.\n" if ($verbose);
1383 if ($lines[1] =~ /^# (?:New )?[Pp]orts collection [mM]akefile/) {
1384 &perror("FATAL", $file, 1, "old style headers found.");
1385 } elsif ($lines[1] =~ /^# Created by: \S/) {
1386 if ($lines[2] !~ /^# \$$rcsidstr[:\$]/) {
1387 &perror("FATAL", $file, 2, "header should be ".
1388 "followed by \$$rcsidstr\$.");
1389 } elsif ($lines[3] !~ /^$/) {
1390 #&perror("FATAL", $file, 3, "do not add extra ".
1391 # "empty comments after header.");
1392 }
1393 # special case for $rcsidsrt\nMCom:
1394 } elsif ($lines[1] =~ /^# \$$rcsidstr[:\$]/ and $lines[2] =~ /^#\s+\$MCom[:\$]/ and $lines[3] =~ /^$/) {
1395 # DO NOTHING
1396 } elsif ($lines[1] !~ /^# \$$rcsidstr[:\$]/ or $lines[2] !~ /^$/) {
1397 &perror("FATAL", $file, 1, "incorrect header; ".
1398 "simply use \$$rcsidstr\$.");
1399 }
1400
1401 #
1402 # whole file: $(VARIABLE)
1403 #
1404 if ($parenwarn) {
1405 print "OK: checking for \$(VARIABLE).\n" if ($verbose);
1406 if ($whole =~ /[^\$]\$\([\w\d]+\)/) {
1407 my $lineno = &linenumber($`);
1408 &perror("WARN", $file, $lineno, "use \${VARIABLE}, instead of ".
1409 "\$(VARIABLE).");
1410 }
1411 }
1412
1413 #
1414 # whole file: empty(${VARIABLE})
1415 #
1416 if ($parenwarn) {
1417 print "OK: checking for empty(\${VARIABLE}).\n" if ($verbose);
1418 if ($whole =~ /empty\(\$\{[\w\d]+/) {
1419 my $lineno = &linenumber($`);
1420 &perror("WARN", $file, $lineno, "use empty(VARIABLE), instead of ".
1421 "empty(\${VARIABLE}).");
1422 }
1423 }
1424
1425 #
1426 # whole file: use of !=
1427 #
1428 print "OK: checking for use of !=.\n" if ($verbose);
1429 if ($whole =~ /^[\w\d_]+\!=/m) {
1430 my $lineno = &linenumber($`);
1431 &perror("WARN", $file, $lineno, "use of != in assignments is almost ".
1432 "never a good thing to do. Try to avoid using them. See ".
1433 "http://lists.freebsd.org/pipermail/freebsd-ports/2008-July/049777.html ".
1434 "for some helpful hints on what to do instead.");
1435 }
1436
1437 #
1438 # whole file: use of .elseif
1439 #
1440 print "OK: checking for use of .elseif.\n" if ($verbose);
1441 if ($whole =~ /^\.\s*else\s*if/m) {
1442 my $lineno = &linenumber($`);
1443 &perror("FATAL", $file, $lineno, "use of .elseif (or .else if) is not ".
1444 "supported in all versions of BSD. Use .elif instead.");
1445 }
1446
1447 #
1448 # whole file: use of @${INSTALL_foo}
1449 #
1450 print "OK: checking for use of muted INSTALL_ commands.\n" if ($verbose);
1451 if ($whole =~ /^\s+\@\$\{INSTALL_/m) {
1452 my $lineno = &linenumber($`);
1453 &perror("WARN", $file, $lineno, "do not use muted INSTALL_foo ".
1454 "commands (i.e., those that start with '\@'). These should be ".
1455 "printed.");
1456 }
1457
1458 #
1459 # checking for use of ${ENV}
1460 #
1461 print "OK: checking for use of \${ENV} instead of \${SETENV}.\n" if ($verbose);
1462 if ($whole =~ /\$\{ENV}/m) {
1463 my $lineno = &linenumber($`);
1464 &perror("WARN", $file, $lineno, "most uses of \${ENV} should really ".
1465 "be \${SETENV} to avoid strange behaviors in sh(1).");
1466 }
1467
1468 #
1469 # whole file: use of IGNOREFILES
1470 #
1471 print "OK: checking for use of IGNOREFILES.\n" if ($verbose);
1472 if ($whole =~ /\nIGNOREFILES.?=/m) {
1473 my $lineno = &linenumber($`);
1474 &perror("FATAL", $file, $lineno, "IGNOREFILES considered unsafe and ".
1475 "not supported anymore.");
1476 }
1477
1478 #
1479 # whole file: use of PLIST_DIRSTRY
1480 #
1481 print "OK: checking for use of PLIST_DIRSTRY.\n" if ($verbose);
1482 if ($whole =~ /\nPLIST_DIRSTRY.?=/m) {
1483 my $lineno = &linenumber($`);
1484 &perror("WARN", $file, $lineno, "PLIST_DIRSTRY is deprecated. Please ".
1485 "use PLIST_DIRS instead.");
1486 }
1487
1488 #
1489 # whole file: PLIST_FILES and PLIST_DIRS
1490 #
1491 print "OK: checking PLIST_FILES and PLIST_DIRS.\n" if ($verbose);
1492 if ($whole =~ /\nPLIST_FILES.?=/ || $whole =~ /\nPLIST_DIRS.?=/) {
1493 if (-f 'pkg-plist') {
1494 my $lineno = &linenumber($`);
1495 &perror("WARN", $file, $lineno, "You may remove pkg-plist ".
1496 "if you use PLIST_FILES and/or PLIST_DIRS.");
1497 }
1498 my @plist_files = split(/\s+/, $makevar{PLIST_FILES});
1499 foreach my $plist_file (@plist_files) {
1500 if ($plist_file =~ m|lib[^\/]+\.so(\.\d+)?$| &&
1501 $makevar{USE_LDCONFIG} eq '') {
1502 &perror("WARN", "", -1, "PLIST_FILES: installing shared libraries, ".
1503 "please define USE_LDCONFIG as appropriate");
1504 }
1505 if ($plist_file =~ m|\.omf$| && $makevar{INSTALLS_OMF} eq '') {
1506 &perror("WARN", "", -1, "PLIST_FILES: installing OMF files, ".
1507 "please define INSTALLS_OMF (see the FreeBSD GNOME ".
1508 "porting guide at ".
1509 "http://www.FreeBSD.org/gnome/docs/porting.html ".
1510 "for more details)");
1511 }
1512 if ($plist_file =~ m|\.core$| && $plist_file !~ /^\@/) {
1513 &perror("WARN", "", -1, "PLIST_FILES: this port installs a file which ".
1514 "ends in \".core\". This file may be deleted if ".
1515 "daily_clean_disks_enable=\"YES\" in /etc/periodic.conf. ".
1516 "If possible, install this file with a different name.");
1517 }
1518 if ($plist_file =~ m|^share/icons/.*/| &&
1519 $makevar{INSTALLS_ICONS} eq '' &&
1520 needs_installs_icons()) {
1521 &perror("WARN", "", -1, "PLIST_FILES: installing icons, ".
1522 "please define INSTALLS_ICONS as appropriate");
1523 }
1524 if ($plist_file =~ /%%[\w_\d]+%%/) {
1525 &perror("FATAL", "", -1, "PLIST_FILES: files cannot contain ".
1526 "%%FOO%% variables. Use make variables and logic instead");
1527 }
1528
1529 }
1530 }
1531
1532 #
1533 # whole file: USE_* and others variables used too late
1534 #
1535 my @options_early = qw(
1536 OPTIONS_DEFAULT
1537 OPTIONS_DEFINE
1538 OPTIONS_EXCLUDE
1539 OPTIONS_GROUP.*?
1540 OPTIONS_MULTI.*?
1541 OPTIONS_RADIO.*?
1542 OPTIONS_SINGLE.*?
1543 );
1544
1545 pos($whole) = 0;
1546 if ($whole =~ /^\.include\s+<bsd\.port\.pre\.mk>$/gm) {
1547 # Remember position
1548 $pre_mk_line = &linenumber($`) + 1;
1549 print "OK: checking for USE_* used too late.\n" if ($verbose);
1550 my @use_early = qw(
1551 BZIP2
1552 GNUSTEP
1553 IMAKE
1554 KDE(?:BASE|LIBS)_VER
1555 (?:LIB)?RUBY
1556 LINUX_PREFIX
1557 OPENSSL
1558 PYTHON
1559 QT2?
1560 QT_VER
1561 X_PREFIX
1562 ZIP
1563 );
1564
1565 my @other_early = qw(
1566 EMACS_PORT_NAME
1567 );
1568
1569 my $earlypattern = join('|', 'USE_(?:'.join('|', @use_early).')',
1570 @other_early, @options_early);
1571
1572 while ($whole =~ /^($earlypattern)[+?:!]?=/gmo) {
1573 my $lineno = &linenumber($`);
1574 &perror("FATAL", $file, $lineno, "$1 is set after ".
1575 "including bsd.port.pre.mk.");
1576 }
1577 }
1578
1579 #
1580 # whole file: check OPTIONS
1581 #
1582 print "OK: checking OPTIONS.\n" if ($verbose);
1583 pos($whole) = 0;
1584 if ($whole =~ /^\.include\s+<bsd\.port\.options\.mk>$/gm) {
1585 # Remember position
1586 $options_mk_line = &linenumber($`) + 1;
1587 }
1588
1589 pos($whole) = 0;
1590 if ($whole =~ /^\.include\s+<bsd\.port\.options\.mk>$/gm) {
1591 my $earlypattern = join('|', @options_early);
1592 while ($whole =~ /^($earlypattern)[+?]?=/gmo) {
1593 my $lineno = &linenumber($`);
1594 &perror("FATAL", $file, $lineno, "$1 is set after ".
1595 "including bsd.port.options.mk.");
1596 }
1597 }
1598
1599 pos($whole) = 0;
1600 foreach my $i ("OPTIONS_RADIO","OPTIONS_SINGLE",
1601 "OPTIONS_MULTI","OPTIONS_GROUP") {
1602 foreach my $j (split(/\s+/, $makevar{$i})) {
1603 if ($j) {
1604 my @ocount = split(/\s+/, get_makevar("${i}_${j}"));
1605 if (!scalar(@ocount)) {
1606 &perror("FATAL", $file, -1,
1607 "Description for ${i}_${j} does not exist");
1608 } else {
1609 push @aopt, @ocount;
1610 }
1611 }
1612 }
1613 }
1614
1615 @opt = split(/\s+/, $makevar{OPTIONS_DEFINE});
1616 pos($whole) = 0;
1617 while ($whole =~ /PORT_OPTIONS:M(\w+)/mg) {
1618 push @mopt, $1;
1619 my $lineno = &linenumber($`) + 1;
1620 &perror("FATAL", $file, $lineno, "PORT_OPTIONS:M$1 is used before ".
1621 "including bsd.port.pre.mk or bsd.port.options.mk.")
1622 if ($optused && $lineno < $pre_mk_line &&
1623 $lineno < $options_mk_line);
1624 }
1625 my @options_helpers = qw(
1626 __DUMMY__
1627 ALL_TARGET
1628 BUILD_DEPENDS
1629 EXTRACT_DEPENDS
1630 FETCH_DEPENDS
1631 LIB_DEPENDS
1632 PKG_DEPENDS
1633 RUN_DEPENDS
1634 CATEGORIES
1635 CFLAGS
1636 CMAKE_OFF
1637 CMAKE_ON
1638 CMAKE_BOOL_OFF
1639 CMAKE_BOOL
1640 CONFIGURE_ENABLE
1641 CONFIGURE_ENV
1642 CONFIGURE_OFF
1643 CONFIGURE_ON
1644 CONFIGURE_WITH
1645 CPPFLAGS
1646 CXXFLAGS
1647 DISTFILES
1648 INSTALL_TARGET
1649 LDFLAGS
1650 MAKE_ARGS
1651 MAKE_ENV
1652 EXTRA_PATCHES
1653 PATCHFILES
1654 PATCH_DEPENDS
1655 PATCH_SITES
1656 PLIST_DIRS
1657 PLIST_DIRSTRY
1658 PLIST_FILES
1659 USE
1660 USES
1661 VARS
1662 VARS_OFF
1663 );
1664
1665 my $m = join("|", @options_helpers);
1666
1667 if ($makevar{OPTIONS_SUB}) {
1668 if ($makevar{PLIST_FILES}) {
1669 foreach my $i (split(/\s+/, $makevar{PLIST_FILES})) {
1670 while ($i =~ /\%\%([^%]+)\%\%/g) {
1671 push @popt, $1;
1672 }
1673 }
1674 }
1675 if ($makevar{PLIST_DIRS}) {
1676 foreach my $i (split(/\s+/, $makevar{PLIST_DIRS})) {
1677 while ($i =~ /\%\%([^%]+)\%\%/g) {
1678 push @popt, $1;
1679 }
1680 }
1681 }
1682 if (-f 'pkg-plist') {
1683 open(PL, 'pkg-plist');
1684 my @pcontents = <PL>;
1685 close(PL);
1686 foreach my $i (@pcontents) {
1687 while ($i =~ /\%\%([^%]+)\%\%/g) {
1688 push @popt, $1;
1689 }
1690 }
1691 }
1692 # special cases for PORTDOCS/PORTEXAMPLES
1693 push @popt, "DOCS" if $makevar{PORTDOCS};
1694 push @popt, "EXAMPLES" if $makevar{PORTEXAMPLES};
1695
1696 # uniq(@popt)
1697 my %seen = ();
1698 @popt = grep { !$seen{$_}++ } @popt;
1699 }
1700 foreach my $i (@popt) {
1701 if ($i eq 'PORTDOCS') {
1702 if (!grep(/^DOCS$/, @opt)) {
1703 &perror("FATAL", $file, -1, "PORTDOCS appears in plist ".
1704 "but DOCS is not listed in OPTIONS_DEFINE.");
1705 }
1706 } elsif ($i eq 'PORTEXAMPLES') {
1707 if (!grep(/^EXAMPLES$/, @opt)) {
1708 &perror("FATAL", $file, -1, "PORTEXAMPLES appears in plist ".
1709 "but EXAMPLES is not listed in OPTIONS_DEFINE.");
1710 }
1711 }
1712 }
1713
1714 foreach my $i ((@opt, @aopt)) {
1715 # skip global options
1716 next if ($i eq 'DOCS' or $i eq 'NLS' or $i eq 'EXAMPLES' or $i eq 'IPV6' or $i eq 'X11' or $i eq 'DEBUG');
1717 if (!grep(/^$i$/, (@mopt, @popt))) {
1718 if ($whole !~ /\n${i}_($m)(_\w+)?(.)?=[^\n]+/) {
1719 if (!$slaveport) {
1720 &perror("WARN", $file, -1, "$i is listed in ".
1721 "OPTIONS_DEFINE, but no PORT_OPTIONS:M$i appears.");
1722 } else {
1723 &perror("WARN", $file, -1, "$i is listed in ".
1724 "OPTIONS_DEFINE, but no PORT_OPTIONS:M$i appears ".
1725 "in this slave Makefile. Make sure it appears in ".
1726 "the master's Makefile.");
1727 }
1728 }
1729 }
1730 }
1731
1732 foreach my $i (@mopt) {
1733 if (!grep(/^$i$/, @opt, @aopt)) {
1734 # skip global options
1735 next if ($i eq 'DOCS' or $i eq 'NLS' or $i eq 'EXAMPLES' or $i eq 'IPV6' or $i eq 'X11');
1736 &perror("WARN", $file, -1, "$i appears in PORT_OPTIONS:M, ".
1737 "but is not listed in OPTIONS_DEFINE.");
1738 }
1739 }
1740
1741 #
1742 # whole file: check DESKTOP_ENTRIES for ${TRUE}/${FALSE}
1743 #
1744 print "OK: checking DESKTOP_ENTRIES for \${TRUE}/\${FALSE}.\n" if ($verbose);
1745 $desktop_entries = &get_makevar_raw('DESKTOP_ENTRIES');
1746 if ($desktop_entries =~ /\$\{TRUE}/ or $desktop_entries =~ /\$\{FALSE}/ or
1747 $desktop_entries =~ /\"true\"/ or $desktop_entries =~ /\"false\"/) {
1748 &perror("FATAL", $file, -1, "Use true/false (without quotes) instead of \${TRUE}/\${FALSE} in DESKTOP_ENTRIES.");
1749 }
1750
1751 #
1752 # whole file: USE_* as a user-settable option
1753 #
1754 print "OK: checking for USE_* as a user-settable option.\n" if ($verbose);
1755 while ($whole =~ /\n\s*\.\s*(?:el)?if[^\n]*?\b(\w*USE_)(\w+)(?![^\n]*\n#?\.error)/g) {
1756 my $lineno = &linenumber($`);
1757 &perror("WARN", $file, $lineno, "is $1$2 a user-settable option? ".
1758 "Consider using WITH_$2 instead.")
1759 if ($1.$2 ne 'USE_GCC');
1760 }
1761
1762 #
1763 # whole file: NO_CHECKSUM
1764 #
1765 # XXX Don't compress newlines since it messes up line number calculation.
1766 #$whole =~ s/\n#[^\n]*/\n/g;
1767 #$whole =~ s/\n\n+/\n/g;
1768 print "OK: checking NO_CHECKSUM.\n" if ($verbose);
1769 if ($whole =~ /\nNO_CHECKSUM/) {
1770 my $lineno = &linenumber($`);
1771 &perror("FATAL", $file, $lineno, "NO_CHECKSUM is a user ".
1772 "variable and is not to be set in a port's Makefile.");
1773 }
1774
1775 #
1776 # whole file: MACHINE_ARCH
1777 #
1778 print "OK: checking MACHINE_ARCH.\n" if ($verbose);
1779 if ($whole =~ /\nMACHINE_ARCH/) {
1780 my $lineno = &linenumber($`);
1781 &perror("FATAL", $file, $lineno, "MACHINE_ARCH should never be ".
1782 "overridden.");
1783 }
1784
1785 #
1786 # whole file: DEPRECATED
1787 #
1788 print "OK: checking DEPRECATED.\n" if ($verbose);
1789 if ($whole =~ /\nDEPRECATED[+?]?=[ \t]*"/ &&
1790 $whole !~ /\nDEPRECATED[+?]?=[ \t]*"\$\{BROKEN\}"/) {
1791 my $lineno = &linenumber($`);
1792 &perror("WARN", $file, $lineno, "DEPRECATED messages should not ".
1793 "be quoted unless they are exactly \"\${BROKEN}\".");
1794 }
1795 if ($whole =~ /\nDEPRECATED[+?]?=[^"]*\$\{BROKEN\}/) {
1796 my $lineno = &linenumber($`);
1797 &perror("WARN", $file, $lineno, "\"\${BROKEN}\" must be quoted ".
1798 "when it is the source of DEPRECATED.");
1799 }
1800
1801 #
1802 # whole file: BROKEN et al.
1803 #
1804 my ($var);
1805 foreach $var (qw(IGNORE BROKEN COMMENT FORBIDDEN MANUAL_PACKAGE_BUILD NO_CDROM NO_PACKAGE RESTRICTED)) {
1806 print "OK: checking ${var}.\n" if ($verbose);
1807 if ($whole =~ /\n${var}[+?]?=[ \t]+"/) {
1808 my $lineno = &linenumber($`);
1809 &perror("WARN", $file, $lineno, "${var} messages should not ".
1810 "be quoted.");
1811 }
1812 }
1813
1814 if ($makevar{COMMENT} =~ /^An? / || $makevar{COMMENT} =~ /^The /) {
1815 &perror("WARN", $file, -1, "COMMENT is not supposed to begin with ".
1816 "'A ', 'An ', or 'The '.");
1817 }
1818
1819 if ($whole =~ /\nIGNORE[+?]?=[ \t]+[^a-z \t]/ ||
1820 $whole =~ /^IGNORE[+?]?=[ \t]+.*\.$/m) {
1821 my $lineno = &linenumber($`);
1822 &perror("WARN", $file, $lineno, "IGNORE messages should begin ".
1823 "with a lowercase letter and end without a period.");
1824 }
1825
1826 if ($whole =~ /\nBROKEN[+?]=[ \t]+[^a-z \t]/ ||
1827 $whole =~ /^BROKEN[+?]?=[ \t]+.*\.$/m) {
1828 my $lineno = &linenumber($`);
1829 &perror("WARN", $file, $lineno, "BROKEN messages should begin ".
1830 "with a lowercase letter and end without a period.");
1831 }
1832
1833 #
1834 # whole file: PKGNAME
1835 #
1836 print "OK: checking PKGNAME.\n" if ($verbose);
1837 if ($whole =~ /\nPKGNAME.?=/) {
1838 my $lineno = &linenumber($`);
1839 &perror("FATAL", $file, $lineno, "PKGNAME is obsoleted by PORTNAME, ".
1840 "PORTVERSION, PKGNAMEPREFIX and PKGNAMESUFFIX.");
1841 }
1842
1843 #
1844 # whole file: MAKE_JOBS_UNSAFE
1845 #
1846 print "OK: checking for MAKE_JOBS_UNSAFE in combination with NO_BUILD.\n" if ($verbose);
1847 if ($whole =~ /\nMAKE_JOBS_UNSAFE.?=/) {
1848 my $matched = $1;
1849 if ($whole =~ /\nNO_BUILD.?=/) {
1850 my $lineno = &linenumber($`);
1851 &perror("WARN", $file, $lineno, "MAKE_JOBS_UNSAFE should not ".
1852 "be used in combination with NO_BUILD. You ".
1853 "should remove MAKE_JOBS_UNSAFE from your Makefile.");
1854 }
1855 }
1856
1857 #
1858 # whole file: Check if some macros are sorted
1859 #
1860 my @macros_to_sort = qw(
1861 ONLY_FOR_ARCHS
1862 NOT_FOR_ARCHS
1863 );
1864 print "OK: checking to see if certain macros are sorted.\n" if ($verbose);
1865 foreach my $sorted_macro (@macros_to_sort) {
1866 while ($whole =~ /\n$sorted_macro.?=\s*(.+)\n/g) {
1867 my $lineno = &linenumber($`);
1868 my $srex = $1;
1869 my @smacros = sort(split / /, $srex);
1870 if (join(" ", @smacros) ne $srex) {
1871 &perror("WARN", $file, $lineno, "the arguments to $sorted_macro ".
1872 "are not sorted. Please consider sorting them.");
1873 }
1874 }
1875 }
1876
1877 #
1878 # whole file: USE_GNOME=pkgconfig
1879 #
1880 print "OK: checking for USE_GNOME=pkgconfig.\n" if ($verbose);
1881 if ($makevar{USE_GNOME} =~ /pkgconfig/) {
1882 &perror("WARN", $file, -1, "USE_GNOME=pkgconfig is now obsolete. ".
1883 "Use USES[+]=pkgconfig instead.");
1884 }
1885
1886 #
1887 # whole file: using INSTALLS_ICONS when it is not wanted
1888 #
1889 if (!($makevar{INSTALLS_ICONS} eq '') &&
1890 !needs_installs_icons()) {
1891 &perror("WARN", $file, -1, "INSTALLS_ICONS is set, but should not be.");
1892 }
1893
1894 #
1895 # whole file: EXPIRATION_DATE
1896 #
1897 print "OK: checking for valid EXPIRATION_DATE.\n" if ($verbose);
1898 my $edate;
1899 if (($edate) = ($whole =~ m/\nEXPIRATION_DATE\??=[ \t]*([^\n]*)\n/)) {
1900 my $lineno = &linenumber($`);
1901 my $ndate = $edate;
1902 if ($ndate eq '' || length $ndate < 10) {
1903 $ndate = '0000-00-00';
1904 }
1905 if ($ndate ne strftime("%Y-%m-%d", 0, 0, 0,
1906 substr($ndate, 8, 2),
1907 substr($ndate, 5, 2) - 1,
1908 substr($ndate, 0, 4) - 1900)) {
1909 &perror("FATAL", $file, $lineno, "EXPIRATION_DATE ($edate) is ".
1910 "either not in YYYY-MM-DD format or it is not a valid ".
1911 "date.");
1912 }
1913 }
1914
1915 #
1916 # whole file: IS_INTERACTIVE/NOPORTDOCS|PORT_OPTIONS:MDOCS
1917 #
1918 print "OK: checking IS_INTERACTIVE.\n" if ($verbose);
1919 if ($whole =~ /\nIS_INTERACTIVE/) {
1920 if ($whole !~ /defined\((BATCH|FOR_CDROM)\)/) {
1921 my $lineno = &linenumber($`);
1922 &perror("WARN", $file, $lineno, "use of IS_INTERACTIVE ".
1923 "discouraged. provide batch mode by using BATCH and/or ".
1924 "FOR_CDROM.");
1925 }
1926 }
1927 print "OK: checking for use of PORT_OPTIONS:MDOCS.\n" if ($verbose);
1928 if ($sharedocused && $whole =~ /PORT_OPTIONS:MDOCS/) {
1929 $docsused++;
1930 }
1931 print "OK: checking for use of NOPORTDOCS.\n" if ($verbose);
1932 if ($whole =~ /defined\s*\(?NOPORTDOCS\)?/ ||
1933 $whole =~ /def\s*\(?NOPORTDOCS\)?/) {
1934 my $lineno = &linenumber($`);
1935 &perror("WARN", $file, $lineno, "NOPORTDOCS is deprecated. Please ".
1936 "use PORT_OPTIONS:MDOCS instead.");
1937 }
1938 print "OK: checking for use of NOPORTEXAMPLES.\n" if ($verbose);
1939 if ($whole =~ /defined\s*\(?NOPORTEXAMPLES\)?/ ||
1940 $whole =~ /def\s*\(?NOPORTEXAMPLES\)?/) {
1941 my $lineno = &linenumber($`);
1942 &perror("WARN", $file, $lineno, "NOPORTEXAMPLES is deprecated. Please ".
1943 "use PORT_OPTIONS:MEXAMPLES instead.");
1944 }
1945 if ($sharedocused && $whole !~ /defined\s*\(?NOPORTDOCS\)?/
1946 && $whole !~ /def\s*\(?NOPORTDOCS\)?/) {
1947 if ($docsused == 1
1948 && $whole !~ m#(\$[\{\(]PREFIX[\}\)]|$localbase)/share/doc/#) {
1949 &perror("WARN", $file, -1, "you should only use \".if \${PORT_OPTIONS:MDOCS}\" to wrap ".
1950 "installation of files into $localbase/share/doc if the".
1951 " collection of files is large and it takes considerable time".
1952 " to copy.");
1953 }
1954 } else {
1955 $docsused++;
1956 }
1957 if ($docsused > 1) {
1958 &perror("FATAL", $file, -1, "Both NOPORTDOCS and PORT_OPTIONS:MDOCS are found. ".
1959 "Remove one or another.");
1960 }
1961 print "OK: checking for use of NOPORTDOCS.\n" if ($verbose);
1962 if ($whole =~ /NOPORTDOCS/) {
1963 my $lineno = &linenumber($`);
1964 &perror("WARN", $file, $lineno, "NOPORTDOCS found. Consider ".
1965 "using PORT_OPTIONS:MDOCS.");
1966 }
1967
1968 #
1969 # whole file: check for USES[+]=gettext
1970 #
1971 print "OK: checking for USES=gettext without PORT_OPTIONS:MNLS.\n" if ($verbose);
1972 if ($makevar{USES} =~ /\bgettext\b/ && $whole !~ /PORT_OPTIONS:MNLS/
1973 && $whole !~ /NLS_USES=.*\bgettext\b/) {
1974 &perror("WARN", $file, -1, "Consider adding support for a NLS ".
1975 "knob to conditionally disable gettext support.");
1976 }
1977
1978 #
1979 # whole file: check for deprecated commands
1980 #
1981 print "OK: checking for deprecated macros.\n" if $verbose;
1982
1983 %deprecated = (
1984 USE_RCORDER => 'USE_RC_SUBR',
1985 );
1986
1987 @deplist = (\%deprecated);
1988
1989 for my $dlst (@deplist) {
1990 my $hurl = $dlst->{'__HELP__'};
1991 foreach my $depmacro (keys %{$dlst}) {
1992 if ($whole =~ /\n($depmacro)[+?:!]?=/) {
1993 my $derror = "$depmacro is ".
1994 "deprecated, use $dlst->{$1} instead";
1995 if (defined($hurl)) {
1996 $derror .= " (see $hurl for more details)";
1997 }
1998 &perror("FATAL", $file, -1, $derror);
1999 }
2000 }
2001 }
2002
2003 #
2004 # whole file: DOS line endings
2005 #
2006 print "OK: checking for DOS line ending removal.\n" if ($verbose);
2007 if ($whole =~ /
2008 / || $whole =~ /:cntrl:/) {
2009 my $lineno = &linenumber($`);
2010 &perror("WARN", $file, $lineno, "Possible manual removal of DOS ".
2011 "line endings found. Consider defining USES=dos2unix instead.");
2012 }
2013
2014 #
2015 # whole file: direct use of command names
2016 #
2017 my %cmdnames = ();
2018 print "OK: checking direct use of command names.\n" if ($verbose);
2019 foreach my $i (qw(
2020 awk basename brandelf cat chmod chown cp cpio dialog dirname egrep expr
2021 false file find gmake grep gzcat ldconfig ln md5 mkdir mv objcopy paste patch
2022 pax perl printf rm rmdir ruby sed sdl-config sh sort sysctl touch tr which
2023 xargs xmkmf
2024 )) {
2025 $cmdnames{$i} = "\$\{\U$i\E\}";
2026 }
2027 $cmdnames{'echo'} = '${ECHO_CMD} or ${ECHO_MSG}';
2028 $cmdnames{'env'} = '${SETENV}';
2029 $cmdnames{'gunzip'} = '${GUNZIP_CMD}';
2030 $cmdnames{'gzip'} = '${GZIP_CMD}';
2031 $cmdnames{'install'} = '${INSTALL_foobar}';
2032 $cmdnames{'python'} = '${PYTHON_CMD}';
2033 $cmdnames{'sdl-config'} = '${SDL_CONFIG}';
2034 $cmdnames{'strip'} = '${STRIP_CMD}';
2035 $cmdnames{'unzip'} = '${UNZIP_CMD}';
2036 $cmdnames{'pkg_create'} = '${PKG_CMD}';
2037 foreach my $i (qw(aclocal autoconf autoheader automake autoreconf autoupdate autoscan ifnames libtoolize)) {
2038 $autocmdnames{$i} = "\$\{" . ( ( $i !~ /auto|aclocal/ ) ? "AUTO" : "" ) . "\U$i\E\}";
2039 }
2040 #
2041 # ignore parameter string to echo command.
2042 # note that we leave the command as is, since we need to check the
2043 # use of echo itself.
2044 $j = $whole;
2045 $j =~ s/([ \t][\@\-]{0,2})(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+(?:"(?:\\'|\\"|[^"])*"|'(?:\\'|\\"|[^'])*')[ \t]*;?(\n?)/$1$2;$3/g; #"
2046 # ignore variables names in .for loops, but not what's at the end
2047 # of the for loop
2048 $j =~ s/(\.for +)([^ ]*)( .*)/$1$3/;
2049 foreach my $i (keys %cmdnames) {
2050 # XXX This is a hack. Really, we should break $j up into individual
2051 # lines, and go through each one.
2052 while ($j =~ /^(.*\b$i\b.*)$/gm) {
2053 my $lineno = &linenumber($`);
2054 my $curline = $1;
2055 my $dte_test = $curline;
2056 $dte_test =~ s/^\s+//g;
2057 if ($desktop_entries =~ /\Q$dte_test\E$/) {
2058 next;
2059 }
2060 if ($curline =~ /(?:^|\s)[\@\-]{0,2}$i(?:$|\s)/
2061 && $curline !~ /^[A-Z]+_TARGET[?+]?=[^\n]+$i/m
2062 && $curline !~ /^[A-Z]+_INSTALL_TARGET[?+]?=[^\n]+$i/m
2063 && $curline !~ /^IGNORE(_[\w\d]+)?(.)?=[^\n]+$i/m
2064 && $curline !~ /^BROKEN(_[\w\d]+)?(.)?=[^\n]+$i/m
2065 && $curline !~ /^RESTRICTED(.)?=[^\n]+$i/m
2066 && $curline !~ /^NO_PACKAGE(.)?=[^\n]+$i/m
2067 && $curline !~ /^NO_CDROM(.)?=[^\n]+$i/m
2068 && $curline !~ /^MAINTAINER(.)?=[^\n]+$i/m
2069 && $curline !~ /^CATEGORIES(.)?=[^\n]+$i/m
2070 && $curline !~ /^(\w+)?USES(.)?=[^\n]+$i/m
2071 && $curline !~ /^WX_COMPS(.)?=[^\n]+$i/m
2072 && $curline !~ /^ONLY_FOR_ARCHS_REASON(_[\w\d]+)?(.)?=[^\n]+$i/m
2073 && $curline !~ /^NOT_FOR_ARCHS_REASON(_[\w\d]+)?(.)?=[^\n]+$i/m
2074 && $curline !~ /^SHEBANG_FILES(.)?=[^\n]+$i/m
2075 && $curline !~ /^[A-Z0-9_]+_DESC=[^\n]+$i/m
2076 && $curline !~ /#.*?$i/m
2077 && $curline !~ /^\s*#.+$/m
2078 && $curline !~ /\$\{MAKE_CMD\}.*\binstall\b/m
2079 && $curline !~ /\-\-$i/m
2080 && $curline !~ /^COMMENT(.)?=[^\n]+$i/m) {
2081 &perror("WARN", $file, $lineno, "possible direct use of ".
2082 "command \"$i\" found. use ".
2083 "$cmdnames{$i} instead.");
2084 }
2085 }
2086 }
2087
2088 foreach my $i (keys %autocmdnames) {
2089 # XXX Same hack as above.
2090 while ($j =~ /^(.*(\b$i\d*).*)$/gm) {
2091 my $lm = $1;
2092 my $sm = $2;
2093 my $lineno = &linenumber($`);
2094 if ($lm =~ /(^|\s+)[\@\-]{0,2}($i\d*)\b/
2095 && $lm !~ /^[A-Z]+_TARGET[?+]?=[^\n]+($i\d*)/m
2096 && $lm !~ /^IGNORE(.)?=[^\n]+($i\d*)/m
2097 && $lm !~ /^BROKEN(.)?=[^\n]+($i\d*)/m
2098 && $lm !~ /^RESTRICTED(.)?=[^\n]+($i\d*)/m
2099 && $lm !~ /^NO_PACKAGE(.)?=[^\n]+($i\d*)/m
2100 && $lm !~ /^NO_CDROM(.)?=[^\n]+($i\d*)/m
2101 && $lm !~ /^MAINTAINER(.)?=[^\n]+($i\d*)/m
2102 && $lm !~ /^CATEGORIES(.)?=[^\n]+($i\d*)/m
2103 && $lm !~ /^USES(.)?=[^\n]+$i/m
2104 && $lm !~ /^[A-Z0-9_]+_DESC=[^\n]+($i\d*)/m
2105 && $lm !~ /^SHEBANG_FILES(.)?=[^\n]+($i\d*)/m
2106 && $lm !~ /^USE_AUTOTOOLS(.)?=[^\n]+($i\d*)/m
2107 && $lm !~ /^\s*#.+$/m
2108 && $lm !~ /^COMMENT(.)?=[^\n]+($i\d*)/m) {
2109 &perror("WARN", $file, $lineno, "possible direct use of ".
2110 "command \"$sm\" found. Use $autocmdnames{$i} ".
2111 "instead and set according USE_AUTOTOOLS=<tool> macro");
2112 }
2113 }
2114 }
2115
2116 if ($makevar{'USE_AUTOTOOLS'} =~ /\blibtool\b/) {
2117 &perror("WARN", $file, -1, "USE_AUTOTOOLS=libtool is deprecated. ".
2118 "Use USES=libtool instead.");
2119 }
2120
2121 #
2122 # whole file: check for use of paths that have macro replacements
2123 #
2124 my %pathnames = ();
2125 print "OK: checking for paths that have macro replacements.\n"
2126 if ($verbose);
2127 $pathnames{'$\{PREFIX\}/share/java/classes'} = 'JAVADIR';
2128 $pathnames{'$\{PREFIX\}/share/java'} = 'JAVASHAREDIR';
2129 foreach my $i (keys %pathnames) {
2130 my $lineno = &linenumber($`);
2131 if ($j =~ m|$i|gm) {
2132 &perror("FATAL", $file, $lineno, "you should use ".
2133 "$pathnames{$i} rather than $i");
2134 }
2135 }
2136
2137 #
2138 # whole file: ${GZIP_CMD} -9 (or any other number)
2139 #
2140 print "OK: checking for compression arguments passed to \${GZIP_CMD}.\n"
2141 if ($verbose);
2142 if ($j =~ /\$\{GZIP_CMD}\s+-(\w+(\s+-)?)*(\d)/) {
2143 my $lineno = &linenumber($`);
2144 &perror("WARN", $file, $lineno, "possible use of \"\${GZIP_CMD} -$3\" ".
2145 "found. \${GZIP_CMD} includes \"-\${GZIP}\" which ".
2146 "sets the compression level.");
2147 }
2148
2149 #
2150 # whole file: ${CHMOD} used
2151 #
2152 print "OK: checking for \${CHMOD}.\n" if ($verbose);
2153 if ($j =~ /\n\s*\$\{CHMOD}/) {
2154 my $lineno = &linenumber($`);
2155 &perror("WARN", $file, $lineno, "possible use of \"\${CHMOD}\" ".
2156 "found. Use @(owner,group,mode) syntax or \@owner/\@group ".
2157 "operators in pkg-plist instead.");
2158 }
2159
2160 #
2161 # whole file: ${INSTALL} -o | -g used
2162 #
2163 print "OK: checking for \${INSTALL} -o | -g.\n" if ($verbose);
2164 if ($j =~ /\n\s*\$\{INSTALL}(.*-\b(o|g)\b.*)/) {
2165 my $lineno = &linenumber($`);
2166 &perror("WARN", $file, $lineno, "possible use of \"\${INSTALL} -o | -g\" ".
2167 "found. Use @(owner,group,mode) syntax or \@owner/\@group ".
2168 "operators in pkg-plist instead.");
2169 }
2170
2171 #
2172 # whole file: ${MKDIR} -p
2173 #
2174 print "OK: checking for \${MKDIR} -p.\n"
2175 if ($verbose);
2176 if ($j =~ /\$\{MKDIR}\s+-p/) {
2177 my $lineno = &linenumber($`);
2178 &perror("WARN", $file, $lineno, "possible use of \"\${MKDIR} -p\" ".
2179 "found. \${MKDIR} includes ".
2180 "\"-p\" by default.");
2181 }
2182
2183 #
2184 # check for use of ${FIND} ... ${XARGS} ${RM}
2185 #
2186 print "OK: checking for instances of \${FIND} ... \${XARGS} \${RM}.\n"
2187 if ($verbose);
2188 if ($j =~ /\$\{FIND\}.*\|.*\$\{XARGS\}.*\$\{RM\}/) {
2189 my $lineno = &linenumber($`);
2190 &perror("WARN", $file, $lineno, "possible use of ".
2191 "\"\${FIND} ... \${XARGS} \${RM}\" when ".
2192 "\"\${FIND} ... -delete\" will work.");
2193 }
2194
2195 #
2196 # whole file: ${MACHINE_ARCH}
2197 #
2198 print "OK: checking for instances of \${MACHINE_ARCH} being test.\n"
2199 if ($verbose);
2200 if ($j =~ /\$\{MACHINE_ARCH}\s*[!=]=/) {
2201 my $lineno = &linenumber($`);
2202 &perror("FATAL", $file, $lineno, "MACHINE_ARCH should never be tested ".
2203 "directly; use ARCH instead.");
2204 }
2205
2206 #
2207 # whole file: full path name
2208 #
2209 &abspathname($whole, $file);
2210
2211 #
2212 # whole file: SITE_PERL
2213 #
2214 print "OK: checking SITE_PERL.\n" if ($verbose);
2215 if ($whole =~ /\nSITE_PERL[?:]?=/) {
2216 my $lineno = &linenumber($`);
2217 &perror("FATAL", $file, $lineno, "use of SITE_PERL discouraged. ".
2218 "it is set in bsd.port.mk.");
2219 }
2220
2221 #
2222 # whole file: ${LOCALBASE}/lib/perl5/site_perl
2223 #
2224 if ($j =~ m'\$\{(?:LOCALBASE|PREFIX)}/lib/perl5/site_perl') {
2225 my $lineno = &linenumber($`);
2226 if ($1 !~ /PREFIX/) {
2227 &perror("WARN", $file, $lineno, "possible use of \"\${LOCALBASE}/lib/perl5/site_perl\" ".
2228 "found. use \"\${SITE_PERL}\" instead.");
2229 } else {
2230 &perror("WARN", $file, $lineno, "possible use of \"\${PREFIX}/lib/perl5/site_perl\" ".
2231 "found. use \"\${PREFIX}/\${SITE_PERL_REL}\" instead.");
2232 }
2233 }
2234
2235 #
2236 # whole file: check for misuse of STAGE with SITE_PERL and SITE_ARCH
2237 #
2238 if ($j =~ m'\$\{FAKE_DESTDIR\}\${SITE_PERL}') {
2239 my $lineno = &linenumber($`);
2240 &perror("WARN", $file, $lineno, "\${FAKE_DESTDIR}\${SITE_PERL} should be ".
2241 "replaced by \${FAKE_DESTDIR}\${PREFIX}/\${SITE_PERL_REL}.");
2242 }
2243
2244 if ($j =~ m'\$\{FAKE_DESTDIR}\$\{SITE_ARCH}') {
2245 my $lineno = &linenumber($`);
2246 &perror("WARN", $file, $lineno, "\${FAKE_DESTDIR}\${SITE_ARCH} should be ".
2247 "replaced by \${FAKE_DESTDIR}\${PREFIX}/\${SITE_ARCH_REL}.");
2248 }
2249
2250 #
2251 # whole file: USE_GNOME check
2252 #
2253 if ($whole =~ /^USE_GNOME[?:]?=\s*(.*)$/m) {
2254 if ($1 =~ /gnomehack/) {
2255 $use_gnome_hack = 1;
2256 }
2257 }
2258
2259 #
2260 # whole file: USE_KDE check
2261 #
2262 if ($whole =~ /^USE_KDE[?:]?=\s*(.*)$/m) {
2263 if ($makevar{USES} !~ /\bkde:[45]/) {
2264 my $lineno = &linenumber($`);
2265 &perror("WARN", $file, $lineno, "USE_KDE is defined without ".
2266 "defining USES=kde:[45]");
2267 }
2268 }
2269
2270 #
2271 # whole file: USES=pyqt:5
2272 #
2273 if ($makevar{USES} =~ /\bpyqt:5/ && $whole !~ /^USE_PYQT[?:]?=\s(.*)$/m) {
2274 &perror("WARN", $file, -1, "When USES=pyqt:5 is defined, you must also define ".
2275 "USE_PYQT=xxxx");
2276 }
2277
2278 #
2279 # whole file: USE_GCC checks
2280 #
2281 if ($whole =~ /^USE_GCC[?:]?=\s*([^\s#]*).*$/m) {
2282 my $lineno = &linenumber($`);
2283 my $gcc_val = $1;
2284 if ($gcc_val eq 'any' || $gcc_val eq 'yes') {
2285 # Just accept these two.
2286 } elsif ($gcc_val !~ /\+/) {
2287 &perror("WARN", $file, $lineno, "Setting a specific version for ".
2288 "USE_GCC should only be done as a last resort. Unless you ".
2289 "have confirmed this port does not build with later ".
2290 "versions of GCC, please use USE_GCC=$gcc_val+.");
2291 }
2292 }
2293
2294 #
2295 # whole file: USE_JAVA check
2296 #
2297 if ($whole =~ /^USE_JAVA[?:]?=\s*(.*)$/m) {
2298 $use_java = 1;
2299 }
2300
2301 #
2302 # whole file: USE_ANT check
2303 #
2304 if ($whole =~ /^USE_ANT[?:]?=\s*(.*)$/m) {
2305 $use_ant = 1;
2306 }
2307
2308 #
2309 # whole file: USE_JAVA not defined, but other Java components are requested
2310 #
2311 if (!$use_java && ($use_ant || $whole =~ /^JAVA_VERSION[?:]?=\s*(.*)$/m ||
2312 $whole =~ /^JAVA_OS[?:]?=\s*(.*)$/m ||
2313 $whole =~ /^JAVA_VENDOR[?:]?=\s*(.*)$/m ||
2314 $whole =~ /^JAVA_RUN[?:]?=\s*(.*)$/m ||
2315 $whole =~ /^JAVA_BUILD[?:]?=\s*(.*)$/m)) {
2316 &perror("FATAL", $file, -1, "the port uses Java features, but USE_JAVA ".
2317 "is not defined");
2318 }
2319
2320 #
2321 # whole file: check for USE_ANT and USES=gmake both defined
2322 #
2323 if ($use_ant && $makevar{USES} =~ /\bgmake\b/) {
2324 &perror("WARN", $file, -1, "a port shall not define both USE_ANT ".
2325 "and USES[+]=gmake");
2326 }
2327
2328 #
2329 # whole file: check for USE_APACHE=yes
2330 #
2331 if ($whole =~ /^USE_APACHE[?:]?=\s*(yes)$/m) {
2332 &perror("FATAL", $file, -1, "Use USE_APACHE=VERSION ".
2333 "(where version can be found in \${PORTSDIR}/Mk/bsd.apache.mk) ".
2334 "instead of yes");
2335 }
2336
2337 #
2338 # whole file: check for WITH_APACHE\d+
2339 #
2340 if ($whole =~ /WITH_APACHE\d+/) {
2341 &perror("FATAL", $file, -1, "Use WITH_APACHE=yes and .if ".
2342 "\${APACHE_VERSION} [==|<|>] 13|20|22|24");
2343 }
2344
2345 #
2346 # whole file: check for JAVA_BUILD and NO_BUILD
2347 #
2348 if ($whole =~ /^NO_BUILD[?:]?=\s*(.*)$/m &&
2349 $whole =~ /^JAVA_BUILD[?:]?=\s*(.*)$/m) {
2350 &perror("FATAL", $file, -1, "JAVA_BUILD and NO_BUILD cannot be set ".
2351 "at the same time");
2352 }
2353
2354 #
2355 # whole file: check for reassignment of ECHO_MSG
2356 #
2357 if ($whole =~ /^ECHO_MSG[?:]?=\s*(.*)$/m) {
2358 &perror("FATAL", $file, -1, "Re-assigning ECHO_MSG can break ".
2359 "``make readme''. Consider using \${PRINTF} directly instead ".
2360 "for custom message output.");
2361 }
2362
2363 #
2364 # whole file: check for --build, --mandir, and --infodir
2365 # when GNU_CONFIGURE
2366 #
2367 if ($makevar{GNU_CONFIGURE} ne '' &&
2368 $makevar{CONFIGURE_ARGS} =~ /--(build|(man|info)dir)/) {
2369 &perror("WARN", $file, -1, "--build, --mandir, and --infodir ".
2370 "are not needed in CONFIGURE_ARGS as they are already set in ".
2371 "bsd.port.mk.");
2372 }
2373
2374 #
2375 # whole file: check for redundant SHEBANG_LANGs
2376 #
2377 if ($whole =~ /^SHEBANG_LANG[?+]?=\s*(.*)$/m) {
2378 my $sh_lang = $1;
2379 my @shebang_langs = split(/\s+/, $makevar{SHEBANG_LANG} // '');
2380 my %sh_seen = ();
2381 foreach my $shebang_lang (@shebang_langs) {
2382 if ($sh_seen{$shebang_lang}) {
2383 $sh_seen{$shebang_lang}++;
2384 } else {
2385 $sh_seen{$shebang_lang} = 1;
2386 }
2387 if ($sh_seen{$shebang_lang} > 1 && $sh_lang =~ /\b$shebang_lang\b/) {
2388 &perror("WARN", $file, -1, "$shebang_lang is already included in ".
2389 "SHEBANG_LANG. You should remove this from $file.");
2390 }
2391 }
2392 }
2393
2394 #
2395 # whole file: CONFIGURE_ENV
2396 #
2397 if ($whole =~ /\nCONFIGURE_ENV[?:+]?=\s*([^\\\n]+(\\\n[^\\\n]+)*)/) {
2398 my $configure_env = $1;
2399 my $cflags = undef;
2400 my $cxxflags = undef;
2401 if ($configure_env =~ /\bCFLAGS="([^"]+)"/ ||
2402 $configure_env =~ /\bCFLAGS='([^']+)'/ ||
2403 $configure_env =~ /\bCFLAGS=(\S+)/) {
2404 $cflags = $1;
2405 }
2406 if ($configure_env =~ /\bCXXFLAGS="([^"]+)"/ ||
2407 $configure_env =~ /\bCXXFLAGS='([^']+)'/ ||
2408 $configure_env =~ /\bCXXFLAGS=(\S+)/) {
2409 $cxxflags = $1;
2410 }
2411
2412 if (defined($cflags) || defined($cxxflags)) {
2413 &perror("WARN", $file, -1, "CFLAGS/CXXFLAGS are not needed in ".
2414 "CONFIGURE_ENV as they are already added there in bsd.port.mk.");
2415 }
2416
2417 if ($makevar{GNU_CONFIGURE} ne '') {
2418 if ((defined($cflags) && $cflags =~ /-I/) ||
2419 (defined($cxxflags) && $cxxflags =~ /-I/)) {
2420 &perror("WARN", $file, -1, "Consider passing include paths ".
2421 "to configure via the CPPFLAGS macro ".
2422 "(i.e. CPPFLAGS+=-I...)");
2423 }
2424 }
2425
2426 if (defined($cflags) && $cflags !~ /\$\{CFLAGS/) {
2427 &perror("FATAL", $file, -1, "CFLAGS are clobbered in ".
2428 "CONFIGURE_ENV. Alter CFLAGS in the Makefile with ".
2429 "CFLAGS+=... instead");
2430 }
2431
2432 if (defined($cxxflags) && $cxxflags !~ /\$\{CXXFLAGS/) {
2433 &perror("FATAL", $file, -1, "CXXFLAGS are clobbered in ".
2434 "CONFIGURE_ENV. Alter CXXFLAGS in the Makefile with ".
2435 "CXXFLAGS+=... instead");
2436 }
2437
2438 if ($configure_env =~ /(FC)=/ ||
2439 $configure_env =~ /(F77)=/ ||
2440 $configure_env =~ /(FFLAGS)=/) {
2441 &perror("FATAL", $file, -1, "$1 is already ".
2442 "passed in CONFIGURE_ENV via bsd.gcc.mk. If you need to ".
2443 "override the default value, alter $1 in the Makefile ".
2444 "instead with $1=...");
2445 }
2446
2447 if ($configure_env =~ /(\bCPPFLAGS)=/) {
2448 &perror("FATAL", $file, -1, "$1 is already ".
2449 "passed in CONFIGURE_ENV via bsd.port.mk. If you need to ".
2450 "override the default value, alter $1 in the Makefile ".
2451 "instead with $1+=...");
2452 }
2453
2454 if ($configure_env =~ /(\bLDFLAGS)=/) {
2455 &perror("FATAL", $file, -1, "$1 is already passed in ".
2456 "CONFIGURE_ENV via bsd.port.mk. If you need to ".
2457 "override the default value, alter $1 in the Makefile ".
2458 "instead with $1+=...");
2459 }
2460 }
2461
2462 #
2463 # whole file: *FLAGS
2464 #
2465 foreach my $f (qw(CFLAGS CXXFLAGS CPPFLAGS LDFLAGS)) {
2466 if ($whole =~ /^$f=/m) {
2467 &perror("WARN", $file, -1, "$f is overridden in the Makefile ".
2468 "clobbering a value possibly set by a user. Consider ".
2469 "using $f+=... if you want to add or $f:=\${$f:C/...//} ".
2470 "if you want to remove specific flags");
2471 }
2472 }
2473
2474 #
2475 # whole file: MAKE_ENV
2476 #
2477 if ($whole =~ /\nMAKE_ENV[?:+]?=\s*([^\\\n]+(\\\n[^\\\n]+)*)/) {
2478 my $make_env = $1;
2479
2480 if ($make_env =~ /(CPPFLAGS)=/) {
2481 &perror("FATAL", $file, -1, "$1 is already ".
2482 "passed in MAKE_ENV via bsd.port.mk. If you need to ".
2483 "override the default value, alter $1 in the Makefile ".
2484 "instead with $1=...");
2485 }
2486 }
2487
2488 #
2489 # slave port check
2490 #
2491 if ($slaveport) {
2492 print "OK: slave port detected, checking for inclusion of $masterdir/Makefile.\n"
2493 if ($verbose);
2494 if ($whole =~ /^\.\s*include\s*[<"]bsd\.port(?:\.post)?\.mk[">]/m) {
2495 &perror("FATAL", $file, -1, "supposedly non-slave port with".
2496 " .CURDIR != MASTERDIR");
2497 } elsif ($whole =~ /^\.\s*include\s*[<"]bsd\.port\.pre\.mk[">]/m) {
2498 &perror("FATAL", $file, -1, "slave ports may not include".
2499 " bsd.port.pre.mk");
2500 }
2501 if ($whole !~ /\n\.include\s+"\$\{MASTERDIR\}\/Makefile"\s*$/s) {
2502 &perror("FATAL", $file, -1, "the last line of a slave port's Makefile has to be".
2503 ' .include "${MASTERDIR}/Makefile"');
2504 }
2505 print "OK: checking master port in $masterdir.\n" if ($verbose);
2506 if (! -e "$masterdir/Makefile") {
2507 &perror("WARN", "", -1, "unable to locate master port in $masterdir");
2508 }
2509 if ($whole !~ /^MASTERDIR=\s*\$\{\.CURDIR\}(?:\/\.\.){1,2}(?:\/[\w\@.+-]+){1,2}\s*$/m) {
2510 &perror("WARN", $file, -1, "slave ports must define MASTERDIR=".
2511 '${.CURDIR}/..(/../<category>)/<port>');
2512 }
2513 } else {
2514 #$slaveport = 0;
2515 print "OK: non-slave port detected, checking for anything after bsd.port(.post).mk.\n"
2516 if ($verbose);
2517 if ($whole !~ /\n\.include\s+<bsd\.port(?:\.post)?\.mk>\s*$/s) {
2518 &perror("FATAL", $file, -1, "the last line of Makefile has to be".
2519 ' .include <bsd.port(.post).mk>');
2520 }
2521 if ($whole =~ /^MASTERDIR\s*[+?:!]?\s*=/m) {
2522 &perror("WARN", $file, -1, "non-slave ports may not define MASTERDIR");
2523 }
2524 }
2525
2526 #
2527 # break the makefile into sections.
2528 #
2529 $tmp = $rawwhole;
2530 $tmp =~ s/\\\n/ /g;
2531 # keep comment, blank line, comment in the same section
2532 $tmp =~ s/(#.*\n)\n+(#.*)/$1$2/g;
2533 @sections = split(/\n\n+/, $tmp);
2534 for ($i = 0; $i <= $#sections; $i++) {
2535 if ($sections[$i] !~ /\n$/) {
2536 $sections[$i] .= "\n";
2537 }
2538 }
2539 $idx = 0;
2540
2541 #
2542 # section 1: comment lines.
2543 #
2544 print "OK: checking comment section of $file.\n" if ($verbose);
2545 my @linestocheck = split("\n", <<EOF);
2546 Whom
2547 Date [cC]reated
2548 EOF
2549
2550 $tmp = $sections[$idx++];
2551 $tmp = "\n" . $tmp; # to make the begin-of-line check easier
2552
2553 if ($tmp =~ /\n[^#]/) {
2554 &perror("FATAL", $file, -1, "non-comment line in comment section.");
2555 }
2556 if ($tmp =~ m/Version [rR]equired/) {
2557 &perror("WARN", $file, -1, "Version required is no longer needed in the comment section.");
2558 }
2559 my $tmp2 = "";
2560 for (split(/\n/, $tmp)) {
2561 $tmp2 .= $_ if (m/\$$rcsidstr/);
2562 }
2563 if ($tmp2 !~ /#(\s+)\$$rcsidstr([^\$]*)\$$/) {
2564
2565 &perror("FATAL", $file, -1, "no \$$rcsidstr\$ line in comment ".
2566 "section.");
2567 } else {
2568 print "OK: \$$rcsidstr\$ seen in $file.\n" if ($verbose);
2569 if ($1 ne ' ') {
2570 &perror("WARN", $file, -1, "please use single whitespace ".
2571 "right before \$$rcsidstr\$ tag.");
2572 }
2573 if ($2 ne '') {
2574 if ($verbose || $newport) { # XXX
2575 &perror("WARN", $file, -1,
2576 ($newport ? 'for new port, '
2577 : 'is it a new port? if so, ').
2578 "make \$$rcsidstr\$ tag in comment ".
2579 "section empty, to make SVN happy.");
2580 }
2581 }
2582 }
2583
2584 #
2585 # for the rest of the checks, comment lines are not important.
2586 #
2587 for ($i = 0; $i < scalar(@sections); $i++) {
2588 $sections[$i] = "\n" . $sections[$i];
2589 $sections[$i] =~ s/\n#[^\n]*//g;
2590 $sections[$i] =~ s/\n\n+/\n/g;
2591 $sections[$i] =~ s/^\n//;
2592 }
2593
2594 #
2595 # section 2: PORTNAME/PORTVERSION/...
2596 #
2597 print "OK: checking first section of $file (PORTNAME/...).\n"
2598 if ($verbose);
2599 $tmp = $sections[$idx++];
2600
2601 # check the order of items.
2602 &checkorder('PORTNAME', $tmp, $file, qw(
2603 PORTNAME PORTVERSION DISTVERSIONPREFIX DISTVERSION DISTVERSIONSUFFIX
2604 PORTREVISION PORTEPOCH CATEGORIES MASTER_SITES MASTER_SITE_SUBDIR
2605 PROJECTHOST PKGNAMEPREFIX PKGNAMESUFFIX DISTNAME EXTRACT_SUFX DISTFILES
2606 DIST_SUBDIR EXTRACT_ONLY
2607 ));
2608
2609 # check the items that has to be there.
2610 $tmp = "\n" . $tmp;
2611 print "OK: checking PORTNAME/PORTVERSION/DISTVERSION.\n" if ($verbose);
2612 if ($tmp !~ /\nPORTNAME(.)?=/) {
2613 &perror("FATAL", $file, -1, "PORTNAME has to be there.") unless ($slaveport && $makevar{PORTNAME} ne '');
2614 } elsif (defined $1 && $1 ne '') {
2615 &perror("WARN", $file, -1, "unless this is a master port, PORTNAME has to be set by \"=\", ".
2616 "not by \"$1=\".") unless ($masterport);
2617 }
2618 if ($tmp !~ /\n(PORTVERSION|DISTVERSION)(.)?=/) {
2619 &perror("FATAL", $file, -1, "PORTVERSION or DISTVERSION has to be there.") unless (($makevar{PORTVERSION} ne '' || $makevar{DISTVERSION} ne ''));
2620 if (!$slaveport && ($makevar{PORTVERSION} ne '' || $makevar{DISTVERSION} ne '')) {
2621 &perror("WARN", $file, -1, "PORTVERSION/DISTVERSION is set externally to this port's Makefile, but this port is not configured as a slave port.");
2622 }
2623 } elsif (defined $2 && $2 ne '') {
2624 &perror("WARN", $file, -1, "unless this is a master port, PORTVERSION has to be set by \"=\", ".
2625 "not by \"$2=\".") unless ($masterport);
2626 }
2627 if ($tmp =~ /\nPORTVERSION.?=/ && $tmp =~ /\nDISTVERSION.?=/) {
2628 &perror("FATAL", $file, -1, "either PORTVERSION or DISTVERSION must be ".
2629 "specified, not both.");
2630 }
2631 if ($newport) {
2632 print "OK: checking for existence of PORTREVISION in new port.\n"
2633 if ($verbose);
2634 if ($tmp =~ /^PORTREVISION(.)?=/m) {
2635 &perror("WARN", $file, -1, "new ports should not set PORTREVISION.");
2636 }
2637 } elsif (!$slaveport) {
2638 print "OK: checking for PORTREVISION=0.\n" if ($verbose);
2639 if ($tmp =~ /^PORTREVISION=\s*0/m) {
2640 &perror("WARN", $file, -1, "Setting PORTREVISION to 0 is not ".
2641 "necessary.");
2642 }
2643 }
2644 if ($newport) {
2645 print "OK: checking for existence of PORTEPOCH in new port.\n"
2646 if ($verbose);
2647 if ($tmp =~ /^PORTEPOCH(.)?=/m) {
2648 &perror("WARN", $file, -1, "new ports should not set PORTEPOCH.");
2649 }
2650 }
2651 print "OK: checking CATEGORIES.\n" if ($verbose);
2652 if ($tmp !~ /\nCATEGORIES(.)?=/) {
2653 &perror("FATAL", $file, -1, "CATEGORIES has to be there.") unless ($makevar{CATEGORIES} ne '');
2654 if (!$slaveport && $makevar{CATEGORIES} ne '') {
2655 &perror("WARN", $file, -1, "CATEGORIES is set externally to this port's Makefile, but this port is not configured as a slave port.");
2656 }
2657 } elsif (defined $1 && ($i = $1) ne '' && $i =~ /[^?+]/) {
2658 &perror("WARN", $file, -1, "unless this is a master port, CATEGORIES should be set by \"=\", \"?=\", or \"+=\", ".
2659 "not by \"$i=\".") unless ($masterport);
2660 }
2661
2662 @cat = split(/\s+/, $makevar{CATEGORIES});
2663 if (@cat == 0) {
2664 &perror("FATAL", $file, -1, "CATEGORIES left blank. set it to \"misc\"".
2665 " if nothing seems apropriate.");
2666 } else {
2667 my %seencat = ();
2668 foreach my $cat (@cat) {
2669 if ($seencat{$cat}) {
2670 &perror("WARN", $file, -1, "Duplicate category, $cat specified".
2671 " in CATEGORIES.");
2672 } else {
2673 $seencat{$cat} = 1;
2674 }
2675 }
2676 }
2677
2678 if ($use_java && !grep /^java$/, @cat) {
2679 &perror("WARN", $file, -1, "the port uses Java but is not part of the ".
2680 "``java'' category");
2681 }
2682
2683 if (scalar(@cat) == 1 && $cat[0] eq "java") {
2684 &perror("FATAL", $file, -1, "the ``java'' category shall not be the only ".
2685 "one for a port");
2686 }
2687
2688 if ($newport && scalar(@cat) > 0 && $cat[0] eq "java") {
2689 &perror("WARN", $file, -1, "save for ports directly related to the Java ".
2690 "language, porters are encouraged not to use ``java'' as ".
2691 "the main category for a port");
2692 }
2693
2694 if ($committer && $makevar{'.CURDIR'} =~ m/\Q${portsdir}\E\/([^\/]+)\/[^\/]+\/?$/) {
2695 if ($cat[0] ne $1 && $makevar{PKGCATEGORY} ne $1 ) {
2696 &perror("FATAL", $file, -1, "category \"$1\" must be listed first");
2697 }
2698 }
2699
2700 #MICHAEL: can these three lang cat checks be combined?
2701 # skip the first category specification if it's a language specific one.
2702 if (grep($_ eq $cat[0], @lang_cat)) {
2703 $has_lang_cat = 1;
2704 $port_lang = $lang_pref{$cat[0]};
2705 shift @cat;
2706 }
2707
2708 # skip further if more language specific ones follow.
2709 if (@cat && grep($_ eq $cat[0], @lang_cat)) {
2710 &perror("WARN", $file, -1, "multiple language specific categories detected. ".
2711 "are you sure?");
2712 do {
2713 shift @cat;
2714 } while (@cat && grep($_ eq $cat[0], @lang_cat));
2715 }
2716
2717 # check x11 in CATEGORIES
2718 #MICHAEL: I don't understand this line
2719 if (2 <= @cat && $cat[1] eq "x11") {
2720 &perror("WARN", $file, -1, "only specific kind of apps should ".
2721 "specify \"x11\" in CATEGORIES. ".
2722 "Do you mean just USE_XORG? ".
2723 "Then remove \"x11\" from CATEGORIES.");
2724 }
2725
2726 if (2 <= @cat) {
2727 # skip the first one that we know is _not_ language specific.
2728 shift @cat;
2729
2730 # any language specific one after non language specific ones?
2731 foreach my $cat (@cat) {
2732 if (grep($_ eq $cat, @lang_cat)) {
2733 $has_lang_cat = 1;
2734 $port_lang = $lang_pref{$cat};
2735 &perror("WARN", $file, -1, "when you specify multiple categories, ".
2736 "language specific category should come first.");
2737 }
2738 }
2739 }
2740
2741 # check the URL
2742 if (($tmp =~ /\nMASTER_SITES[+?]?=[ \t]*([^\n]*)\n/
2743 && $1 !~ /^[ \t]*$/) || ($makevar{MASTER_SITES} ne '')) {
2744 print "OK: seen MASTER_SITES, sanity checking URLs.\n"
2745 if ($verbose);
2746 my $urlseen = 0;
2747 my @sites = split(/\s+/, $1 // '');
2748 my $ftphttp = 0;
2749 foreach my $i (@sites) {
2750 last if ($i =~ /^#/);
2751 if ($i =~ m#^\w+://#) {
2752 $urlseen = 1;
2753 $ftphttp = 1 if ($i =~ /^(ftp|http):/);
2754 &urlcheck($i, $file);
2755 unless (&is_predefined($i, $file)) {
2756 print "OK: URL \"$i\" ok.\n"
2757 if ($verbose);
2758 }
2759 } else {
2760 my $good_ms = 1;
2761 foreach my $mss (split(/\s+/, $makevar{MASTER_SITES_SUBDIRS})) {
2762 my ($ms, $sd) = split(/:/, $mss);
2763 if ($i =~ /^$ms/ && $i ne $ms) {
2764 my $ip = $i;
2765 $ip =~ s/^$ms\///;
2766 my $exp_sd = get_makevar($ip);
2767 if ($exp_sd eq $sd) {
2768 &perror("WARN", $file, -1, "typically when you specify magic site $ms ".
2769 "you do not need anything else as $sd is assumed");
2770 $good_ms = 0;
2771 }
2772 }
2773 }
2774 if ($good_ms) {
2775 print "OK: non-URL \"$i\" ok.\n"
2776 if ($verbose);
2777 }
2778 # Assume variables contain an ftp/http site.
2779 $ftphttp = 1;
2780 }
2781 }
2782 } else {
2783 &perror("WARN", $file, -1, "no MASTER_SITES found. is it ok?");
2784 }
2785
2786 # check DISTFILES and related items.
2787 $distfiles = $1 if ($tmp =~ /\nDISTFILES[+?]?=[ \t]*([^\n]+)\n/);
2788 $portname = $makevar{PORTNAME};
2789 $portversion = $makevar{PORTVERSION};
2790 $distversionprefix = $makevar{DISTVERSIONPREFIX};
2791 $distversion = $makevar{DISTVERSION};
2792 $distversionsuffix = $makevar{DISTVERSIONSUFFIX};
2793 $distname = $1 if ($tmp =~ /\nDISTNAME[+?]?=[ \t]*([^\n]+)\n/);
2794 $extractsufx = $1 if ($tmp =~ /\nEXTRACT_SUFX[+?]?=[ \t]*([^\n]+)\n/);
2795
2796 # check bogus EXTRACT_SUFX.
2797 if ($extractsufx ne '') {
2798 print "OK: seen EXTRACT_SUFX, checking value.\n" if ($verbose);
2799 if ($distfiles ne '') {
2800 &perror("WARN", $file, -1, "no need to define EXTRACT_SUFX if ".
2801 "DISTFILES is defined.");
2802 }
2803 if ($extractsufx eq '.tar.gz') {
2804 &perror("WARN", $file, -1, "EXTRACT_SUFX is \".tar.gz.\" ".
2805 "by default. you don't need to specify it.");
2806 }
2807 if ($extractsufx =~ /^\.tar\.(bz2|lzma|xz|Z)$/) {
2808 my $ext = $1;
2809 $ext = 'bzip2' if ($ext eq 'bz2');
2810 &perror("WARN", $file, -1, "EXTRACT_SUFX is \".tar.$ext\". ".
2811 "Please use USES=tar:$ext instead.");
2812 }
2813 if ($extractsufx =~ /^\.(tgz|tbz|txz)$/) {
2814 &perror("WARN", $file, -1, "EXTRACT_SUFX is \".$1\". ".
2815 "Please use USES=tar:$1 instead.");
2816 }
2817 if ($extractsufx eq '.zip') {
2818 &perror("WARN", $file, -1, "EXTRACT_SUFX is \".zip\" ".
2819 "You should use USES[+]=zip instead.");
2820 }
2821 } else {
2822 print "OK: no EXTRACT_SUFX seen, using default value.\n"
2823 if ($verbose);
2824 $extractsufx = '.tar.gz';
2825 }
2826
2827 print "OK: sanity checking PORTNAME/PORTVERSION/DISTVERSIONPREFIX/DISTVERSION/DISTVERSIONSUFFIX.\n" if ($verbose);
2828 if ($distname ne '') {
2829 my $exp_distname = $makevar{DISTNAME};
2830 if ($exp_distname eq "$portname-$portversion") {
2831 &perror("WARN", $file, -1, "DISTNAME is \${PORTNAME}-\${PORTVERSION} by ".
2832 "default, you don't need to define DISTNAME.");
2833 } else {
2834 if ($exp_distname eq "$portname-$distversionprefix$distversion$distversionsuffix") {
2835 &perror("WARN", $file, -1, "DISTNAME is \${PORTNAME}-\${DISTVERSIONPREFIX}\${DISTVERSION}\${DISTVERSIONSUFFIX} by ".
2836 "default, you don't need to define DISTNAME.");
2837 }
2838 }
2839 if ($distname =~ /PORTREVISION/) {
2840 &perror("FATAL", $file, -1, "DISTNAME contains a reference to ".
2841 "PORTREVISION. You should only be using PORTVERSION");
2842 }
2843 if ($distname =~ /PORTEPOCH/) {
2844 &perror("FATAL", $file, -1, "DISTNAME contains a reference to ".
2845 "PORTEPOCH. You should only be using PORTVERSION");
2846 }
2847 }
2848 if ($portname =~ /^$re_lang_short/) {
2849 &perror("FATAL", $file, -1, "language prefix is automatically".
2850 " set by PKGNAMEPREFIX.".
2851 " you must remove it from PORTNAME.");
2852 }
2853 if ($portname =~ /([|<>=! ])/) {
2854 &perror("FATAL", $file, -1, "PORTNAME contains the illegal character \"$1\".".
2855 " You should modify \"$portname\".");
2856 } elsif ($portname =~ /\$[\{\(].+[\}\)]/) {
2857 &perror("WARN", $file, -1, "using variable in PORTNAME.".
2858 " consider using PKGNAMEPREFIX and/or PKGNAMESUFFIX.");
2859 } elsif ($portname =~ /([^\w._@+-])/) {
2860 &perror("WARN", $file, -1, "using \"$1\" in PORTNAME.".
2861 " You should modify \"$portname\".");
2862 } elsif ($portname =~ /-/ && $distname ne '') {
2863 &perror("WARN", $file, -1, "using hyphen in PORTNAME.".
2864 " consider using PKGNAMEPREFIX and/or PKGNAMESUFFIX.");
2865 }
2866 if ($portversion eq '' && $distversion eq '') {
2867 &perror("FATAL", $file, -1, "either PORTVERSION or DISTVERSION must be specified");
2868 }
2869 if ($portversion =~ /^pl[0-9]*$/
2870 || $portversion =~ /^[0-9]*[A-Za-z]?[0-9]*(\.[0-9]*[A-Za-z]?[0-9+]*)*$/) {
2871 print "OK: PORTVERSION \"$portversion\" looks fine.\n" if ($verbose);
2872 } elsif ($portversion =~ /^[^\-]*\$[{\(].+[\)}][^\-]*$/) {
2873 &perror("WARN", $file, -1, "using variable, \"$portversion\", as version ".
2874 "number");
2875 } elsif ($portversion =~ /([-,_<>=! #*])/) {
2876 &perror("FATAL", $file, -1, "PORTVERSION must not contain \"$1\". ".
2877 "You should modify \"$portversion\".");
2878 } else {
2879 &perror("FATAL", $file, -1, "PORTVERSION looks illegal. ".
2880 "You should modify \"$portversion\".");
2881
2882 }
2883
2884 $pkg_version = $makevar{PKG_VERSION};
2885
2886 if ($makevar{CONFLICTS}) {
2887 print "OK: checking CONFLICTS.\n" if ($verbose);
2888 foreach my $conflict (split ' ', $makevar{CONFLICTS}) {
2889 `$pkg_version -T '$makevar{PKGNAME}' '$conflict'`;
2890 my $selfconflict = !$?;
2891 if ($selfconflict) {
2892 &perror("FATAL", "", -1, "Package conflicts with itself. ".
2893 "You should remove \"$conflict\" from CONFLICTS.");
2894 }
2895 }
2896 }
2897
2898 $versiondir = $ENV{VERSIONDIR} // '/var/db/chkversion';
2899
2900 $versionfile = "$versiondir/VERSIONS";
2901 $useindex = !-r "$versionfile";
2902
2903 $versionfile = "$portsdir/$makevar{INDEXFILE}"
2904 if $useindex;
2905
2906 if (-r "$versionfile") {
2907 print "OK: checking if PORTVERSION is going backwards.\n" if ($verbose);
2908 open VERSIONS, "<$versionfile";
2909
2910 while (<VERSIONS>) {
2911 my($origin, $version) = ('', '');
2912 chomp;
2913 next if /^(#|$)/;
2914 if ($useindex) {
2915 ($version, $origin) = split /\|/;
2916 $origin =~ s,^.*/([^/]+/[^/]+)/?$,$1,;
2917 } else {
2918 ($origin, $version) = split;
2919 }
2920 if ($origin eq $makevar{PKGORIGIN}) {
2921 my $newversion = $makevar{PKGNAME};
2922 my $oldversion = $version;
2923 my $result = '';
2924
2925 $newversion =~ s/^.*-//;
2926 $oldversion =~ s/^.*-//;
2927
2928 $result = `$pkg_version -t '$newversion' '$oldversion'`;
2929 chomp $result;
2930 if ($result eq '<') {
2931 &perror("FATAL", $file, -1, "$makevar{PKGNAME} < $version. ".
2932 "Choose another PORTVERSION or bump PORTEPOCH.");
2933 # $backwards{$origin} = "$pkgname{$origin} < $version";
2934 }
2935 last;
2936 }
2937 }
2938 close VERSIONS;
2939 }
2940
2941 # if DISTFILES have only single item, it is better to avoid DISTFILES
2942 # and to use combination of DISTNAME and EXTRACT_SUFX.
2943 # example:
2944 # DISTFILES=package-1.0.tgz
2945 # should be
2946 # DISTNAME= package-1.0
2947 # EXTRACT_SUFX= .tgz
2948 if ($distfiles =~ /^\S+$/ && $distfiles !~ /:[^\/:]+$/) {
2949 $bogusdistfiles++;
2950 print "OK: seen DISTFILES with single item, checking value.\n"
2951 if ($verbose);
2952 &perror("WARN", $file, -1, "use of DISTFILES with single file ".
2953 "discouraged. distribution filename should be set by ".
2954 "DISTNAME and EXTRACT_SUFX.");
2955 if ($distfiles eq (($distname ne '') ? $distname : "$portname-$portversion") . $extractsufx) {
2956 &perror("WARN", $file, -1, "definition of DISTFILES not necessary. ".
2957 "DISTFILES is \${DISTNAME}/\${EXTRACT_SUFX} ".
2958 "by default.");
2959 }
2960
2961 # display advice only in certain cases.
2962 #MICHAEL: will this work with multiple distfiles in this list? what about
2963 # doing the same sort of thing for DISTNAME, is it needed?
2964 if ($distfiles =~ /^\Q$i\E([\-.].+)$/) {
2965 &perror("WARN", $file, -1, "how about \"EXTRACT_SUFX=$1\"".
2966 ", instead of DISTFILES?");
2967 }
2968 }
2969
2970 push(@varnames, qw(
2971 PORTNAME PORTVERSION DISTVERSIONPREFIX DISTVERSION DISTVERSIONSUFFIX
2972 PORTREVISION PORTEPOCH CATEGORIES MASTER_SITES MASTER_SITE_SUBDIR
2973 PROJECTHOST PKGNAMEPREFIX PKGNAMESUFFIX DISTNAME EXTRACT_SUFX DISTFILES
2974 DIST_SUBDIR EXTRACT_ONLY
2975 ));
2976
2977 #
2978 # section 3: PATCH_SITES/PATCHFILES(optional)
2979 #
2980 print "OK: checking second section of $file (PATCH*: optional).\n"
2981 if ($verbose);
2982 $tmp = $sections[$idx] // '';
2983
2984 if ($tmp =~ /(PATCH_SITES|PATCH_SITE_SUBDIR|PATCHFILES|PATCH_DIST_STRIP)/) {
2985 &checkearlier($file, $tmp, @varnames);
2986
2987 if ($tmp =~ /PATCH_SITES[?+]?=[^\n]+\n/) {
2988 print "OK: seen PATCH_SITES.\n" if ($verbose);
2989 $tmp =~ s/PATCH_SITES[?+]?=[^\n]+\n//;
2990 }
2991 if ($tmp =~ /PATCH_SITE_SUBDIR[?+]?=[^\n]+\n/) {
2992 print "OK: seen PATCH_SITE_SUBDIR.\n" if ($verbose);
2993 $tmp =~ s/PATCH_SITE_SUBDIR[?+]?=[^\n]+\n//;
2994 }
2995 if ($tmp =~ /PATCHFILES[?+]?=[^\n]+\n/) {
2996 print "OK: seen PATCHFILES.\n" if ($verbose);
2997 $tmp =~ s/PATCHFILES[?+]?=[^\n]+\n//;
2998 }
2999 if ($tmp =~ /PATCH_DIST_STRIP[?+]?=[^\n]+\n/) {
3000 print "OK: seen PATCH_DIST_STRIP.\n" if ($verbose);
3001 $tmp =~ s/PATCH_DIST_STRIP[?+]?=[^\n]+\n//;
3002 }
3003
3004 &checkextra($tmp, 'PATCH_SITES', $file);
3005
3006 $idx++;
3007 }
3008
3009 push(@varnames, qw(
3010 PATCH_SITES PATCHFILES PATCH_DIST_STRIP
3011 ));
3012
3013 #
3014 # section 4: MAINTAINER
3015 #
3016 print "OK: checking third section of $file (MAINTAINER).\n"
3017 if ($verbose);
3018 $tmp = $sections[$idx] // '';
3019
3020 &checkearlier($file, $tmp, @varnames);
3021 &checkorder('MAINTAINER', $tmp, $file, qw(
3022 MAINTAINER COMMENT
3023 ));
3024
3025 $tmp = "\n" . $tmp;
3026 if ($tmp =~ /\nMAINTAINER(\?)?=([^\n]+)/) {
3027 my $addr = $2;
3028 if (defined $1 && $1 ne '') {
3029 &perror("WARN", $file, -1, "unless this is a master port, ".
3030 "MAINTAINER has to be set by \"=\", ".
3031 "not by \"$1=\".") unless ($masterport);
3032 }
3033 $addr =~ s/^\s*//;
3034 $addr =~ s/\s*$//;
3035 if ($addr =~ /[\s,<>()]/) {
3036 &perror("FATAL", $file, -1, "MAINTAINER should be a single address without comment.");
3037 }
3038 if ($addr !~ /^[^\@]+\@[\w\d\-\.]+$/) {
3039 &perror("FATAL", $file, -1, "MAINTAINER address, $addr, does not appear to be a valid email address.");
3040 }
3041 if ($newport && $addr =~ /ports\@freebsd.org/i) {
3042 &perror("WARN", $file, -1, "new ports should not be maintained by ".
3043 "ports\@FreeBSD.org.");
3044 }
3045 $tmp =~ s/\nMAINTAINER\??=[^\n]+//;
3046 } elsif ($whole !~ /\nMAINTAINER[?]?=/) {
3047 &perror("FATAL", $file, -1, "no MAINTAINER listed.") unless ($makevar{MAINTAINER} ne '');
3048 if (!$slaveport && $makevar{MAINTAINER} ne '') {
3049 &perror("WARN", $file, -1, "MAINTAINER is set externally to this port's Makefile, but this port is not configured as a slave port.");
3050 }
3051 }
3052 $tmp =~ s/\n\n+/\n/g;
3053
3054 # check COMMENT
3055 if ($tmp !~ /\nCOMMENT(.)?=/) {
3056 &perror("FATAL", $file, -1, "COMMENT has to be there.") unless ($makevar{COMMENT} ne '');
3057 if (!$slaveport && $makevar{COMMENT} ne '') {
3058 &perror("WARN", $file, -1, "COMMENT is set externally to this port's Makefile, but this port is not configured as a slave port.");
3059 }
3060 } elsif (defined $1 && $1 ne '') {
3061 &perror("WARN", $file, -1, "unless this is a master port, COMMENT has to be set by \"=\", ".
3062 "not by \"$1=\".") unless ($masterport);
3063 } else { # check for correctness
3064 if (($makevar{COMMENT} !~ /^["\[0-9A-Z]/) || ($makevar{COMMENT} =~ m/\.$/)) { #"
3065 &perror("WARN", $file, -1, "COMMENT should begin with a capital, and end without a period");
3066 }
3067 if (length($makevar{COMMENT}) > 70) {
3068 &perror("WARN", $file, -1, "COMMENT exceeds 70 characters limit.");
3069 }
3070 }
3071
3072 $idx++;
3073
3074 push(@varnames, qw(
3075 MAINTAINER COMMENT
3076 ));
3077
3078 #
3079 # section 5: LICENSE
3080 #
3081 print "OK: checking fourth section of $file (LICENSE).\n"
3082 if ($verbose);
3083 $tmp = $sections[$idx] // '';
3084
3085 if ($makevar{LICENSE}) {
3086 &checkorder('LICENSE', $tmp, $file, qw(
3087 LICENSE LICENSE_COMB LICENSE_GROUPS(_\w+)? LICENSE_NAME(_\w+)?
3088 LICENSE_TEXT(_\w+)? LICENSE_FILE(_\w+)? LICENSE_PERMS(_\w+)?
3089 LICENSE_DISTFILES(_\w+)?
3090 ));
3091
3092 # check LICENSE
3093 if ($makevar{LICENSE} && $makevar{LICENSE} ne '') {
3094 my $comb = $makevar{LICENSE_COMB} // 'single';
3095
3096 my @tokens = split(/ /, $makevar{LICENSE});
3097 if ($comb eq 'single' && scalar(@tokens) > 1) {
3098 &perror("FATAL", $file, -1, "LICENSE contains multiple licenses but LICENSE_COMB is not set to 'dual' or 'multi'");
3099 }
3100 }
3101
3102 # check value of LICENSE_COMB
3103 if ($makevar{LICENSE_COMB} && $makevar{LICENSE_COMB} !~ /^(single|dual|multi$)/) {
3104 &perror("FATAL", $file, -1, "LICENSE_COMB contains invalid value '$1' - must be one of 'single', 'dual', 'multi'");
3105 }
3106
3107 $idx++;
3108
3109 push(@varnames, qw(
3110 LICENSE LICENSE_COMB LICENSE_GROUPS LICENSE_NAME
3111 LICENSE_TEXT LICENSE_FILE LICENSE_PERMS
3112 ));
3113 } else {
3114 &perror("WARN", $file, -1, "Consider defining LICENSE.");
3115 }
3116
3117 #
3118 # section 6: BROKEN/IGNORE/DEPRECATED (may not be there)
3119 #
3120 print "OK: checking sixth section of $file (BROKEN/IGNORE/DEPRECATED).\n"
3121 if ($verbose);
3122 $tmp = $sections[$idx] // '';
3123
3124 @linestocheck = qw(
3125 DEPRECATED EXPIRATION_DATE FORBIDDEN BROKEN(_\w+)? IGNORE(_\w+)?
3126 ONLY_FOR_ARCHS ONLY_FOR_ARCHS_REASON(_\w+)?
3127 NOT_FOR_ARCHS NOT_FOR_ARCHS_REASON(_\w+)?
3128 );
3129
3130 my $brokenpattern = "^(" . join("|", @linestocheck) . ")[?+:]?=";
3131
3132 if ($tmp =~ /$brokenpattern/) {
3133 $idx++;
3134 }
3135
3136 foreach my $i (@linestocheck) {
3137 $tmp =~ s/$i[?+:]?=[^\n]+\n//g;
3138 }
3139
3140 push(@varnames, @linestocheck);
3141 &checkearlier($file, $tmp, @varnames);
3142
3143 #
3144 # section 7: *_DEPENDS (may not be there)
3145 #
3146 print "OK: checking seventh section of $file (*_DEPENDS).\n"
3147 if ($verbose);
3148 $tmp = $sections[$idx] // '';
3149
3150 # Check for direct assignment of BUILD_DEPENDS to RUN_DEPENDS.
3151 if ($tmp =~ /\nRUN_DEPENDS=[ \t]*\$\{BUILD_DEPENDS}/) {
3152 &perror("FATAL", $file, -1, "RUN_DEPENDS should not be set to ".
3153 "\${BUILD_DEPENDS} as \${BUILD_DEPENDS} includes other ".
3154 "implicit dependencies. Instead, copy the explicit dependencies ".
3155 "from BUILD_DEPENDS to RUN_DEPENDS. See ".
3156 "http://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/makefile-depend.html#AEN2154 ".
3157 "for more details.");
3158 }
3159
3160 @linestocheck = qw(
3161 EXTRACT_DEPENDS LIB_DEPENDS PATCH_DEPENDS BUILD_DEPENDS RUN_DEPENDS
3162 TEST_DEPENDS FETCH_DEPENDS DEPENDS_TARGET
3163 );
3164
3165 if ($tmp =~ /^(PATCH_|EXTRACT_|LIB_|BUILD_|RUN_|TEST_|FETCH_)DEPENDS/m) {
3166 &checkearlier($file, $tmp, @varnames);
3167
3168 check_depends_syntax($tmp, $file);
3169
3170 foreach my $i (@linestocheck) {
3171 foreach my $flavor (split(/\s+/, $makevar{FLAVORS} // '')) {
3172 $tmp =~ s/${flavor}_$i[?+:]?=[^\n]+\n//g;
3173 }
3174 $tmp =~ s/$i[?+:]?=[^\n]+\n//g;
3175 }
3176
3177 # Remove any other *_DEPENDS lines as people may
3178 # use a macro for common depends as described in
3179 # section 5.9.2 of the Porter's Handbook.
3180 $tmp =~ s/.+_DEPENDS[?+:]?=[^\n]+\n//g;
3181
3182 &checkextra($tmp, '*_DEPENDS', $file);
3183
3184 $idx++;
3185 }
3186
3187 push(@varnames, @linestocheck);
3188 &checkearlier($file, $tmp, @varnames);
3189
3190 #
3191 # Makefile 7: check the rest of file
3192 #
3193 print "OK: checking the rest of the $file.\n" if ($verbose);
3194 $tmp = join("\n\n", @sections[$idx .. scalar(@sections)-1]);
3195
3196 $tmp = "\n" . $tmp; # to make the begin-of-line check easier
3197
3198 &checkearlier($file, $tmp, @varnames);
3199
3200 # Check depends that might be specified based on the WITH_/WITHOUT_
3201 # arguments and other external variables.
3202 check_depends_syntax($tmp, $file);
3203
3204 # check WRKSRC/NO_WRKSUBDIR
3205 #
3206 # do not use DISTFILES/DISTNAME to control over WRKSRC.
3207 # DISTNAME is for controlling distribution filename.
3208 # example:
3209 # DISTNAME= package
3210 # DISTFILES=package-1.0.tgz
3211 # should be
3212 # DISTNAME= package-1.0
3213 # EXTRACT_SUFX=.tgz
3214 # WRKSRC= ${WRKDIR}/package
3215 #
3216 print "OK: checking WRKSRC.\n" if ($verbose);
3217 $wrksrc = $nowrksubdir = '';
3218 $wrksrc = $1 if ($tmp =~ /\nWRKSRC[+?]?=[ \t]*([^\n]*)\n/);
3219 $nowrksubdir = $1 if ($tmp =~ /\nNO_WRKSUBDIR[+?]?=[ \t]*([^\n]*)\n/);
3220 if ($nowrksubdir eq '') {
3221 $realwrksrc = $wrksrc ? "$wrksrc/$distname"
3222 : "\${WRKDIR}/$distname";
3223 } else {
3224 $realwrksrc = $wrksrc ? $wrksrc : '${WRKDIR}';
3225 }
3226 print "OK: WRKSRC seems to be $realwrksrc.\n" if ($verbose);
3227
3228 if ($nowrksubdir eq '') {
3229 print "OK: no NO_WRKSUBDIR, checking value of WRKSRC.\n"
3230 if ($verbose);
3231 if ($wrksrc eq 'work' || $wrksrc =~ /^$[\{\(]WRKDIR[\}\)]/) {
3232 &perror("WARN", $file, -1, "WRKSRC is set to meaningless value ".
3233 "\"$1\".".
3234 ($nowrksubdir eq ''
3235 ? " use \"NO_WRKSUBDIR=yes\" instead."
3236 : ""));
3237 }
3238 if ($bogusdistfiles) {
3239 if ($distname ne '' && $wrksrc eq '') {
3240 &perror("WARN", $file, -1, "do not use DISTFILES and DISTNAME ".
3241 "to control WRKSRC. how about ".
3242 "\"WRKSRC=\${WRKDIR}/$distname\"?");
3243 } else {
3244 &perror("WARN", $file, -1, "DISTFILES/DISTNAME affects WRKSRC. ".
3245 "take caution when changing them.");
3246 }
3247 }
3248 } else {
3249 print "OK: seen NO_WRKSUBDIR, checking value of WRKSRC.\n"
3250 if ($verbose);
3251 if ($wrksrc eq 'work' || $wrksrc =~ /^$[\{\(]WRKDIR[\}\)]/) {
3252 &perror("WARN", $file, -1, "definition of WRKSRC not necessary. ".
3253 "WRKSRC is \${WRKDIR} by default.");
3254 }
3255 }
3256
3257 # check RESTRICTED/NO_CDROM/NO_PACKAGE
3258 print "OK: checking RESTRICTED/NO_CDROM/NO_PACKAGE.\n" if ($verbose);
3259 if ($committer && $tmp =~ /\n(RESTRICTED|NO_CDROM|NO_PACKAGE)[+?]?=/) {
3260 &perror("WARN", $file, -1, "\"$1\" found. do not forget to update ".
3261 "ports/LEGAL.");
3262 }
3263
3264 # check NO_STAGE
3265 if ($makevar{NO_STAGE}) {
3266 &perror("FATAL", $file, -1, "STAGE support is missing.");
3267 }
3268
3269 # various MAN'uals related checks
3270 if ($makevar{USE_PERL5} =~ /\b(configure|modbuild|modbuildtiny)\b/
3271 && $tmp =~ /\nMAN3PREFIX=\s*\$\{PREFIX}\/lib\/perl5\/\$\{PERL_VER/) {
3272 &perror("WARN", $file, -1, "MAN3PREFIX is ".
3273 "\"\${PREFIX}/lib/perl5/\${PERL_VERSION}\" ".
3274 "when USE_PERL5=configure|modbuild|modbuildtiny is set. You do not need to specify it.");
3275 }
3276
3277 if ($tmp =~ /\nMAN[1-9LN][?]?=/) {
3278 &perror("FATAL", $file, -1, "MAN[1-9LN] macro is not supported anymore. ".
3279 "Please list manpages in plist.");
3280 }
3281
3282 # check INFO
3283 print "OK: checking INFO.\n" if ($verbose);
3284 if ($tmp =~ /\nINFO=\s*([^\n]*)\n/) {
3285 my @minfo = grep($_ !~ /^\s*$/, split(/\s+/, $1));
3286 if ($tmp =~ /[\/|\s]install-info\s/) {
3287 &perror("FATAL", $file, -1, "install-info is automatically run ".
3288 "when INFO is defined.");
3289 }
3290 foreach $i (@minfo) {
3291 if ($i =~ /\.info(-\d+)?$/) {
3292 &perror("FATAL", $file, -1, "do not include the .info extension ".
3293 "on files listed in the INFO macro.");
3294 }
3295 }
3296 } elsif ($tmp =~ /[\/|\s]install-info\s/) {
3297 &perror("WARN", $file, -1, "do not call install-info directly. Use the ".
3298 "INFO macro instead.");
3299 }
3300
3301 # check for HAS_CONFIGURE or GNU_CONFIGURE
3302 if ($tmp =~ /\nGNU_CONFIGURE[?+]?=/
3303 && $tmp =~ /\n(HAS_CONFIGURE)[?+]?=/) {
3304 &perror("WARN", $file, -1, "since you already have GNU_CONFIGURE, ".
3305 "you do not need $1.");
3306 }
3307
3308 # check direct use of important make targets.
3309 if ($tmp =~ /\n(fetch|extract|patch|configure|build|install):/) {
3310 &perror("FATAL", $file, -1, "direct redefinition of make target \"$1\" ".
3311 "discouraged. redefine \"do-$1\" instead.");
3312 }
3313
3314 # check for incorrect use of the pre-everything target.
3315 if ($tmp =~ /\npre-everything:[^:]/) {
3316 &perror("FATAL", $file, -1, "use pre-everything:: instead of pre-everything:");
3317 }
3318
3319 if ($tmp =~ /^pre-patch:/m && $use_gnome_hack) {
3320 &perror("FATAL", $file, -1, "pre-patch target overwrites gnomehack component. ".
3321 "use post-patch instead.");
3322 }
3323
3324 if ($tmp =~ /^do-build:/m && $use_ant) {
3325 &perror("WARN", $file, -1, "USE_ANT is intended only for ports that ".
3326 "build with Ant. It is recommended not to override the default ".
3327 "'do-build:' target when defining USE_ANT");
3328 }
3329
3330 #
3331 # check for deprecated use of USE_RC_SUBR, and current syntax
3332 #
3333 if ($tmp =~ /\nUSE_RC_SUBR=([\s]*)(.*)/) {
3334 my $subr_value = $makevar{USE_RC_SUBR};
3335 if ($subr_value eq '') {
3336 $subr_value = $2;
3337 }
3338
3339 if (($subr_value =~ /^yes$/i) ||
3340 ($subr_value =~ /^true$/i) ||
3341 ($subr_value =~ /^1$/)) {
3342 &perror("FATAL", $file, -1, "The value of the USE_RC_SUBR variable ".
3343 "should be the name of the intended rc.d script, and there ".
3344 "should be a corresponding file in the files/ directory.");
3345 } else {
3346 foreach my $i (split(/\s/, $subr_value)) {
3347 if ($i ne '' && -f "files/$i.in") {
3348 if (open(RCIN, "< files/$i.in")) {
3349 my @rccontents = <RCIN>;
3350 my $found_provide = 0;
3351 foreach my $line (@rccontents) {
3352 if ($line =~ /^# PROVIDE:/) {
3353 $found_provide = 1;
3354 last;
3355 }
3356 }
3357 if (!$found_provide) {
3358 &perror("FATAL", "files/$i.in", -1, "rc.d script ".
3359 "$i.in must contain a '# PROVIDE:' line in ".
3360 "order to be started at boot time.");
3361 }
3362
3363 close(RCIN);
3364 }
3365 }
3366 }
3367 }
3368 }
3369
3370 # check for health of SUB_FILES
3371
3372 if ($tmp =~ /\nSUB_FILES=([\s]*)(.*)/) {
3373 my $subr_value = $makevar{SUB_FILES};
3374 if ($subr_value eq '') {
3375 $subr_value = $2;
3376 }
3377 foreach my $i (split(/\s/, $subr_value)) {
3378 my $mvar;
3379 if ($i =~ /\$\{([^}]+)\}/) {
3380 $mvar = $1;
3381 if (defined($makevar{$mvar})) {
3382 $i = $makevar{$mvar};
3383 } else {
3384 $i = &get_makevar($mvar);
3385 }
3386 }
3387 if ($i ne '' && ! -f "files/$i.in") {
3388 &perror("FATAL", $file, -1, "$i listed in SUB_FILES/USE_RC_SUBR, ".
3389 "but files/$i.in is missing.");
3390 } elsif ($i eq '' && $mvar && $mvar ne '') {
3391 &perror("WARN", $file, -1, "possible undefined make variable ".
3392 "$mvar used as the value for SUB_FILES/USE_RC_SUBR.");
3393 }
3394 }
3395 }
3396
3397 1;
3398 }
3399
3400 sub perror($$$$) {
3401 my($type, $file, $line, $msg) = @_;
3402
3403 if ($type eq 'FATAL') {
3404 $err++;
3405 } else {
3406 $warn++;
3407 }
3408 if ($grouperrs) {
3409 $msg = '%%LINES%%' . $msg;
3410 if ($file ne "") {
3411 $msg = $file . ": " . $msg;
3412 }
3413 $msg = $type . ": " . $msg;
3414 if (!$errcache{$msg}) {
3415 push @errlst, $msg;
3416 }
3417 if ($line > -1) {
3418 push @{$errcache{$msg}}, $line;
3419 }
3420 } else {
3421 if ($line > -1) {
3422 $msg = "[$line]: " . $msg;
3423 }
3424 if ($file ne "") {
3425 $msg = $file . ": " . $msg;
3426 }
3427 $msg = $type . ": " . $msg;
3428 print $msg . "\n";
3429 }
3430 }
3431
3432 sub checkextra {
3433 my($str, $section, $file) = @_;
3434
3435 $str = "\n" . $str if ($str !~ /^\n/);
3436 $str =~ s/\n#[^\n]*/\n/g;
3437 $str =~ s/\n\.[^\n]+/\n/g;
3438 $str =~ s/\n\n+/\n/g;
3439 $str =~ s/^\s+//;
3440 $str =~ s/\s+$//;
3441 return if ($str eq '');
3442
3443 if ($str =~ /^([\w\d]+)/) {
3444 &perror("WARN", $file, -1, "extra item placed in the ".
3445 "$section section, ".
3446 "for example, \"$1\".");
3447 } else {
3448 &perror("WARN", $file, -1, "extra item placed in the ".
3449 "$section section.");
3450 }
3451 }
3452
3453 sub checkorder {
3454 my($section, $str, $file, @order) = @_;
3455 my(@items, $i, $j, $k, $invalidorder);
3456
3457 print "OK: checking the order of $section section.\n" if ($verbose);
3458 $str //= '';
3459
3460 @items = ();
3461 foreach my $i (split("\n", $str)) {
3462 $i =~ s/[+?]?=.*$//;
3463 push(@items, $i);
3464 }
3465
3466 @items = reverse(@items);
3467 $j = -1;
3468 $invalidorder = 0;
3469 while (scalar(@items)) {
3470 $i = pop(@items);
3471 $k = 0;
3472 while ($k < scalar(@order) && $order[$k] ne $i) {
3473 if (defined $order[$k] &&
3474 $order[$k] =~ /[\.\*\+\?\{\}\[\]\^\$\|]/ &&
3475 $i =~ /$order[$k]/) {
3476 last;
3477 }
3478 $k++;
3479 }
3480 if (defined $order[$k] && $order[$k] =~ /[\.\*\+\?\{\}\[\]\^\$\|]/ &&
3481 $i =~ /$order[$k]/) {
3482 if ($k < $j) {
3483 &perror("FATAL", $file, -1, "$i appears out-of-order.");
3484 $invalidorder++;
3485 } else {
3486 print "OK: seen $i, in order.\n" if ($verbose);
3487 }
3488 $j = $k;
3489 } elsif (defined $order[$k] && $order[$k] eq $i) {
3490 if ($k < $j) {
3491 &perror("FATAL", $file, -1, "$i appears out-of-order.");
3492 $invalidorder++;
3493 } else {
3494 print "OK: seen $i, in order.\n" if ($verbose);
3495 }
3496 $j = $k;
3497 # This if condition tests for .if, .else (in all forms),
3498 # .for and .endfor and .include
3499 } elsif ($i !~ m/^\.(if|el|endif|for|endfor|include)/) {
3500 &perror("FATAL", $file, -1, "extra item \"$i\" placed in the ".
3501 "$section section.");
3502 }
3503 }
3504 if ($invalidorder) {
3505 &perror("FATAL", $file, -1, "order must be " . join('/', @order) . '.');
3506 } else {
3507 print "OK: $section section is ordered properly.\n"
3508 if ($verbose);
3509 }
3510 }
3511
3512 sub checkearlier {
3513 my($file, $str, @varnames) = @_;
3514
3515 $str //= '';
3516
3517 print "OK: checking items that have to appear earlier.\n" if ($verbose);
3518 foreach my $i (@varnames) {
3519 if ($str =~ /\n($i)\??=/) {
3520 &perror("WARN", $file, -1, "\"$1\" has to appear earlier.");
3521 }
3522 }
3523 }
3524
3525 sub linenumber {
3526 my $text = shift;
3527 my @lines;
3528
3529 @lines = split /\n/, $text;
3530
3531 return scalar(@lines) - 1;
3532 }
3533
3534 sub abspathname {
3535 my($str, $file) = @_;
3536 my($s, $i, %cmdnames);
3537 my($pre);
3538
3539 # trim all trailing backslash and newline
3540 $str =~ s/\\\n\s*/ /g;
3541
3542 # ignore parameter string to reinplace command
3543 $str =~ s/([ \t][\@-]?(?:sed|\$[\{\(]SED[\}\)]|\$[\{\(]REINPLACE_CMD[\}\)]))((?:\s+\-\w+)*\s+(?:"(?:\\"|[^"\n])*"|'(?:\\'|[^'\n])*'))+(.*)/$1$3/g; #'
3544
3545 # ignore parameter string to echo command
3546 # XXX: This next pattern crashes Perl 5.8.7.
3547 #$str =~ s/[ \t][\@-]?(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+("(\\'|\\"|[^"])*"|'(\\'|\\"|[^"])*')[ \t]*[;\n]//; #'
3548 $str =~ s/[ \t][\@-]?(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+.*(;|$)//m; #'
3549
3550 print "OK: checking direct use of full pathnames in $file.\n"
3551 if ($verbose);
3552 foreach my $s (split(/\n+/, $str)) {
3553 $i = '';
3554 $s =~ s/#.*$//;
3555 if ($s =~ /(^|[ \t\@'"-])(\/[\w\d])/) { #'
3556 # suspected pathnames are recorded.
3557 $i = $2 . $';
3558 $pre = $` . $1;
3559
3560 if ($pre =~ /MASTER_SITE_SUBDIR/) {
3561 # MASTER_SITE_SUBDIR lines are ok.
3562 $i = '';
3563 }
3564 if ($s =~ /\$\{[^}]*?\Q$i\E/) {
3565 # If we're inside a make variable, we probably do not have
3566 # an absolute path.
3567 $i = '';
3568 }
3569 }
3570 if ($i ne '' && ! grep {$i =~ m|^$_|} @ALLOWED_FULL_PATHS) {
3571 $i =~ s/\s.*$//;
3572 $i =~ s/['"].*$//; #'
3573 $i = substr($i, 0, 20) . '...' if (20 < length($i));
3574 &perror("WARN", $file, -1, "possible use of absolute pathname ".
3575 "\"$i\".");
3576 }
3577 }
3578
3579 foreach my $s (split(/\n+/, $str)) {
3580 print "OK: checking direct use of pathnames, phase 1.\n" if ($verbose);
3581 %cmdnames = split(/\n|\t+/, <<EOF);
3582 /usr/opt \${PORTSDIR} instead
3583 $portsdir \${PORTSDIR} instead
3584 $localbase \${PREFIX} or \${LOCALBASE}, as appropriate
3585 EOF
3586 foreach my $i (keys %cmdnames) {
3587 if ($s =~ /^[^#]*$i/) {
3588 &perror("WARN", $file, -1, "possible direct use of \"$&\" ".
3589 "found. if so, use $cmdnames{$i}.");
3590 }
3591 }
3592
3593 print "OK: checking direct use of pathnames, phase 2.\n" if ($verbose);
3594 %cmdnames = split(/\n|\t+/, <<EOF);
3595 distfiles \${DISTDIR} instead
3596 pkg \${PKGDIR} instead
3597 files \${FILESDIR} instead
3598 scripts \${SCRIPTDIR} instead
3599 patches \${PATCHDIR} instead
3600 work \${WRKDIR} instead
3601 EOF
3602 foreach my $i (keys %cmdnames) {
3603 # use (?![\w-]) instead of \b to exclude pkg-*
3604 if ($file =~ /^[^#]*(\.\/|\$[\{\(]\.CURDIR[\}\)]\/|[ \t])(\b$i)(?![\w-])/
3605 && $s !~ /^COMMENT(.)?=[^\n]+$i/m
3606 && $s !~ /^IGNORE(.)?=[^\n]+$i/m
3607 && $s !~ /^BROKEN(.)?=[^\n]+$i/m
3608 && $s !~ /^RESTRICTED(.)?=[^\n]+$i/m
3609 && $s !~ /^NO_PACKAGE(.)?=[^\n]+$i/m
3610 && $s !~ /^NO_CDROM(.)?=[^\n]+$i/m
3611 && $s !~ /^MAINTAINER(.)?=[^\n]+$i/m
3612 && $s !~ /^CATEGORIES(.)?=[^\n]+$i/m
3613 && $s !~ /^USES(.)?=[^\n]+$i/m
3614 && $s !~ /^WX_COMPS(.)?=[^\n]+$i/m
3615 && $s !~ /^SHEBANG_FILES(.)?=[^\n]+$i/m
3616 && $s !~ /^[A-Z0-9_]+_DESC=[^\n]+$i/m
3617 && $s !~ /^ONLY_FOR_ARCHS_REASON(.)?=[^\n]+$i/m
3618 && $s !~ /^NOT_FOR_ARCHS_REASON(.)?=[^\n]+$i/m) {
3619 &perror("WARN", $file, -1, "possible direct use of \"$i\" \"$s\" ".
3620 "found. if so, use $cmdnames{$i}.");
3621 }
3622 }
3623 }
3624 }
3625
3626 sub get_makevar {
3627 my($cmd, $result);
3628
3629 $cmd = join(' -V ', "make $makeenv MASTER_SITE_BACKUP=''", map { "'$_'" } @_);
3630 $result = `$cmd`;
3631 chomp $result;
3632
3633 $result =~ s/\n\n/\n\0\n/g;
3634 if (${^CHILD_ERROR_NATIVE} != 0) {
3635 die "\nFATAL ERROR: make(1) died with status ${^CHILD_ERROR_NATIVE} and returned '$result'";
3636 }
3637
3638 return $result;
3639 }
3640
3641 sub get_makevar_raw {
3642 my($cmd, $result);
3643
3644 $cmd = join(' -XV ', "make $makeenv MASTER_SITE_BACKUP=''", map { "'$_'" } @_);
3645 $result = `$cmd`;
3646 chomp $result;
3647
3648 $result =~ s/\n\n/\n\0\n/g;
3649 if (${^CHILD_ERROR_NATIVE} != 0) {
3650 die "\nFATAL ERROR: make(1) died with status ${^CHILD_ERROR_NATIVE} and returned '$result'";
3651 }
3652
3653 return $result;
3654 }
3655
3656 sub is_predefined {
3657 my($url, $file) = @_;
3658 my($site, $site_re);
3659 my $subdir_re = quotemeta quotemeta '/%SUBDIR%/';
3660 for my $site (keys %predefined) {
3661 $site_re = quotemeta $site;
3662 $site_re =~ s,$subdir_re,/(.*)/,;
3663
3664 if ($url =~ /$site_re/ && $file) {
3665 my $pe = "how about using \"\${MASTER_SITE_$predefined{$site}}\" ";
3666 if ($1) {
3667 $pe .= "with \"MASTER_SITE_SUBDIR=$1\", ";
3668 }
3669 $pe .= "instead of \"$url\"?";
3670 &perror("WARN", $file, -1, $pe);
3671 return &TRUE;
3672 } elsif ($url =~ /$site_re/ && !$file) {
3673 return &TRUE;
3674 }
3675 }
3676 undef;
3677 }
3678
3679 sub urlcheck {
3680 my ($url, $file) = @_;
3681 if ($url !~ m#^\w+://#) {
3682 &perror("WARN", $file, -1, "\"$url\" doesn't appear to be a URL to me.");
3683 }
3684 if ($url !~ m#/(:[^/:]+)?$# && $url !~ m#:$#) {
3685 &perror("FATAL", $file, -1, "URL \"$url\" should ".
3686 "end with \"/\" or a group name (e.g. :something).");
3687 }
3688 if ($url =~ m#://[^/]*:/#) {
3689 &perror("FATAL", $file, -1, "URL \"$url\" contains ".
3690 "extra \":\".");
3691 }
3692 }
3693
3694 # GNOME wants INSTALL_ICONS, but Qt-based applications, including KDE, don't.
3695 # Be pessimistic: everything needs it unless we know it doesn't.
3696 sub needs_installs_icons {
3697 return $makevar{USE_QT5} eq ''
3698 }
3699
3700 sub TRUE {1;}
3701
3702 # Local variables:
3703 # tab-width: 4
3704 # End: