#!@PREFIX@/bin/perl # # pkglint - lint for package directory # # implemented by: # Jun-ichiro itojun Hagino # Yoshishige Arai # # Copyright(c) 1997 by Jun-ichiro Hagino . # All rights reserved. # Freely redistributable. Absolutely no warranty. # # From Id: portlint.pl,v 1.64 1998/02/28 02:34:05 itojun Exp # $NetBSD: pkglint.pl,v 1.83 2003/03/28 20:22:23 wiz Exp $ # # This version contains lots of changes necessary for NetBSD packages # done by Hubert Feyrer , # Thorsten Frueauf , Thomas Klausner # and others. # use Getopt::Std; use File::Basename; use FileHandle; $err = $warn = 0; $extrafile = $parenwarn = $committer = 1; # -abc $verbose = $newpkg = 0; # -vN $showmakefile = 0; # -I $contblank = 1; $portdir = '.'; %definesfound = (); # default settings for NetBSD $portsdir = '@PORTSDIR@'; $rcsidstr = 'NetBSD'; $localbase = '@PREFIX@'; getopts('hINB:vV'); if ($opt_h) { ($prog) = ($0 =~ /([^\/]+)$/); print STDERR <) { print "OK: checking category Makefile.\n" if ($verbose); &category_check; exit 0; } # # variables for global checks. # $sharedocused = 0; $seen_PLIST_SRC = 0; $seen_NO_PKG_REGISTER = 0; $seen_NO_CHECKSUM = 0; $seen_USE_PKGLOCALEDIR = 0; $seen_USE_BUILDLINK2 = 0; %predefined = (); foreach $i (split("\n", <, <$portdir/$pkgdir/*>)) { next if (! -T $i); next if ($i =~ /distinfo$/); next if ($i =~ /Makefile$/); $i =~ s/^\Q$portdir\E\///; next if (defined $checker{$i}); if ($i =~ /MESSAGE/) { unshift(@checker, $i); $checker{$i} = 'checkmessage'; } elsif ($i =~ /PLIST/) { unshift(@checker, $i); $checker{$i} = 'checkplist'; } else { push(@checker, $i); $checker{$i} = 'checkpathname'; } } } foreach $i (<$portdir/$patchdir/patch-*>) { next if (! -T $i); $i =~ s/^\Q$portdir\E\///; next if (defined $checker{$i}); push(@checker, $i); $checker{$i} = 'checkpatch'; } if (-e <$portdir/$distinfo>) { $i = "$distinfo"; next if (defined $checker{$i}); push(@checker, $i); $checker{$i} = 'checkdistinfo'; } { # Make sure there's a distinfo if there are patches $patches=0; patch: foreach $i (<$portdir/$patchdir/patch-*>) { if ( -T "$i" ) { $patches=1; last patch; } } if ($patches && ! -f "$portdir/$distinfo" ) { &perror("WARN: no $portdir/$distinfo file. Please run '@MAKE@ makepatchsum'."); } } foreach $i (@checker) { print "OK: checking $i.\n"; if (! -f "$portdir/$i") { &perror("FATAL: no $i in \"$portdir\"."); } else { $proc = $checker{$i}; &$proc($i) || &perror("WARN: Cannot open the file $i\n"); if ($i !~ /patches\/patch/) { &checklastline($i) || &perror("WARN: Cannot open the file $i\n"); } } } if (-e <$portdir/$distinfo> ) { if ( $seen_NO_CHECKSUM ) { &perror("WARN: NO_CHECKSUM set, but $portdir/$distinfo exists. Please remove it."); } } else { if ( ! $seen_NO_CHECKSUM ) { &perror("WARN: no $portdir/$distinfo file. Please run '@MAKE@ makesum'."); } } if (-e <$portdir/$filesdir/md5> ) { &perror("FATAL: $filesdir/md5 is deprecated -- run '@MAKE@ mdi' to generate distinfo."); } if (-e <$portdir/$filesdir/patch-sum> ) { &perror("FATAL: $filesdir/patch-sum is deprecated -- run '@MAKE@ mps' to generate distinfo."); } if (-e <$pkgdir/COMMENT> ) { &perror("FATAL: $pkgdir/COMMENT is deprecated -- please use a COMMENT variable instead."); } if (-d "$portdir/pkg" ) { &perror("FATAL: $portdir/pkg and its contents are deprecated!\n". "\tPlease 'mv $portdir/pkg/* $portdir' and 'rmdir $portdir/pkg'."); } if (-d "$portdir/scripts" ) { &perror("WARN: $portdir/scripts and its contents are deprecated! Please call the script(s)\n". "\texplicitly from the corresponding target(s) in the pkg's Makefile."); } if (! -f "$portdir/$pkgdir/PLIST" and ! -f "$portdir/$pkgdir/PLIST-mi" and ! $seen_PLIST_SRC and ! $seen_NO_PKG_REGISTER ) { &perror("WARN: no PLIST or PLIST-mi, and PLIST_SRC and NO_PKG_REGISTER unset.\n Are you sure PLIST handling is ok?"); } if ($committer) { if (scalar(@_ = <$portdir/work*/*>) || -d "$portdir/work*") { &perror("WARN: be sure to cleanup $portdir/work* ". "before committing the package."); } if (scalar(@_ = <$portdir/*/*~>) || scalar(@_ = <$portdir/*~>)) { &perror("WARN: for safety, be sure to cleanup ". "emacs backup files before committing the package."); } if (scalar(@_ = <$portdir/*/*.orig>) || scalar(@_ = <$portdir/*.orig>) || scalar(@_ = <$portdir/*/*.rej>) || scalar(@_ = <$portdir/*.rej>)) { &perror("WARN: for safety, be sure to cleanup ". "patch backup files before committing the package."); } } if ($err || $warn) { print "$err fatal errors and $warn warnings found.\n" } else { print "looks fine.\n"; } exit $err; # # DESCR # sub checkdescr { local($file) = @_; local(%maxchars) = ('DESCR', 80); local(%maxlines) = ('DESCR', 24); local(%errmsg) = ('DESCR', "exceeds $maxlines{'DESCR'} ". "lines, make it shorter if possible"); local($longlines, $linecnt, $tmp) = (0, 0, ""); $shortname = basename($file); open(IN, "< $portdir/$file") || return 0; while () { $linecnt++; $longlines++ if ($maxchars{$shortname} < length($_)); $tmp .= $_; } if ($linecnt > $maxlines{$shortname}) { &perror("WARN: $file $errmsg{$shortname} ". "(currently $linecnt lines)."); } else { print "OK: $file has $linecnt lines.\n" if ($verbose); } if ($longlines > 0) { &perror("WARN: $file includes lines that exceed ". "$maxchars{$shortname} characters."); } if ($tmp =~ /[\033\200-\377]/) { &perror("WARN: $file includes iso-8859-1, or ". "other local characters. $file should be ". "plain ascii file."); } close(IN); } # # distinfo # sub checkdistinfo { local($file) = @_; # distinfo local(%indistinfofile); open(SUM,"<$portdir/$file") || return 0; $_ = ; if (! /^\$NetBSD(:.*|)\$$/) { &perror("FATAL: missing RCS Id in distinfo file: $_"); } while() { next if !/^(MD5|SHA1|RMD160) \(([^)]+)\) = (.*)$/; $alg=$1; $patch=$2; $sum=$3; # bitch about *~ if ($patch =~ /~$/) { &perror("WARN: possible backup file '$patch' in $portdir/$file?"); } if (-T "$portdir/$patchdir/$patch") { $calcsum=`sed -e '/\$NetBSD.*/d' $portdir/$patchdir/$patch | digest $alg`; chomp($calcsum); if ( "$sum" ne "$calcsum" ) { &perror("FATAL: checksum of $patch differs between $portdir/$file and\n" ." $portdir/$patchdir/$patch. Rerun '@MAKE@ makepatchsum'."); } } elsif ($patch =~ /^patch-[a-z0-9]+$/) { &perror("FATAL: patchfile '$patch' is in $file\n" ." but not in $portdir/$patchdir/$patch. Rerun '@MAKE@ makepatchsum'."); } $indistinfofile{$patch} = 1; } close(SUM); foreach $patch ( <$portdir/$patchdir/patch-*> ) { $patch =~ /\/([^\/]+)$/; if (! $indistinfofile{$1}) { &perror("FATAL: patchsum of '$1' is in $portdir/$patchdir/$1 but not in\n" ." $file. Rerun '@MAKE@ makepatchsum'."); } } return 1; } # # MESSAGE # sub checkmessage { local($file) = @_; local($longlines, $lastline, $tmp) = (0, "", ""); $shortname = basename($file); open(IN, "< $portdir/$file") || return 0; $_ = ; if (! /^={75}$/) { &perror("WARN: $file should begin with a 75-character ". "double-dashed line."); } $_ = ; if (! /^\$NetBSD(:.*|)\$$/) { &perror("FATAL: missing RCS Id in MESSAGE file: $file"); } while () { $longlines++ if (80 < length($_)); $lastline = $_; $tmp .= $_; } if ($lastline !~ /^={75}$/) { &perror("WARN: $file should end with a 75-character ". "double-dashed line."); } if ($longlines > 0) { &perror("WARN: $file includes lines that exceed ". "80 characters."); } if ($tmp =~ /[\033\200-\377]/) { &perror("WARN: $file includes iso-8859-1, or ". "other local characters. $file should be ". "plain ascii file."); } close(IN); } # # PLIST # sub checkplist { local($file) = @_; local($curdir) = ($localbase); local($inforemoveseen, $infoinstallseen, $infoseen) = (0, 0, 0); local($infobeforeremove, $infoafterinstall) = (0, 0); local($infooverwrite) = (0); local($rcsidseen) = 0; open(IN, "< $portdir/$file") || return 0; while () { if ($_ =~ /[ \t]+\n?$/) { &perror("WARN: $file $.: whitespace before end ". "of line."); } # make it easier to handle. $_ =~ s/\s+$//; $_ =~ s/\n$//; if ($_ =~ /<\$ARCH>/) { &perror("WARN: $file $.: use of <\$ARCH> ". "deprecated, use \${MACHINE_ARCH instead}."); } if ($_ =~ /^\@/) { if ($_ =~ /^\@(cwd|cd)[ \t]+(\S+)/) { $curdir = $2; } elsif ($_ =~ /^\@unexec[ \t]+rmdir/) { &perror("WARN: use \"\@dirrm\" ". "instead of \"\@unexec rmdir\"."); } elsif ($_ =~ /^\@exec[ \t]+(.*\/)?install-info/) { $infoinstallseen = $. } elsif ($_ =~ /^\@exec[ \t]+(.*\/)?\$\{INSTALL_INFO\}/) { $infoinstallseen = $. } elsif ($_ =~ /^\@unexec[ \t]+(.*\/)?install-info[ \t]+--delete/) { $inforemoveseen = $. } elsif ($_ =~ /^\@unexec[ \t]+(.*\/)?\$\{INSTALL_INFO\}[ \t]+--delete/) { $inforemoveseen = $. } elsif ($_ =~ /^\@(exec|unexec)/) { if (/ldconfig/ && !/\/usr\/bin\/true/) { &perror("FATAL: $file $.: ldconfig ". "must be used with ". "\"||/usr/bin/true\"."); } } elsif ($_ =~ /^\@(comment)/) { $rcsidseen++ if (/\$$rcsidstr[:\$]/); } elsif ($_ =~ /^\@(dirrm|option)/) { ; # no check made } elsif ($_ =~ /^\@(mode|owner|group)/) { &perror("WARN: \"\@mode/owner/group\" are ". "deprecated, please use chmod/". "chown/chgrp in the pkg Makefile ". "and let tar do the rest."); } else { &perror("WARN: $file $.: ". "unknown PLIST directive \"$_\""); } next; } if ($_ =~ /^\//) { &perror("FATAL: $file $.: use of full pathname ". "disallowed."); } if ($_ =~ /^info\/.*info(-[0-9]+)?$/) { $infoseen = $.; $infoafterinstall++ if ($infoinstallseen); $infobeforeremove++ if (!$inforemoveseen); } if ($_ =~ /^info\/dir$/) { &perror("FATAL: \"info/dir\" should not be listed in ". "$file. use install-info to add/remove ". "an entry."); $infooverwrite++; } if ($_ =~ /^lib\/locale/) { &perror("FATAL: \"lib/locale\" should not be listed ". "in $file. Use \${PKGLOCALEDIR}/locale and ". "set USE_PKGLOCALEDIR instead."); } if ($_ =~ /^share\/locale/) { &perror("WARN: use of \"share/locale\" in $file is ". "deprecated. Use \${PKGLOCALEDIR}/locale and ". "set USE_PKGLOCALEDIR instead."); } if ($_ =~ /\${PKGLOCALEDIR}/ && $seen_USE_BUILDLINK2 && ! $seen_USE_PKGLOCALEDIR) { &perror("WARN: PLIST contains \${PKGLOCALEDIR}, ". "but USE_PKGLOCALEDIR was not found."); } if ($curdir !~ m#^$localbase# && $curdir !~ m#^/usr/X11R6#) { &perror("WARN: $file $.: installing to ". "directory $curdir discouraged. ". "could you please avoid it?"); } if ("$curdir/$_" =~ m#^$localbase/share/doc#) { print "OK: seen installation to share/doc in $file. ". "($curdir/$_)\n" if ($verbose); $sharedocused++; } } if (!$rcsidseen) { &perror("FATAL: RCS tag \"\$$rcsidstr\$\" must be present ". "in $file as \@comment.") } if (!$infoseen) { close(IN); return 1; } if (!$infoinstallseen) { if ($infooverwrite) { &perror("FATAL: \"\@exec install-info\" must be used ". "to add/delete entries into \"info/dir\"."); } &perror("FATAL: \"\@exec install-info\" must be placed ". "after all the info files."); } elsif ($infoafterinstall) { &perror("FATAL: move \"\@exec install-info\" line to make ". "sure that it is placed after all the info files. ". "(currently on line $infoinstallseen in $file)"); } if (!$inforemoveseen) { &perror("FATAL: \"\@unexec install-info --delete\" must ". "be placed before any of the info files listed."); } elsif ($infobeforeremove) { &perror("FATAL: move \"\@exec install-info --delete\" ". "line to make sure ". "that it is placed before any of the info files. ". "(currently on line $inforemoveseen in $file)"); } close(IN); } # # misc files # sub checkpathname { local($file) = @_; local($whole); open(IN, "< $portdir/$file") || return 0; $whole = ''; while () { $whole .= $_; } &abspathname($whole, $file); close(IN); } sub checklastline { local($file) = @_; local($whole); open(IN, "< $portdir/$file") || return 0; $whole = ''; while () { $whole .= $_; } if ($whole eq "") { &perror("FATAL: $file is empty."); } else { if ($whole !~ /\n$/) { &perror("FATAL: the last line of $file has to be ". "terminated by \\n."); } if ($whole =~ /\n([ \t]*\n)+$/) { &perror("WARN: $file seems to have unnecessary ". "blank lines at the bottom."); } } close(IN); } sub checkpatch { local($file) = @_; local($rcsidseen) = 0; local($whole); if ($file =~ /.*~$/) { &perror("WARN: is $file a backup file? If so, please remove it \n" ." and rerun '@MAKE@ makepatchsum'"); } open(IN, "< $portdir/$file") || return 0; $whole = ''; while () { $rcsidseen++ if /\$$rcsidstr[:\$]/; $whole .= $_; } if ($committer && $whole =~ /.\$(Author|Date|Header|Id|Locker|Log|Name|RCSfile|Revision|Source|State|NetBSD)[:\$]/) { # XXX # RCS ID in very first line is ok, to identify version # of patch (-> only warn if there's something before the # actual $RCS_ID$, not on BOF - '.' won't match there) &perror("WARN: $file includes possible RCS tag \"\$$1\$\". ". "use binary mode (-ko) on commit/import."); } if (!$rcsidseen) { &perror("FATAL: RCS tag \"\$$rcsidstr\$\" must be present ". "in patch $file.") } close(IN); } sub readmakefile { local ($file) = @_; local $contents = ""; local $includefile; local $dirname; local $savedln; local $level; local $_; my $handle = new FileHandle; $savedln = $.; $. = 0; open($handle, "< $file") || return 0; print("OK: reading Makefile '$file'\n") if ($verbose); while (<$handle>) { if ($_ =~ /[ \t]+\n?$/ && !/^#/) { &perror("WARN: $file $.: whitespace before ". "end of line."); } if ($_ =~ /^ /) { # 8 spaces here! &perror("WARN: $file $.: use tab (not spaces) to". " make indentation."); } if ($_ =~ /^\.\s*if\s+!defined\s*\((\w+)\)/) { if ($definesfound{$1}) { $level = 1; print("OK: omitting contents of !defined($1)\n") if ($verbose); $contents .= "# omitted inclusion for !defined($1) here\n"; while (<$handle>) { if ($_ =~ /^\.\s*if\s+/) { $level++; } elsif ($_ =~ /^\.\s*endif\s+/) { $level--; } if ($level eq 0) { break; } } if ($level > 0) { &perror("WARN: missing .endif."); } next; } else { print("OK: defining $1\n") if $verbose; $definesfound{$1} = true; } } # try to get any included file if ($_ =~ /^.include\s+([^\n]+)\n/) { $includefile = $1; if ($includefile =~ /\"([^\"]+)\"/) { $includefile = $1; } if ($includefile =~ /\/mk\/bsd/) { # we don't want to include the whole # bsd.pkg.mk or bsd.prefs.mk files $contents .= $_; } else { $dirname = dirname($file); print("OK: including $dirname/$includefile\n"); $contents .= readmakefile("$dirname/$includefile"); } } else { # we don't want the include Makefile.common lines # to be pkglinted $contents .= $_; } } close($handle); $. = $savedln; return $contents; } # # Makefile # sub checkmakefile { local($file) = @_; local($rawwhole, $whole, $idx, @sections); local($tmp, $tmp2); local($i, $j, $k, $l); local(@varnames) = (); local($distfiles, $pkgname, $svrpkgname, $distname, $extractsufx) = ('', '', '', '', ''); local($bogusdistfiles) = (0); local($realwrksrc, $wrksrc, $nowrksubdir) = ('', '', ''); local($includefile); $tmp = 0; $rawwhole = readmakefile("$portdir/$file"); if ($rawwhole eq '') { &perror("FATAL: can't read $portdir/$file"); return 0; } else { print("OK: whole Makefile (with all included files):\n". "$rawwhole\n") if ($showmakefile); } # # whole file: blank lines. # $whole = "\n" . $rawwhole; print "OK: checking contiguous blank lines in $file.\n" if ($verbose); $i = "\n" x ($contblank + 2); if ($whole =~ /$i/) { &perror("FATAL: contiguous blank lines (> $contblank lines) found ". "in $file at line " . int(@_ = split(/\n/, $`)) . "."); } # # whole file: $(VARIABLE) # if ($parenwarn) { print "OK: checking for \$(VARIABLE).\n" if ($verbose); if ($whole =~ /\$\([\w\d]+\)/) { &perror("WARN: use \${VARIABLE}, instead of ". "\$(VARIABLE)."); } } # # whole file: get FILESDIR, PATCHDIR, PKGDIR, SCRIPTDIR, # PATCH_SUM_FILE and DIGEST_FILE # print "OK: checking for PATCHDIR, SCRIPTDIR, FILESDIR, PKGDIR,". " DIGEST_FILE.\n" if ($verbose); $filesdir = "files"; $filesdir = $1 if ($whole =~ /\nFILESDIR[+?]?=[ \t]*([^\n]+)\n/); $filesdir =~ s/\$\{.CURDIR\}/./; $patchdir = "patches"; $patchdir = $1 if ($whole =~ /\nPATCHDIR[+?]?=[ \t]*([^\n]+)\n/); $patchdir =~ s/\$\{.CURDIR\}/./; $patchdir =~ s/\${PKGSRCDIR}/..\/../; $pkgdir = "pkg"; if (! -d "$portdir/$pkgdir") { $pkgdir = "."; } $pkgdir = $1 if ($whole =~ /\nPKGDIR[+?]?=[ \t]*([^\n]+)\n/); $pkgdir =~ s/\$\{.CURDIR\}/./; $scriptdir = "scripts"; $scriptdir = $1 if ($whole =~ /\nSCRIPTDIR[+?]?=[ \t]*([^\n]+)\n/); $scriptdir =~ s/\$\{.CURDIR\}/./; $distinfo = "distinfo"; $distinfo = $1 if ($whole =~ /\nDISTINFO_FILE[+?]?=[ \t]*([^\n]+)\n/); $distinfo =~ s/\$\{.CURDIR\}/./; $distinfo =~ s/\${PKGSRCDIR}/..\/../; print("OK: PATCHDIR: $patchdir, SCRIPTDIR: $scriptdir, ". "FILESDIR: $filesdir, PKGDIR: $pkgdir, ". "DISTINFO: $distinfo\n") if ($verbose); # # whole file: INTERACTIVE_STAGE # $whole =~ s/\n#[^\n]*/\n/g; $whole =~ s/\n\n+/\n/g; print "OK: checking INTERACTIVE_STAGE.\n" if ($verbose); if ($whole =~ /\nINTERACTIVE_STAGE/) { if ($whole !~ /defined\((BATCH|FOR_CDROM)\)/) { &perror("WARN: use of INTERACTIVE_STAGE discouraged. ". "provide batch mode by using BATCH and/or ". "FOR_CDROM."); } } print "OK: checking IS_INTERACTIVE.\n" if ($verbose); if ($whole =~ /\nIS_INTERACTIVE/) { &perror("FATAL: IS_INTERACTIVE is deprecated, ". "use INTERACTIVE_STAGE instead."); } print "OK: checking for PLIST_SRC.\n" if ($verbose); if ($whole =~ /\nPLIST_SRC/) { $seen_PLIST_SRC=1; } print "OK: checking for NO_PKG_REGISTER.\n" if ($verbose); if ($whole =~ /\nNO_PKG_REGISTER/) { $seen_NO_PKG_REGISTER=1; } print "OK: checking for NO_CHECKSUM.\n" if ($verbose); if ($whole =~ /\nNO_CHECKSUM/) { $seen_NO_CHECKSUM=1; } print "OK: checking USE_PERL usage.\n" if ($verbose); if ($whole =~ /\nUSE_PERL[^5]/) { &perror("WARN: USE_PERL found -- you probably mean USE_PERL5."); } print "OK: checking USE_PKGLIBTOOL.\n" if ($verbose); if ($whole =~ /\nUSE_PKGLIBTOOL/) { &perror("FATAL: USE_PKGLIBTOOL is deprecated, ". "use USE_LIBTOOL instead."); } print "OK: checking for USE_BUILDLINK2.\n" if ($verbose); if ($whole =~ /\nUSE_BUILDLINK2/) { $seen_USE_BUILDLINK2=1; } print "OK: checking for USE_PKGLOCALEDIR.\n" if ($verbose); if ($whole =~ /\nUSE_PKGLOCALEDIR/) { $seen_USE_PKGLOCALEDIR=1; } print "OK: checking USE_SSL.\n" if ($verbose); if ($whole =~ /\nUSE_SSL/) { &perror("FATAL: USE_SSL is deprecated, ". "use the openssl buildlink2.mk instead."); } print "OK: checking NO_WRKSUBDIR.\n" if ($verbose); if ($whole =~ /\nNO_WRKSUBDIR/) { &perror("FATAL: NO_WRKSUBDIR is deprecated, ". "use WRKSRC=\$\{WRKDIR\} instead."); } print "OK: checking MD5_FILE, DIGEST_FILE and PATCH_SUM_FILE.\n" if ($verbose); if ($whole =~ /\n(MD5_FILE)/ or $whole =~ /\n(DIGEST_FILE)/ or $whole =~ /\n(PATCH_SUM_FILE)/) { &perror("FATAL: $1 is deprecated, ". "use DISTINFO_FILE instead."); } print "OK: checking MIRROR_DISTFILE.\n" if ($verbose); if ($whole =~ /\nMIRROR_DISTFILE/) { &perror("WARN: use of MIRROR_DISTFILE deprecated, ". "use NO_BIN_ON_FTP and/or NO_SRC_ON_FTP instead."); } print "OK: checking NO_CDROM.\n" if ($verbose); if ($whole =~ /\nNO_CDROM/) { &perror("WARN: use of NO_CDROM discouraged, ". "use NO_BIN_ON_CDROM and/or NO_SRC_ON_CDROM instead."); } print "OK: checking NO_PACKAGE.\n" if ($verbose); if ($whole =~ /\nNO_PACKAGE/) { &perror("WARN: use of NO_PACKAGE to enforce license ". "restrictions is deprecated."); } print "OK: checking NO_PATCH.\n" if ($verbose); if ($whole =~ /\nNO_PATCH/) { &perror("WARN: use of NO_PATCH deprecated."); } print "OK: checking IGNORE.\n" if ($verbose); if ($whole =~ /\nIGNORE/) { &perror("FATAL: use of IGNORE deprecated, ". "use PKG_FAIL_REASON or PKG_SKIP_REASON instead."); } print "OK: checking for MKDIR.\n" if ($verbose); if ($whole =~ m|\${MKDIR}.*(\${PREFIX}[/0-9a-zA-Z\${}]*)|) { &perror("WARN: \${MKDIR} $1: consider using INSTALL_*_DIR"); } print "OK: checking for unneeded INSTALL -d.\n" if ($verbose); if ($whole =~ m|\${INSTALL}(.*)\n|) { $args = $1; if ($args =~ /-d/) { if ($args !~ /-[ogm]/) { &perror("WARN: \${INSTALL}$args: " . "consider using INSTALL_*_DIR"); } } } print "OK: checking for unneeded failure check on directory creation.\n" if ($verbose); if ($whole =~ /\n\t-(.*(MKDIR|INSTALL.*-d|INSTALL_.*_DIR).*)/g) { &perror("WARN: $1: no need to use '-' before command"); } # # whole file: direct use of command names # print "OK: checking direct use of command names.\n" if ($verbose); foreach $i (split(/\s+/, < 5) { &perror("FATAL: SVR4_PKGNAME should not be longer ". "than 5 characters."); } } $i = ($pkgname eq '') ? $distname : $pkgname; $i =~ s/\${DISTNAME[^}]*}/$distname/g; if ($i =~ /-([^-]+)$/) { $j = $`; $k = $1; if ($j =~ /[0-9]$/) { &perror("WARN: is \"$j\" sane as package name ". "WITHOUT version number? ". "if not, avoid \"-\" in version number ". "part of ". (($pkgname eq '') ? "DISTNAME." : "PKGNAME.")); } # Be very smart. Kids, don't do this at home. if ($k =~ /\$(\(|\{)([A-Z_-]+)(\)|\})/) { $k1 = $2; $k = $1 if ($rawwhole =~ /\n$k1[ \t]*?=[ \t]*([^\n]+)\n/); } if ($k =~ /^pl[0-9]*$/ || $k =~ /^[0-9]*[A-Za-z]*[0-9]*(\.[0-9]*[A-Za-z]*[0-9]*)*$/) { print "OK: trailing part of PKGNAME\"-$k\" ". "looks fine.\n" if ($verbose); } else { &perror("FATAL: version number part of PKGNAME". (($pkgname eq '') ? ', which is derived from DISTNAME, ' : ' '). "looks illegal. You should modify \"-$k\""); } } else { &perror("FATAL: PKGNAME". (($pkgname eq '') ? ', which is derived from DISTNAME, ' : ' '). "must come with version number, like \"foobaa-1.0\"."); if ($i =~ /_pl[0-9]*$/ || $i =~ /_[0-9]*[A-Za-z]?[0-9]*(\.[0-9]*[A-Za-z]?[0-9]*)*$/) { &perror("FATAL: you seem to using underline ". "before version number in PKGNAME. ". "it has to be hyphen."); } } if ($distname =~ /(nb\d*)/) { &perror("WARN: is '$1' really ok on DISTNAME, ". "or is it intended for PKGNAME?"); } # if DISTFILES have only single item, it is better to avoid DISTFILES # and to use combination of DISTNAME and EXTRACT_SUFX. # example: # DISTFILES=package-1.0.tgz # should be # DISTNAME= package-1.0 # EXTRACT_SUFX= .tgz if ($distfiles =~ /^\S+$/) { $bogusdistfiles++; print "OK: seen DISTFILES with single item, checking value.\n" if ($verbose); &perror("WARN: use of DISTFILES with single file ". "discouraged. distribution filename should be set by ". "DISTNAME and EXTRACT_SUFX."); if ($distfiles eq $distname . $extractsufx) { &perror("WARN: definition of DISTFILES not necessary. ". "DISTFILES is \${DISTNAME}/\${EXTRACT_SUFX} ". "by default."); } # make an advice only in certain cases. if ($pkgname ne '' && $distfiles =~ /^$pkgname([-\.].+)$/) { &perror("WARN: how about \"DISTNAME=$pkgname\"". (($1 eq '.tar.gz') ? "" : " and \"EXTRACT_SUFX=$1\""). ", instead of DISTFILES?"); } } # additional checks for committer. $i = ($pkgname eq '') ? $distname : $pkgname; if ($committer && $i =~ /^(de|ja|ko|ru|vi|zh)-/) { &perror("WARN: be sure to include country code \"$1-\" ". "in the module alias name."); } if ($committer && -f "$portdir/$i.tgz") { &perror("WARN: be sure to remove $portdir/$i.tgz ". "before committing the package."); } push(@varnames, split(/\s+/, < 70) { &perror("WARN: COMMENT should not be longer than 70 characters."); } &checkearlier($tmp, @varnames); $tmp = "\n" . $tmp; if ($tmp =~ /\nMAINTAINER=[^\n]+/) { $tmp =~ s/\nMAINTAINER=[^\n]+//; } else { &perror("FATAL: no MAINTAINER listed in $file."); # Why is this fatal? There's a default in bsd.pkg.mk - HF } $tmp =~ s/\n\n+/\n/g; push(@varnames, split(/\s+/, <