123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220 |
- #! /usr/bin/perl
- # ex:ts=4
- #
- # portlint - lint for port directory
- # implemented by:
- # Jun-ichiro itojun Hagino <itojun@itojun.org>
- # Yoshishige Arai <ryo2@on.rim.or.jp>
- #
- # Copyright(c) 1997 by Jun-ichiro Hagino <itojun@itojun.org>.
- # All rights reserved.
- # Freely redistributable. Absolutely no warranty.
- #
- # Please note that this perl code used to be able to handle (Open|Net|Free)BSD
- # bsd.port.mk. There are significant differences in those so you'll have
- # hard time upgrading this...
- # This code now mainly supports FreeBSD, but patches to update support for
- # OpenBSD and NetBSD will be accepted.
- #
- # $FreeBSD$
- # $Id$
- #
- use vars qw/ $opt_a $opt_A $opt_b $opt_c $opt_h $opt_t $opt_v $opt_M $opt_N $opt_B $opt_V /;
- use Getopt::Std;
- use File::Find;
- use IPC::Open2;
- #use strict;
- my ($err, $warn);
- my ($extrafile, $parenwarn, $committer, $verbose, $usetabs, $newport);
- my $contblank;
- my $portdir;
- my $makeenv = "";
- $err = $warn = 0;
- $extrafile = $parenwarn = $committer = $verbose = $usetabs = $newport = 0;
- $contblank = 1;
- $portdir = '.';
- # version variables
- my $major = 2;
- my $minor = 5;
- my $micro = 2;
- sub l { '[{(]'; }
- sub r { '[)}]'; }
- sub s { '[ \t]'; }
- my $l = &l;
- my $r = &r;
- my $s = &s;
- # default setting - for FreeBSD
- my $portsdir = '/usr/ports';
- my $rcsidstr = 'FreeBSD';
- my $multiplist = 0;
- my $ldconfigwithtrue = 0;
- my $rcsidinplist = 0;
- my $mancompress = 1;
- my $manstrict = 0;
- my $newxdef = 1;
- my $automan = 1;
- my $autoinfo = 1;
- my $manchapters = '123456789ln';
- my $localbase = '/usr/local';
- my %lang_pref = qw(
- arabic ar
- chinese zh
- french fr
- german de
- hebrew iw
- hungarian hu
- japanese ja
- korean ko
- polish pl
- portuguese pt
- russian ru
- ukrainian uk
- vietnamese vi
- );
- my @lang_cat = keys %lang_pref;
- my @lang_short = values %lang_pref;
- my $re_lang_short = '(' . join('|', @lang_short) . ')-';
- my ($prog) = ($0 =~ /([^\/]+)$/);
- sub usage {
- print STDERR <<EOF;
- usage: $prog [-AabchvtN] [-M ENV] [-B#] [port_directory]
- -a additional check for scripts/* and pkg-*
- -A turn on all additional checks (equivalent to -abcNt)
- -b warn \$(VARIABLE)
- -c committer mode
- -h show summary of command line options
- -v verbose mode
- -t nit pick about use of spaces
- -N writing a new port
- -V print the version and exit
- -M ENV set make variables to ENV (ex. PORTSDIR=/usr/ports.work)
- -B# allow # contiguous blank lines (default: $contblank line)
- EOF
- exit 0;
- }
- sub version {
- print "$prog version $major.$minor.$micro\n";
- exit $major;
- }
- getopts('AabchtvB:M:NV');
- &usage if $opt_h;
- &version if $opt_V;
- $extrafile = 1 if $opt_a || $opt_A;
- $parenwarn = 1 if $opt_b || $opt_A;
- $committer = 1 if $opt_c || $opt_A;
- $verbose = 1 if $opt_v;
- $newport = 1 if $opt_N || $opt_A;
- $usetabs = 1 if $opt_t || $opt_A;
- $contblank = $opt_B if $opt_B;
- $makeenv = $opt_M if $opt_M;
- $portdir = $ARGV[0] ? $ARGV[0] : '.';
- # OS dependent configs
- # os portsdir rcsid mplist ldcfg plist-rcsid mancompresss strict localbase newxdef automan autoinfo
- my @osdep = split(/\n/, <<EOF);
- FreeBSD /usr/ports FreeBSD 0 0 0 1 0 /usr/local 1 1 1
- NetBSD /usr/pkgsrc NetBSD 1 1 1 0 1 /usr/pkg 0 0 0
- EOF
- my $osname = `uname -s`;
- $osname =~ s/\n$//;
- foreach my $i (@osdep) {
- if ($i =~ /^$osname\t(.*)/) {
- print "OK: found OS config for $osname.\n" if ($verbose);
- ($portsdir, $rcsidstr, $multiplist, $ldconfigwithtrue,
- $rcsidinplist, $mancompress, $manstrict, $localbase,
- $newxdef, $automan, $autoinfo)
- = split(/\t+/, $1);
- last;
- }
- }
- # The PORTSDIR environment variable overrides our defaults.
- $portsdir = $ENV{PORTSDIR} if ( defined $ENV{'PORTSDIR'} );
- if ($verbose) {
- print "OK: config: portsdir: \"$portsdir\" ".
- "rcsidstr: \"$rcsidstr\" ".
- "multiplist: $multiplist ".
- "ldconfigwithtrue: $ldconfigwithtrue ".
- "rcsidinplist: $rcsidinplist ".
- "mancompress: $mancompress ".
- "manstrict: $manstrict ".
- "localbase: $localbase ".
- "\n";
- }
- #
- # just for safety.
- #
- if (! -d $portdir) {
- print STDERR "FATAL: invalid directory $portdir specified.\n";
- exit 1;
- }
- chdir "$portdir" || die "$portdir: $!";
- # get make vars
- my @varlist = qw(
- PORTNAME PORTVERSION PORTREVISION PORTEPOCH PKGNAME PKGNAMEPREFIX
- PKGNAMESUFFIX DISTNAME DISTFILES CATEGORIES MASTERDIR MAINTAINER
- MASTER_SITES WRKDIR WRKSRC NO_WRKSUBDIR PATCHDIR SCRIPTDIR FILESDIR
- PKGDIR COMMENT DESCR PLIST PKGCATEGORY PKGINSTALL PKGDEINSTALL
- PKGREQ PKGMESSAGE MD5_FILE .CURDIR INSTALLS_SHLIB
- );
- my $cmd = join(' -V ', "make $makeenv MASTER_SITE_BACKUP=''", @varlist);
- my %makevar;
- my $i = 0;
- for (split(/\n/, `$cmd`)) {
- print "OK: makevar: $varlist[$i] = $_\n" if ($verbose);
- $makevar{$varlist[$i]} = $_;
- $i++;
- }
- #
- # variables for global checks.
- #
- my $sharedocused = 0;
- my %plistmanall = ();
- my %plistmangz = ();
- my %plistman = ();
- my %manlangs = ();
- my %predefined = ();
- # historical, no longer in FreeBSD's bsd.sites.mk
- foreach my $i (split(/\n/, <<EOF)) {
- GNU ftp://prep.ai.mit.edu/pub/gnu/%SUBDIR%/
- GNU ftp://wuarchive.wustl.edu/systems/gnu/%SUBDIR%/
- GNU ftp://ftp.ecrc.net/pub/gnu/%SUBDIR%/
- PERL_CPAN ftp://ftp.cdrom.com/pub/perl/CPAN/modules/by-module/%SUBDIR%/
- SUNSITE ftp://sunsite.unc.edu/pub/Linux/%SUBDIR%/
- SUNSITE ftp://ftp.funet.fi/pub/mirrors/sunsite.unc.edu/pub/Linux/%SUBDIR%/
- SUNSITE ftp://ftp.infomagic.com/pub/mirrors/linux/sunsite/%SUBDIR%/
- TEX_CTAN ftp://ftp.cdrom.com/pub/tex/ctan/%SUBDIR%/
- TEX_CTAN ftp://ftp.tex.ac.uk/public/ctan/tex-archive/%SUBDIR%/
- GNOME ftp://ftp.cybertrails.com/pub/gnome/%SUBDIR%/
- AFTERSTEP ftp://ftp.alpha1.net/pub/mirrors/ftp.afterstep.org/%SUBDIR%/
- AFTERSTEP ftp://casper.yz.yamagata-u.ac.jp/pub/X11/apps/afterstep/%SUBDIR%/
- WINDOWMAKER ftp://ftp.io.com/pub/%SUBDIR%/
- EOF
- my ($j, $k) = split(/\t+/, $i);
- $predefined{$k} = $j;
- }
- # Read bsd.sites.mk
- $sites_mk = "$portsdir/Mk/bsd.sites.mk";
- open(MK, $sites_mk) || die "$sites_mk: $!";
- my @site_groups = grep($_ = /^MASTER_SITE_(\w+)/ && $1, <MK>);
- close(MK);
- $cmd = join(' -V MASTER_SITE_', "make $makeenv -f - all", @site_groups);
- $i = 0;
- open2(IN, OUT, $cmd);
- print OUT <<EOF;
- all:
- # do nothing
- .include "$sites_mk"
- EOF
- close(OUT);
- while (<IN>) {
- my $g = $site_groups[$i];
- for my $s (split()) {
- $predefined{$s} = $g;
- }
- $i++;
- }
- close(IN);
- #
- # check for files.
- #
- my @checker = ($makevar{DESCR}, 'Makefile', $makevar{MD5_FILE});
- my %checker = (
- $makevar{DESCR} => 'checkdescr',
- 'Makefile' => 'checkmakefile',
- $makevar{MD5_FILE} => 'TRUE'
- );
- if ($extrafile) {
- my @files = (
- <$makevar{SCRIPTDIR}/*>,
- @makevar{DESCR,PLIST,PKGINSTALL,PKGDEINSTALL,PKGREQ,PKGMESSAGE}
- );
- foreach my $i (@files) {
- next if (! -T $i);
- next if (defined $checker{$i});
- if ($i =~ /\bpkg-plist$/
- || ($multiplist && $i =~ /\bpkg-plist/)) {
- unshift(@checker, $i);
- $checker{$i} = 'checkplist';
- } else {
- push(@checker, $i);
- $checker{$i} = 'checkpathname';
- }
- }
- }
- foreach my $i (<$makevar{PATCHDIR}/patch-*>) {
- next if (! -T $i);
- next if (defined $checker{$i});
- push(@checker, $i);
- $checker{$i} = 'checkpatch';
- }
- foreach my $i (@checker) {
- print "OK: checking $i.\n" if ($verbose);
- if (! -f "$i") {
- &perror("FATAL: no $i in \"$portdir\".") unless $i eq $makevar{MD5_FILE} && $makevar{DISTFILES} eq "";
- } else {
- my $proc = $checker{$i};
- &$proc($i) || &perror("Cannot open the file $i\n");
- if ($proc ne 'checkpatch') {
- &checklastline($i)
- || &perror("Cannot open the file $i\n");
- }
- }
- }
- # Check to make sure there is no pkg-comment file anymore.
- if (-f 'pkg-comment') {
- &perror("FATAL: Use of pkg-comment is obsolete. Use the COMMENT macro within the port's Makefile instead.");
- }
- if ($committer) {
- sub find_proc {
- return if /^\.\.?$/;
- (my $fullname = $File::Find::name) =~ s#^\./##;
- print "OK: checking the file name of $fullname.\n" if ($verbose);
- if ($fullname eq 'work') {
- &perror("FATAL: $fullname: be sure to cleanup the working directory ".
- "before committing the port.");
- $File::Find::prune = 1;
- } elsif (-l) {
- &perror("Warning: $fullname: this is a symlink. ".
- "CVS will ignore it.");
- } elsif (-z) {
- &perror("FATAL: $fullname: empty file and should be removed. ".
- "If it still needs to be there, put a dummy comment ".
- "to state that the file is intentionally left empty.");
- } elsif (-d && scalar(my @x = <$_/{*,.?*}>) <= 1) {
- &perror("FATAL: $fullname: empty directory should be removed.");
- } elsif (/^\./) {
- &perror("Warning: $fullname: dotfiles are not preferred. ".
- "If this file is a dotfile to be installed as an example, ".
- "consider importing it as \"dot$_\".");
- } elsif (/\.(orig|rej|bak)$/ || /~$/ || /^\#/) {
- &perror("FATAL: $fullname: for safety, be sure to cleanup ".
- "backup files before committing the port.");
- } elsif (/(^|\.)core$/) {
- &perror("FATAL: $fullname: for safety, be sure to cleanup ".
- "core files before committing the port.");
- } elsif ($_ eq 'CVS' && -d) {
- if ($newport) {
- &perror("FATAL: $fullname: for safety, be sure to cleanup ".
- "CVS directories before importing the new port.");
- }
- $File::Find::prune = 1;
- }
- }
- find(\&find_proc, '.');
- sub checksubdir {
- my $dir = shift;
- print "OK: checking CVS status of \"$dir\".\n" if ($verbose);
- opendir DIR, $dir;
- my @filenames = readdir DIR;
- closedir DIR;
- my %entries;
- if (-f "$dir/CVS/Entries") {
- open ENTRIES, "<$dir/CVS/Entries";
- while (<ENTRIES>) {
- chomp;
- my @entry = split /\//;
- if ($entry[0] eq 'D') {
- $entries{ $entry[1] } = $entry[0]
- if $entry[1];
- }
- elsif ($entry[0] eq '') {
- if ($entry[2] =~ /^-/) {
- $entries{ $entry[1] } = 'x';
- }
- elsif ($entry[2] eq '0') {
- $entries{ $entry[1] } = 'n';
- }
- else {
- $entries{ $entry[1] } = 'f';
- }
- }
- else {
- &perror("WARN: can not parse CVS line $_");
- }
- }
- close ENTRIES;
- } else {
- &perror("WARN: no CVS directories. Use -n to check a new port.");
- return;
- }
- if (-f "$dir/CVS/Entries.Log") {
- open ENTRIES, "<$dir/CVS/Entries.Log";
- while (<ENTRIES>) {
- chomp;
- my $cmd;
- my @entry = split /\//;
- if (/^(.) (.*)$/) {
- $cmd = $1;
- @entry = split /\//, $2;
- }
- else {
- $cmd = 'A';
- @entry = split /\//;
- }
- if ($cmd eq 'A') {
- if ($entry[0] eq 'D') {
- $entries{ $entry[1] } = $entry[0]
- if $entry[1];
- }
- elsif ($entry[0] eq '') {
- if ($entry[2] =~ /^-/) {
- $entries{ $entry[1] } = 'x';
- }
- elsif ($entry[2] eq '0') {
- $entries{ $entry[1] } = 'n';
- }
- else {
- $entries{ $entry[1] } = 'f';
- }
- }
- else {
- &perror("WARN: can not parse CVS line $_");
- }
- }
- elsif ($cmd eq 'R') {
- delete $entries{ $entry[1] }
- if $entry[1];
- }
- # ignore unknown commands
- }
- close ENTRIES;
- }
- foreach (@filenames) {
- next
- if /^(?:\.\.?|CVS)$/;
- my $filename = $dir eq '.' ? $_ : "$dir/$_";
- if (-d $filename) {
- if (!$entries{$_} || $entries{$_} ne 'D') {
- &perror("FATAL: directory $filename not in CVS.");
- }
- else {
- delete $entries{$_};
- checksubdir($filename);
- }
- }
- else {
- if (!$entries{$_}) {
- &perror("FATAL: file $filename not in CVS.");
- }
- elsif ($entries{$_} eq 'D') {
- &perror("FATAL: file $filename is a directory in CVS.");
- }
- elsif ($entries{$_} eq 'x') {
- &perror("FATAL: file $filename is deleted in CVS.");
- }
- elsif ($entries{$_} eq 'n') {
- if (!system("egrep", "-q", "\\\$$rcsidstr\[^\$\]+\\\$", $filename)) {
- &perror("WARN: RCS tag \"\$$rcsidstr\$\" ".
- "should be empty in new file $filename.");
- }
- delete $entries{$_};
- }
- else {
- delete $entries{$_};
- }
- }
- }
- while (my ($file, $type) = each %entries) {
- next if $type eq 'x';
- if ($type eq 'D') {
- &perror("FATAL: CVS directory $dir/$file missing");
- }
- else {
- &perror("FATAL: CVS file $dir/$file missing");
- }
- }
- }
- checksubdir('.')
- unless $newport;
- # Check for ports that may break INDEX
- my $indexerr = `env LOCALBASE=/nonexistentlocal X11BASE=/nonexistentx make $makeenv describe 2>&1 >/dev/null`;
- chomp $indexerr;
- $indexerr =~ tr/\n/ /s;
- &perror("FATAL: breaks INDEX ($indexerr).")
- if ($indexerr);
- }
- if ($err || $warn) {
- print "$err fatal errors and $warn warnings found.\n"
- } else {
- print "looks fine.\n";
- }
- exit $err;
- #
- # pkg-descr
- #
- sub checkdescr {
- my($file) = @_;
- my(%maxchars) = ($makevar{DESCR}, 80);
- my(%maxlines) = ($makevar{DESCR}, 24);
- my(%errmsg) = ($makevar{DESCR}, "exceeds $maxlines{$makevar{DESCR}} ".
- "lines, make it shorter if possible.");
- my($longlines, $linecnt, $tmp) = (0, 0, "");
- open(IN, "< $file") || return 0;
- while (<IN>) {
- $tmp .= $_;
- chomp || &perror("WARN: $file: should terminate in '\n'.");
- $linecnt++;
- $longlines++ if ($maxchars{$file} < length);
- }
- if ($linecnt > $maxlines{$file}) {
- &perror("WARN: $file $errmsg{$file}".
- "(currently $linecnt lines)");
- } else {
- print "OK: $file: has $linecnt lines.\n" if ($verbose);
- }
- if ($longlines > 0) {
- &perror("WARN: $file: includes lines that exceed $maxchars{$file} ".
- "characters.");
- }
- if ($tmp =~ /[\033\200-\377]/) {
- &perror("WARN: $file: includes iso-8859-1, or ".
- "other local characters. files should be in ".
- "plain 7-bit ASCII");
- }
- if ($file =~ /\bpkg-descr/ && $tmp =~ m,http://,) {
- my $has_url = 0;
- my $has_www = 0;
- foreach my $line (grep($_ =~ "http://", split(/\n+/, $tmp))) {
- $has_url = 1;
- if ($line =~ m,WWW:[ \t]+http://,) {
- $has_www = 1;
- }
- }
- if ($has_url && ! $has_www) {
- &perror("FATAL: $file: contains a URL but no \"WWW:\"");
- }
- }
- close(IN);
- }
- #
- # pkg-plist
- #
- sub checkplist {
- my($file) = @_;
- my($curdir) = ($localbase);
- my(%omfremoveseen) = ();
- my(%omfinstallseen) = ();
- my(%omfseen) = ();
- my($inforemoveseen, $infoinstallseen, $infoseen) = (0, 0, 0);
- my(%omfafterinstall) = ();
- my(%omfafterremove) = ();
- my($infobeforeremove, $infoafterinstall) = (0, 0);
- my($infooverwrite) = (0);
- my($rcsidseen) = (0);
- my(@exec_omf) = ();
- my(@exec_info) = ();
- my(@unexec_omf) = ();
- my(@unexec_info) = ();
- my(@omffile) = ();
- my(@infofile) = ();
- open(IN, "< $file") || return 0;
- while (<IN>) {
- if ($_ =~ /[ \t]+\n?$/) {
- &perror("WARN: $file [$.]: whitespace before end ".
- "of line.");
- }
- # make it easier to handle.
- $_ =~ s/\s+$//;
- $_ =~ s/\n$//;
- if ($osname eq 'NetBSD' && $_ =~ /<\$ARCH>/) {
- &perror("WARN: $file [$.]: use of <\$ARCH> deprecated, ".
- "use \${MACHINE_ARCH} instead.");
- }
- if (m'lib/perl5/site_perl/%%PERL_VER%%') {
- &perror("WARN: $file [$.]: use \%\%SITE_PERL\%\% ".
- "instead of lib/perl5/site_perl/\%\%PERL_VER\%\%.");
- }
- if ($_ =~ /^\@/) {
- if ($_ =~ /^\@(cwd|cd)[ \t]+(\S+)/) {
- $curdir = $2;
- } elsif ($_ =~ /^\@unexec[ \t]+rm[ \t]/) {
- if ($_ !~ /%[DB]/) {
- &perror("WARN: $file [$.]: use \"%D\" or \"%B\" to ".
- "specify prefix.");
- }
- if ($_ !~ /true$/ && $_ !~ /rm -f/) {
- &perror("WARN: $file [$.]: add \"2>&1 ".
- ">/dev/null || true\" ".
- "to \"\@unexec rm\".");
- }
- } elsif ($_ =~ /^\@unexec[ \t]+rmdir/) {
- if ($_ !~ /%[DB]/) {
- &perror("WARN: $file [$.]: use \"%D\" or \"%B\" to ".
- "specify prefix.");
- }
- if ($_ !~ /true$/) {
- &perror("WARN: $file [$.]: use \"\@dirrm\" ".
- "instead of \"\@unexec rmdir\".");
- }
- } elsif ($_ =~ /^\@exec[ \t]+scrollkeeper-install[ \t]+-q\s+(\S+)\s+.+$/) {
- push(@exec_omf, $1);
- my $ot = $1;
- $ot =~ s/^\%D\///;
- $omfinstallseen{$ot} = $.;
- } elsif (!$autoinfo && $_ =~ /^\@exec[ \t]+install-info\s+(.+)\s+(.+)$/) {
- $infoinstallseen = $.;
- push(@exec_info, $1);
- } elsif ($autoinfo && $_ =~ /^\@exec[ \t]+install-info\s+(.+)\s+(.+)$/) {
- &perror("WARN: $file [$.]: \@exec install-info is deprecated in favor of adding info files into the Makefile using the INFO macro.");
- } elsif ($_ =~ /^\@unexec[ \t]+scrollkeeper-uninstall[ \t]+-q\s+(\S+)\s+.+$/) {
- push(@unexec_omf, $1);
- my $ot = $1;
- $ot =~ s/^\%D\///;
- $omfremoveseen{$ot} = $.;
- } elsif (!$autoinfo && $_ =~ /^\@unexec[ \t]+install-info[ \t]+--delete\s+(.+)\s+(.+)$/) {
- $inforemoveseen = $.;
- push(@unexec_info, $1);
- } elsif ($autoinfo && $_ =~ /^\@unexec[ \t]+install-info[ \t]+--delete\s+(.+)\s+(.+)$/) {
- &perror("WARN: $file [$.]: \@unexec install-info is deprecated in favor of adding info files into the Makefile using the INFO macro.");
- } elsif ($_ =~ /^\@(exec|unexec)/) {
- if (/ldconfig/) {
- if ($ldconfigwithtrue
- && !/\/usr\/bin\/true/) {
- &perror("FATAL: $file [$.]: ldconfig ".
- "must be used with ".
- "\"||/usr/bin/true\".");
- }
- &perror("WARN: $file [$.]: possible ".
- "direct use of ldconfig ".
- "in PLIST found. use ".
- "INSTALLS_SHLIB instead.");
- }
- } elsif ($_ =~ /^\@(comment)/) {
- $rcsidseen++ if (/\$$rcsidstr[:\$]/);
- } elsif ($_ =~ /^\@(owner|group)\s/) {
- &perror("WARN: $file [$.]: \@$1 should not be needed");
- } elsif ($_ =~ /^\@(dirrm|option)/) {
- ; # no check made
- } else {
- &perror("WARN: $file [$.]: ".
- "unknown pkg-plist directive \"$_\"");
- }
- next;
- }
- if ($_ =~ /^\//) {
- &perror("FATAL: $file [$.]: use of full pathname ".
- "disallowed.");
- }
- if ($_ =~ /\.la$/) {
- &perror("WARN: $file [$.]: installing libtool archives, ".
- "please use USE_LIBTOOL in Makefile if possible");
- }
- if ($_ =~ /\.so(\.\d+)?$/ && $makevar{INSTALLS_SHLIB} eq '') {
- &perror("WARN: $file [$.]: installing shared libraries, ".
- "please define INSTALLS_SHLIB as appropriate");
- }
- if ($autoinfo && $_ =~ /\.info$/) {
- &perror("WARN: $file [$.]: enumerating info files in the plist is deprecated in favor of adding info files into the Makefile using the INFO macro.");
- }
- if ($autoinfo && $_ =~ /\.info-\d+$/) {
- &perror("FATAL: $file [$.]: numbered info files are obsolete and not portable; add info files using the INFO macro in the Makefile.");
- }
- if ($_ =~ /.*\.omf$/) {
- $omfseen{$_} = $.;
- $omfafterinstall{$_}++ if ($omfinstallseen{$_});
- $omfafterremove{$_}++ if ($omfremoveseen{$_});
- push(@omffile, $_);
- }
- if (!$autoinfo) {
- if ($_ =~ /^info\/.*info(-[0-9]+)?$/) {
- $infoseen = $.;
- $infoafterinstall++ if ($infoinstallseen);
- $infobeforeremove++ if (!$inforemoveseen);
- push(@infofile, $_);
- }
- if ($_ =~ /^info\/dir$/) {
- &perror("FATAL: $file [$.]: \"info/dir\" should not be listed.".
- "use install-info to add/remove ".
- "an entry.");
- $infooverwrite++;
- }
- }
- if ($_ =~ /^(\%\%PORTDOCS\%\%)?share\/doc\//) {
- &perror("WARN: $file [$.]: consider using DOCSDIR macro");
- $sharedocused++;
- } elsif ($_ =~ /^(\%\%PORTDOCS\%\%)?\%\%DOCSDIR\%\%/) {
- $sharedocused++;
- }
- if ($_ =~ /^share\/examples\//) {
- &perror("WARN: $file [$.]: consider using EXAMPLESDIR macro");
- }
- if ($_ =~ m#man/([^/]+/)?man([$manchapters])/([^\.]+\.[$manchapters])(\.gz)?$#) {
- if ($4 eq '') {
- $plistman{$2} .= ' ' . $3;
- if ($mancompress) {
- &perror("FATAL: $file [$.]: ".
- "unpacked man file $3 ".
- "listed. must be gzipped.");
- }
- } else {
- $plistmangz{$2} .= ' ' . $3;
- if (!$mancompress) {
- &perror("FATAL: $file [$.]: ".
- "gzipped man file $3$4 ".
- "listed. unpacked one should ".
- "be installed.");
- }
- }
- $plistmanall{$2} .= ' ' . $3;
- if ($1 ne '') {
- $manlangs{substr($1, 0, length($1) - 1)}++;
- }
- }
- 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: $file [$.]: seen installation to share/doc. ".
- "($curdir/$_)\n" if ($verbose);
- $sharedocused++;
- }
- }
- # Check that each OMF file has an install and deinstall line.
- my $omf_install = join(" ", @exec_omf);
- $omf_install .= ' ';
- my $omf_deinstall = join(" ", @unexec_omf);
- $omf_deinstall .= ' ';
- foreach my $of (@omffile) {
- if ($omf_install !~ /\%D\/\Q$of\E/) {
- &perror("FATAL: $file: you need an '\@exec scrollkeeper-install -q \%D/$of 2>/dev/null || /usr/bin/true' line");
- }
- if ($omf_deinstall !~ /\%D\/$of/) {
- &perror("FATAL: $file: you need an '\@unexec scrollkeeper-uninstall -q \%D/$of 2>/dev/null || /usr/bin/true' line");
- }
- }
- if (!$autoinfo) {
- # check that every infofile has an exec install-info and unexec install-info
- my $exec_install = join(" ", @exec_info);
- $exec_install .= ' ';
- my $unexec_install = join(" ", @unexec_info);
- $unexec_install .= ' ';
- foreach my $if (@infofile) {
- next if ($if =~ m/info-/);
- if ($exec_install !~ m/\%D\/\Q$if\E/) {
- &perror("FATAL: $file: you need an '\@exec install-info \%D/$if \%D/info/dir' line");
- }
- if ($unexec_install !~ m/\%D\/$if/) {
- &perror("FATAL: $file: you need an '\@unexec install-info --delete \%D/$if \%D/info/dir' line");
- }
- }
- }
- if ($rcsidinplist && !$rcsidseen) {
- &perror("FATAL: $file: RCS tag \"\$$rcsidstr\$\" must be present ".
- "as \@comment.")
- }
- if (((!$autoinfo && !$infoseen) || $autoinfo) && !scalar(keys %omfseen)) {
- close(IN);
- return 1;
- }
- if (scalar(keys %omfseen)) {
- if (!scalar(keys %omfinstallseen)) {
- &perror("FATAL: $file: scrollkeeper-install must be used to ".
- "add/delete entries from the ScrollKeeper OMF database.");
- } else {
- foreach my $of (keys %omfseen) {
- if ($omfafterinstall{$of}) {
- &perror("FATAL: $file [$omfinstallseen{$of}]: move ".
- "\"\@exec scrollkeeper-install\" ".
- "line to make sure that it is placed after ".
- "the $of entry.");
- }
- }
- }
- if (!scalar(keys %omfremoveseen)) {
- &perror("FATAL: $file: \"\@unexec scrollkeeper-uninstall\" must ".
- "be placed after the OMF file it uninstalls.");
- } else {
- foreach my $of (keys %omfseen) {
- if ($omfafterremove{$of}) {
- &perror("FATAL: $file [$omfremoveseen{$of}]: move ".
- "\"\@unexec scrollkeeper-uninstall\" ".
- "line to make sure that it is placed after ".
- "the $of entry.");
- }
- }
- }
- }
- if (!$autoinfo && $infoseen) {
- if (!$infoinstallseen) {
- if ($infooverwrite) {
- &perror("FATAL: $file: install-info must be used to ".
- "add/delete entries into \"info/dir\".");
- }
- &perror("FATAL: $file: \"\@exec install-info \%D/... \%D/info/dir\" must be placed ".
- "after all the info files.");
- } elsif ($infoafterinstall) {
- &perror("FATAL: $file [$infoinstallseen]: move ".
- "\"\@exec install-info\" line to make ".
- "sure that it is placed after all the info files.");
- }
- if (!$inforemoveseen) {
- &perror("FATAL: $file: \"\@unexec install-info --delete \%D/... \%D/info/dir\" must ".
- "be placed before any of the info files listed.");
- } elsif ($infobeforeremove) {
- &perror("FATAL: $file [$inforemoveseen]: move ".
- "\"\@exec install-info --delete\" ".
- "line to make sure ".
- "that it is placed before any of the info files. ");
- }
- }
- close(IN);
- }
- #
- # misc files
- #
- sub checkpathname {
- my($file) = @_;
- my($whole);
- open(IN, "< $file") || return 0;
- $whole = '';
- while (<IN>) {
- $whole .= $_;
- }
- &abspathname($whole, $file);
- close(IN);
- }
- sub checklastline {
- my($file) = @_;
- my($whole);
- open(IN, "< $file") || return 0;
- $whole = '';
- while (<IN>) {
- $whole .= $_;
- }
- if ($whole !~ /\n$/) {
- &perror("FATAL: $file: the last line has to be ".
- "terminated by \\n.");
- }
- if ($whole =~ /\n([ \t]*\n)+$/) {
- &perror("WARN: $file: seems to have unnecessary blank lines ".
- "at the last part.");
- }
- close(IN);
- }
- sub checkpatch {
- my($file) = @_;
- my($whole);
- if (-z "$file") {
- &perror("FATAL: $file: has no content. should be removed ".
- "from repository.");
- return;
- }
- open(IN, "< $file") || return 0;
- $whole = '';
- while (<IN>) {
- $whole .= $_;
- }
- if ($committer && $whole =~ /\$([A-Za-z0-9]+)[:\$]/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: includes possible RCS tag \"\$$1\$\". ".
- "use binary mode (-ko) on commit/import.") unless
- $1 eq $rcsidstr;
- }
- close(IN);
- }
- #
- # Makefile
- #
- sub checkmakefile {
- my($file) = @_;
- my($rawwhole, $whole, $idx, @sections);
- my($i, $j, $k, $l);
- my @cat = ();
- my $has_lang_cat = 0;
- my $port_lang = '';
- my $tmp;
- my $bogusdistfiles = 0;
- my @varnames = ();
- my($portname, $portversion, $distfiles, $distname, $extractsufx) = ('', '', '', '', '');
- my $masterport = 0;
- my $slaveport = 0;
- my $use_gnome_hack = 0;
- my($realwrksrc, $wrksrc, $nowrksubdir) = ('', '', '');
- my(@mman, @pman);
- open(IN, "< $file") || return 0;
- $rawwhole = '';
- $tmp = 0;
- while (<IN>) {
- if ($_ =~ /[ \t]+\n?$/) {
- &perror("WARN: $file [$.]: whitespace before ".
- "end of line.");
- }
- if ($_ =~ /^ /) { # 8 spaces here!
- &perror("WARN: $file [$.]: use tab (not space) to make ".
- "indentation");
- }
- if ($usetabs) {
- if (m/^[A-Za-z0-9_-]+.?= /) {
- if (m/[?+]=/) {
- &perror("WARN: $file [$.]: use a tab (not space) after a ".
- "variable name");
- } else {
- &perror("FATAL: $file [$.]: use a tab (not space) after a ".
- "variable name");
- }
- }
- }
- #
- # I'm still not very convinced, for using this kind of magical word.
- # 1. This kind of items are not important for Makefile;
- # portlint should not require any additional rule to Makefile.
- # portlint should simply implement items that are declared in Handbook.
- # 2. If we have LINTSKIP, we can't stop people using LINTSKIP too much.
- # IMHO it is better to warn the user and let the user think twice,
- # than let the user escape from portlint.
- # Uncomment this part if you are willing to use these magical words.
- # Thu Jun 26 11:37:56 JST 1997
- # -- itojun
- #
- # if ($_ =~ /^# LINTSKIP\n?$/) {
- # print "OK: skipping from line $. in $file.\n"
- # if ($verbose);
- # $tmp = 1;
- # next;
- # }
- # if ($_ =~ /^# LINTAGAIN\n?$/) {
- # print "OK: check start again from line $. in $file.\n"
- # if ($verbose);
- # $tmp = 0;
- # next;
- # }
- # if ($_ =~ /# LINTIGNORE/) {
- # print "OK: ignoring line $. in $file.\n" if ($verbose);
- # next;
- # }
- # next if ($tmp);
- $rawwhole .= $_;
- }
- close(IN);
- #
- # whole file: blank lines.
- #
- $whole = "\n" . $rawwhole;
- study $whole;
- print "OK: checking contiguous blank lines in $file.\n"
- if ($verbose);
- $i = "\n" x ($contblank + 2);
- if ($whole =~ /$i/) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: contiguous blank lines ".
- "(> $contblank lines) found.");
- }
- #
- # whole file: $(VARIABLE)
- #
- if ($parenwarn) {
- print "OK: checking for \$(VARIABLE).\n" if ($verbose);
- if ($whole =~ /\$\([\w\d]+\)/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: use \${VARIABLE}, instead of ".
- "\$(VARIABLE).");
- }
- }
- #
- # whole file: USE_* used too late
- #
- pos($whole) = 0;
- if ($whole =~ /^\.include\s+<bsd\.port\.pre\.mk>$/gm) {
- print "OK: checking for USE_* used too late.\n" if ($verbose);
- my @use_early = qw(
- APACHE
- GNUSTEP
- IMAKE
- JAVA
- KDE(?:BASE|LIBS)_VER
- LIBRUBY
- LINUX_PREFIX
- OPENSSL
- PYTHON
- QT2?
- QT_VER
- RUBY
- X_PREFIX
- );
- my @other_early = qw(
- EMACS_PORT_NAME
- );
- my $earlypattern = join('|', 'USE_(?:'.join('|', @use_early).')',
- @other_early);
- while ($whole =~ /^($earlypattern)[+?:!]?=/gmo) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: $1 is set after ".
- "including bsd.port.pre.mk.");
- }
- }
- #
- # whole file: anything after bsd.port(.post).mk
- #
- print "OK: checking for anything after bsd.port(.post).mk.\n"
- if ($verbose);
- if ($whole =~ /^\.include\s+<bsd\.port(?:\.post)\.mk>\s*[^\s]/m) {
- &perror("FATAL: $file: do not include anything after ".
- "bsd.port(.post).mk.");
- }
- #
- # whole file: USE_* as a user-settable option
- #
- print "OK: checking for USE_* as a user-settable option.\n" if ($verbose);
- while ($whole =~ /\n\s*\.\s*(?:el)?if[^\n]*?\b(\w*USE_)(\w+)(?\![^\n]*\n#?\.error)/g) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: is $1$2 a user-settable option? ".
- "Consider using WITH_$2 instead.")
- if ($1.$2 ne 'USE_GCC');
- }
- #
- # whole file: NO_CHECKSUM
- #
- # XXX Don't compress newlines since it messes up line number calculation.
- #$whole =~ s/\n#[^\n]*/\n/g;
- #$whole =~ s/\n\n+/\n/g;
- print "OK: checking NO_CHECKSUM.\n" if ($verbose);
- if ($whole =~ /\nNO_CHECKSUM/) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: use of NO_CHECKSUM discouraged. ".
- "it is intended to be a user variable.");
- }
-
- #
- # whole file: PKGNAME
- #
- print "OK: checking PKGNAME.\n" if ($verbose);
- if ($whole =~ /\nPKGNAME.?=/) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: PKGNAME is obsoleted by PORTNAME, ".
- "PORTVERSION, PKGNAMEPREFIX and PKGNAMESUFFIX.");
- }
- #
- # whole file: IS_INTERACTIVE/NOPORTDOCS
- #
- print "OK: checking IS_INTERACTIVE.\n" if ($verbose);
- if ($whole =~ /\nIS_INTERACTIVE/) {
- if ($whole !~ /defined\((BATCH|FOR_CDROM)\)/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: use of IS_INTERACTIVE ".
- "discouraged. provide batch mode by using BATCH and/or ".
- "FOR_CDROM.");
- }
- }
- print "OK: checking for use of NOPORTDOCS.\n" if ($verbose);
- if ($whole =~ /NOPORTSDOC/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: NOPORTSDOC found. Do you ".
- "mean NOPORTDOCS?");
- }
- if ($sharedocused && $whole !~ /defined\s*\(?NOPORTDOCS\)?/
- && $whole !~ /def\s*\(?NOPORTDOCS\)?/
- && $whole !~ m#(\$[\{\(]PREFIX[\}\)]|$localbase)/share/doc#) {
- &perror("WARN: $file: use \".if !defined(NOPORTDOCS)\" to wrap ".
- "installation of files into $localbase/share/doc.");
- }
- #
- # whole file: direct use of command names
- #
- my %cmdnames = ();
- print "OK: checking direct use of command names.\n" if ($verbose);
- foreach my $i (qw(
- awk basename cat chmod chown cp echo expr false file find gmake grep gzcat
- ldconfig ln md5 mkdir mv patch perl rm rmdir ruby sed sh touch tr which xargs xmkmf
- )) {
- $cmdnames{$i} = "\$\{\U$i\E\}";
- }
- $cmdnames{'env'} = '${SETENV}';
- $cmdnames{'gunzip'} = '${GUNZIP_CMD}';
- $cmdnames{'gzip'} = '${GZIP_CMD}';
- $cmdnames{'install'} = '${INSTALL_foobaa}';
- $cmdnames{'python'} = '${PYTHON_CMD}';
- $cmdnames{'strip'} = '${STRIP_CMD}';
- foreach my $i (qw(aclocal autoconf autoheader automake autoreconf autoupdate autoscan ifnames libtool libtoolize)) {
- $autocmdnames{$i} = "\$\{" . ( ( $i !~ /auto|aclocal|libtool/ ) ? "AUTO" : "" ) . "\U$i\E\}";
- }
- #
- # ignore parameter string to echo command.
- # note that we leave the command as is, since we need to check the
- # use of echo itself.
- $j = $whole;
- $j =~ s/([ \t][\@\-]{0,2})(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+("(\\'|\\"|[^"])*"|'(\\'|\\"|[^'])*')[ \t]*;?(\n?)/$1$2;$3/g; #"
- foreach my $i (keys %cmdnames) {
- # XXX This is a hack. Really, we should break $j up into individual
- # lines, and go through each one.
- while ($j =~ /^(.*$i.*)$/gm) {
- my $curline = $1;
- my $lineno = &linenumber($`);
- if ($curline =~ /(^|\s+)[\@\-]{0,2}$i\b/
- && $curline !~ /^[A-Z]+_TARGET[?+]?=[^\n]+$i/m
- && $curline !~ /^IGNORE(.)?=[^\n]+$i/m
- && $curline !~ /^BROKEN(.)?=[^\n]+$i/m
- && $curline !~ /^RESTRICTED(.)?=[^\n]+$i/m
- && $curline !~ /^NO_PACKAGE(.)?=[^\n]+$i/m
- && $curline !~ /^NO_CDROM(.)?=[^\n]+$i/m
- && $curline !~ /^CATEGORIES(.)?=[^\n]+$i/m
- && $curline !~ /^COMMENT(.)?=[^\n]+$i/m) {
- &perror("WARN: $file [$lineno]: possible direct use of ".
- "command \"$i\" found. use ".
- "$cmdnames{$i} instead.");
- }
- }
- }
- foreach my $i (keys %autocmdnames) {
- # XXX Same hack as above.
- while ($j =~ /^(.*($i\d*).*)$/gm) {
- my $lm = $1;
- my $sm = $2;
- my $lineno = &linenumber($`);
- if ($lm =~ /(^|\s+)[\@\-]{0,2}($i\d*)\b/
- && $lm !~ /^[A-Z]+_TARGET[?+]?=[^\n]+($i\d*)/m
- && $lm !~ /^IGNORE(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^BROKEN(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^RESTRICTED(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^NO_PACKAGE(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^NO_CDROM(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^CATEGORIES(.)?=[^\n]+($i\d*)/m
- && $lm !~ /^COMMENT(.)?=[^\n]+($i\d*)/m) {
- &perror("WARN: $file [$lineno]: possible direct use of ".
- "command \"$sm\" found. Use $autocmdnames{$i} ".
- "instead and set according USE_*_VER= flag");
- }
- }
- }
- #
- # whole file: ldconfig must come with "true" command
- #
- if ($ldconfigwithtrue
- && $j =~ /(ldconfig|\$[{(]LDCONFIG[)}])/
- && $j !~ /(\/usr\/bin\/true|\$[{(]TRUE[)}])/) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: ldconfig must be used with ".
- "\"||\${TRUE}\".");
- }
- #
- # whole file: ${GZIP_CMD} -9 (or any other number)
- #
- if ($j =~ /\${GZIP_CMD}\s+-(\w+(\s+-)?)*(\d)/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: possible use of \"\${GZIP_CMD} -$3\" ".
- "found. \${GZIP_CMD} includes \"-\${GZIP}\" which ".
- "sets the compression level.");
- }
- #
- # whole file: ${MKDIR} -p
- #
- if ($j =~ /\${MKDIR}\s+-p/) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: possible use of \"\${MKDIR} -p\" ".
- "found. \${MKDIR} includes ".
- "\"-p\" by default.");
- }
- #
- # whole file: full path name
- #
- &abspathname($whole, $file);
- #
- # whole file: SITE_PERL
- #
- print "OK: checking SITE_PERL.\n" if ($verbose);
- if ($whole =~ /\nSITE_PERL[?:]?=/) {
- my $lineno = &linenumber($`);
- &perror("FATAL: $file [$lineno]: use of SITE_PERL discouraged. ".
- "it is set in bsd.port.mk.");
- }
- #
- # whole file: ${LOCALBASE}/lib/perl5/site_perl/${PERL_VER}
- #
- if ($j =~ m'\${(?:LOCALBASE|PREFIX)}/lib/perl5/site_perl/\${PERL_VER}') {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: possible use of \"\${LOCALBASE}/lib/perl5/site_perl/\${PERL_VER}\" ".
- "found. use \"\${SITE_PERL}\" instead.");
- }
- #
- # whole file: USE_GNOME check
- #
- if ($whole =~ /^USE_GNOME[?:]?=\s*(.*)$/m) {
- if ($1 =~ /gnomehack/) {
- $use_gnome_hack = 1;
- }
- }
- #
- # whole file: check for deprecated USE_MESA
- #
- if ($whole =~ /^USE_MESA[?:]?=/m) {
- my $lineno = &linenumber($`);
- &perror("WARN: $file [$lineno]: USE_MESA is deprecated".
- ". use USE_GL instead.");
- }
- #
- # slave port check
- #
- my $masterdir = $makevar{MASTERDIR};
- if ($masterdir ne '' && $masterdir ne $makevar{'.CURDIR'}) {
- $slaveport = 1;
- print "OK: slave port detected, checking for inclusion of $masterdir/Makefile.\n"
- if ($verbose);
- if ($whole !~ /\n\.include\s+[<"]\$\{MASTERDIR\}\/Makefile[">]\s*$/) {
- &perror('FATAL: $file: the last line of a slave port\'s Makefile has to be'.
- ' .include "${MASTERDIR}/Makefile"');
- }
- print "OK: checking master port in $masterdir.\n" if ($verbose);
- if (! -e "$masterdir/Makefile") {
- &perror("WARN: unable to locate master port in $masterdir");
- }
- }
- #
- # break the makefile into sections.
- #
- $tmp = $rawwhole;
- # keep comment, blank line, comment in the same section
- $tmp =~ s/(#.*\n)\n+(#.*)/$1$2/g;
- @sections = split(/\n\n+/, $tmp);
- for ($i = 0; $i <= $#sections; $i++) {
- if ($sections[$i] !~ /\n$/) {
- $sections[$i] .= "\n";
- }
- }
- $idx = 0;
- #
- # section 1: comment lines.
- #
- print "OK: checking comment section of $file.\n" if ($verbose);
- my @linestocheck = split("\n", <<EOF);
- Whom
- Date [cC]reated
- EOF
- if ($osname eq 'NetBSD') {
- unshift(@linestocheck, '(New )?[pP](ackage|ort)s [cC]ollection [mM]akefile [fF]or');
- } else {
- unshift(@linestocheck, '(New )?[pP]orts [cC]ollection [mM]akefile [fF]or');
- }
- $tmp = $sections[$idx++];
- $tmp = "\n" . $tmp; # to make the begin-of-line check easier
- if ($tmp =~ /\n[^#]/) {
- &perror("FATAL: $file: non-comment line in comment section.");
- }
- foreach my $i (@linestocheck) {
- $j = $i;
- $j =~ s/\(.*\)\?//g;
- $j =~ s/\[(.)[^\]]*\]/$1/g;
- if ($tmp !~ /# $i:[ \t]+\S+/) {
- &perror("FATAL: $file: no \"$j\" line in comment section.");
- } else {
- print "OK: \"$j\" seen in $file.\n" if ($verbose);
- }
- }
- if ($tmp =~ m/Version [rR]equired/) {
- &perror("WARN: $file: Version required is no longer needed in the comment section.");
- }
- my $tmp2 = "";
- for (split(/\n/, $tmp)) {
- $tmp2 .= $_ if (m/\$$rcsidstr/);
- }
- if ($tmp2 !~ /#(\s+)\$$rcsidstr([^\$]*)\$$/) {
- &perror("FATAL: $file: no \$$rcsidstr\$ line in comment ".
- "section.");
- } else {
- print "OK: \$$rcsidstr\$ seen in $file.\n" if ($verbose);
- if ($1 ne ' ') {
- &perror("WARN: $file: please use single whitespace ".
- "right before \$$rcsidstr\$ tag.");
- }
- if ($2 ne '') {
- if ($verbose || $newport) { # XXX
- &perror("WARN: $file: ".
- ($newport ? 'for new port, '
- : 'is it a new port? if so, ').
- "make \$$rcsidstr\$ tag in comment ".
- "section empty, to make CVS happy.");
- }
- }
- }
- #
- # for the rest of the checks, comment lines are not important.
- #
- for ($i = 0; $i < scalar(@sections); $i++) {
- $sections[$i] = "\n" . $sections[$i];
- $sections[$i] =~ s/\n#[^\n]*//g;
- $sections[$i] =~ s/\n\n+/\n/g;
- $sections[$i] =~ s/\\\n/ /g;
- $sections[$i] =~ s/^\n//;
- }
- #
- #
- # section 2: PORTNAME/PORTVERSION/...
- #
- print "OK: checking first section of $file (PORTNAME/...).\n"
- if ($verbose);
- $tmp = $sections[$idx++];
- # check the order of items.
- &checkorder('PORTNAME', $tmp, $file, qw(
- PORTNAME PORTVERSION PORTREVISION PORTEPOCH CATEGORIES MASTER_SITES
- MASTER_SITE_SUBDIR PKGNAMEPREFIX PKGNAMESUFFIX DISTNAME EXTRACT_SUFX
- DISTFILES DIST_SUBDIR EXTRACT_ONLY
- ));
- # check the items that has to be there.
- $tmp = "\n" . $tmp;
- print "OK: checking PORTNAME/PORTVERSION.\n" if ($verbose);
- if ($tmp !~ /\nPORTNAME(.)?=/) {
- &perror("FATAL: $file: PORTNAME has to be there.") unless ($slaveport && $makevar{PORTNAME} ne '');
- } elsif ($1 ne '') {
- &perror("WARN: $file: unless this is a master port, PORTNAME has to be set by \"=\", ".
- "not by \"$1=\".") unless ($masterport);
- }
- if ($tmp !~ /\nPORTVERSION(.)?=/) {
- &perror("FATAL: $file: PORTVERSION has to be there.") unless ($slaveport && $makevar{PORTVERSION} ne '');
- } elsif ($1 ne '') {
- &perror("WARN: $file: unless this is a master port, PORTVERSION has to be set by \"=\", ".
- "not by \"$1=\".") unless ($masterport);
- }
- if ($newport) {
- print "OK: checking for existence of PORTREVISION in new port.\n"
- if ($verbose);
- if ($tmp =~ /^PORTREVISION(.)?=/m) {
- &perror("WARN: $file: new ports should not set PORTREVISION.");
- }
- }
- if ($newport) {
- print "OK: checking for existence of PORTEPOCH in new port.\n"
- if ($verbose);
- if ($tmp =~ /^PORTEPOCH(.)?=/m) {
- &perror("WARN: $file: new ports should not set PORTEPOCH.");
- }
- }
- print "OK: checking CATEGORIES.\n" if ($verbose);
- if ($tmp !~ /\nCATEGORIES(.)?=/) {
- &perror("FATAL: $file: CATEGORIES has to be there.") unless ($slaveport && $makevar{CATEGORIES} ne '');
- } elsif (($i = $1) ne '' && $i =~ /[^?+]/) {
- &perror("WARN: $file: unless this is a master port, CATEGORIES should be set by \"=\", \"?=\", or \"+=\", ".
- "not by \"$i=\".") unless ($masterport);
- }
- @cat = split(/\s+/, $makevar{CATEGORIES});
- if (@cat == 0) {
- &perror("FATAL: $file: CATEGORIES left blank. set it to \"misc\"".
- " if nothing seems apropriate.");
- }
- if ($committer && $makevar{'.CURDIR'} =~ m'/([^/]+)/[^/]+/?$') {
- if ($cat[0] ne $1 && $makevar{PKGCATEGORY} ne $1 ) {
- &perror("FATAL: $file: category \"$1\" must be listed first");
- }
- }
- #MICHAEL: can these three lang cat checks be combined?
- # skip the first category specification if it's a language specific one.
- if (grep($_ eq $cat[0], @lang_cat)) {
- $has_lang_cat = 1;
- $port_lang = $lang_pref{$cat[0]};
- shift @cat;
- }
-
- # skip further if more language specific ones follow.
- if (@cat && grep($_ eq $cat[0], @lang_cat)) {
- &perror("WARN: $file: multiple language specific categories detected. ".
- "are you sure?");
- do {
- shift @cat;
- } while (@cat && grep($_ eq $cat[0], @lang_cat));
- }
- # check x11 in CATEGORIES
- if ($newxdef) {
- #MICHAEL: I don't understand this line
- if (2 <= @cat && $cat[1] eq "x11") {
- &perror("WARN: $file: only specific kind of apps should ".
- "specify \"x11\" in CATEGORIES. ".
- "Do you mean just USE_XLIB? ".
- "Then remove \"x11\" from CATEGORIES.");
- }
- }
- if (2 <= @cat) {
- # skip the first one that we know is _not_ language specific.
- shift @cat;
-
- # any language specific one after non language specific ones?
- foreach my $cat (@cat) {
- if (grep($_ eq $cat, @lang_cat)) {
- $has_lang_cat = 1;
- $port_lang = $lang_pref{$cat};
- &perror("WARN: $file: when you specify multiple categories, ".
- "language specific category should come first.");
- }
- }
- }
- # check the URL
- if (($tmp =~ /\nMASTER_SITES[+?]?=[ \t]*([^\n]*)\n/
- && $1 !~ /^[ \t]*$/) || ($makevar{MASTER_SITES} ne '')) {
- print "OK: seen MASTER_SITES, sanity checking URLs.\n"
- if ($verbose);
- my @sites = split(/\s+/, $1);
- my $skipnext = 0;
- foreach my $i (@sites) {
- if ($skipnext) {
- $skipnext = 0;
- next;
- }
- $skipnext++ if ($i =~ /^#/);
- if ($i =~ m#^\w+://#) {
- &urlcheck($i, $file);
- unless (&is_predefined($i, $file)) {
- print "OK: URL \"$i\" ok.\n"
- if ($verbose);
- }
- } else {
- print "OK: non-URL \"$i\" ok.\n"
- if ($verbose);
- }
- }
- } else {
- &perror("WARN: $file: no MASTER_SITES found. is it ok?");
- }
- # check DISTFILES and related items.
- $distfiles = $1 if ($tmp =~ /\nDISTFILES[+?]?=[ \t]*([^\n]+)\n/);
- #$portname = $1 if ($tmp =~ /\nPORTNAME[+?]?=[ \t]*([^\n]+)\n/);
- #$portversion = $1 if ($tmp =~ /\nPORTVERSION[+?]?=[ \t]*([^\n]+)\n/);
- $portname = $makevar{PORTNAME};
- $portversion = $makevar{PORTVERSION};
- $distname = $1 if ($tmp =~ /\nDISTNAME[+?]?=[ \t]*([^\n]+)\n/);
- $extractsufx = $1 if ($tmp =~ /\nEXTRACT_SUFX[+?]?=[ \t]*([^\n]+)\n/);
- # check bogus EXTRACT_SUFX.
- if ($extractsufx ne '') {
- print "OK: seen EXTRACT_SUFX, checking value.\n" if ($verbose);
- if ($distfiles ne '') {
- &perror("WARN: $file: no need to define EXTRACT_SUFX if ".
- "DISTFILES is defined.");
- }
- if ($extractsufx eq '.tar.gz') {
- &perror("WARN: $file: EXTRACT_SUFX is \".tar.gz.\" ".
- "by default. you don't need to specify it.");
- }
- } else {
- print "OK: no EXTRACT_SUFX seen, using default value.\n"
- if ($verbose);
- $extractsufx = '.tar.gz';
- }
- print "OK: sanity checking PORTNAME/PORTVERSION.\n" if ($verbose);
- if ($distname ne '' && $distname eq "$portname-$portversion") {
- &perror("WARN: $file: DISTNAME is \${PORTNAME}-\${PORTVERSION} by ".
- "default, you don't need to define DISTNAME.");
- }
- if ($portname =~ /^$re_lang_short/) {
- &perror("FATAL: $file: language prefix is automatically".
- " set by PKGNAMEPREFIX.".
- " you must remove it from PORTNAME.");
- }
- if ($portname =~ /\$[\{\(].+[\}\)]/) {
- &perror("WARN: $file: using variable in PORTNAME.".
- " consider using PKGNAMEPREFIX and/or PKGNAMESUFFIX.");
- } elsif ($portname =~ /-/ && $distname ne '') {
- &perror("WARN: $file: using hyphen in PORTNAME.".
- " consider using PKGNAMEPREFIX and/or PKGNAMESUFFIX.");
- }
- if ($portversion eq '') {
- &perror("FATAL: $file: PORTVERSION must be specified");
- }
- if ($portversion =~ /^pl[0-9]*$/
- || $portversion =~ /^[0-9]*[A-Za-z]?[0-9]*(\.[0-9]*[A-Za-z]?[0-9]*)*$/) {
- print "OK: PORTVERSION \"$portversion\" looks fine.\n" if ($verbose);
- } elsif ($portversion =~ /^[^\-]*\$[{\(].+[\)}][^\-]*$/) {
- &perror("WARN: $file: using variable, \"$portversion\", as version ".
- "number");
- } elsif ($portversion =~ /-/) {
- &perror("FATAL: $file: PORTVERSION should not contain a hyphen.".
- "should modify \"$portversion\".");
- } else {
- &perror("FATAL: $file: PORTVERSION looks illegal. ".
- "should modify \"$portversion\".");
- }
- # 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+$/ && $distfiles !~ /:[^\/:]+$/) {
- $bogusdistfiles++;
- print "OK: seen DISTFILES with single item, checking value.\n"
- if ($verbose);
- &perror("WARN: $file: use of DISTFILES with single file ".
- "discouraged. distribution filename should be set by ".
- "DISTNAME and EXTRACT_SUFX.");
- if ($distfiles eq (($distname ne '') ? $distname : "$portname-$portversion") . $extractsufx) {
- &perror("WARN: $file: definition of DISTFILES not necessary. ".
- "DISTFILES is \${DISTNAME}/\${EXTRACT_SUFX} ".
- "by default.");
- }
- # display advice only in certain cases.
- #MICHAEL: will this work with multiple distfiles in this list? what about
- # doing the same sort of thing for DISTNAME, is it needed?
- if ($distfiles =~ /^\Q$i\E([\-.].+)$/) {
- &perror("WARN: $file: how about \"EXTRACT_SUFX=$1\"".
- ", instead of DISTFILES?");
- }
- }
- # additional checks for committer.
- if ($committer && $has_lang_cat) {
- &perror("WARN: $file: be sure to include language code ".
- "\"$port_lang-\" ".
- "in the module alias name.");
- }
- if ($committer) {
- if (opendir(DIR, ".")) {
- my @tgz = grep(/\.tgz$/, readdir(DIR));
- closedir(DIR);
-
- if (@tgz) {
- my $tgz = (2 <= @tgz)
- ? '{' . join(',', @tgz) . '}'
- : $tgz[0];
-
- &perror("WARN: be sure to remove $portdir/$tgz ".
- "before committing the port.");
- }
- }
- }
- push(@varnames, qw(
- PORTNAME PORTVERSION PORTREVISION PORTEPOCH CATEGORIES MASTER_SITES
- MASTER_SITE_SUBDIR PKGNAMEPREFIX PKGNAMESUFFIX DISTNAME EXTRACT_SUFX
- DISTFILES EXTRACT_ONLY
- ));
- #
- # section 3: PATCH_SITES/PATCHFILES(optional)
- #
- print "OK: checking second section of $file (PATCH*: optional).\n"
- if ($verbose);
- $tmp = $sections[$idx];
- if ($tmp =~ /(PATCH_SITES|PATCH_SITE_SUBDIR|PATCHFILES|PATCH_DIST_STRIP)/) {
- &checkearlier($file, $tmp, @varnames);
- if ($tmp =~ /^PATCH_SITES=/) {
- print "OK: seen PATCH_SITES.\n" if ($verbose);
- $tmp =~ s/^[^\n]+\n//;
- }
- if ($tmp =~ /^PATCH_SITE_SUBDIR=/) {
- print "OK: seen PATCH_SITE_SUBDIR.\n" if ($verbose);
- $tmp =~ s/^[^\n]+\n//;
- }
- if ($tmp =~ /^PATCHFILES=/) {
- print "OK: seen PATCHFILES.\n" if ($verbose);
- $tmp =~ s/^[^\n]+\n//;
- }
- if ($tmp =~ /^PATCH_DIST_STRIP=/) {
- print "OK: seen PATCH_DIST_STRIP.\n" if ($verbose);
- $tmp =~ s/^[^\n]+\n//;
- }
- &checkextra($tmp, 'PATCH_SITES', $file);
- $idx++;
- }
- push(@varnames, qw(
- PATCH_SITES PATCHFILES PATCH_DIST_STRIP
- ));
- #
- # section 4: MAINTAINER
- #
- print "OK: checking third section of $file (MAINTAINER).\n"
- if ($verbose);
- $tmp = $sections[$idx++];
- &checkearlier($file, $tmp, @varnames);
- &checkorder('MAINTAINER', $tmp, $file, qw(
- MAINTAINER COMMENT
- ));
- $tmp = "\n" . $tmp;
- if ($tmp =~ /\nMAINTAINER\??=([^\n]+)/) {
- my $addr = $1;
- $addr =~ s/^\s*//;
- $addr =~ s/\s*$//;
- if ($addr =~ /[\s,<>()]/) {
- &perror("FATAL: $file: MAINTAINER should be a single address without comment.");
- }
- if ($addr !~ /^[^\@]+\@[\w\d\-\.]+$/) {
- &perror("FATAL: $file: MAINTAINER address, $addr, does not appear to be a valid email address.");
- }
- $tmp =~ s/\nMAINTAINER\??=[^\n]+//;
- } elsif ($whole !~ /\nMAINTAINER[?]?=/) {
- &perror("FATAL: $file: no MAINTAINER listed.") unless ($slaveport && $makevar{MAINTAINER} ne '');
- }
- $tmp =~ s/\n\n+/\n/g;
- # check COMMENT
- if ($tmp !~ /\nCOMMENT(.)?=/) {
- &perror("FATAL: $file: COMMENT has to be there.") unless ($slaveport && $makevar{COMMENT} ne '');
- } elsif ($1 ne '') {
- &perror("WARN: $file: unless this is a master port, COMMENT has to be set by \"=\", ".
- "not by \"$1=\".") unless ($masterport);
- } else { # check for correctness
- if (($makevar{COMMENT} !~ /^["0-9A-Z]/) || ($makevar{COMMENT} =~ m/\.$/)) { #"
- &perror("WARN: $file: COMMENT should begin with a capital, and end without a period");
- } elsif (length($makevar{COMMENT}) > 70) {
- &perror("WARN: $file: COMMENT exceeds 70 characters limit.");
- }
- }
- push(@varnames, qw(
- MAINTAINER COMMENT
- ));
- #
- # section 5: *_DEPENDS (may not be there)
- #
- print "OK: checking fourth section of $file (*_DEPENDS).\n"
- if ($verbose);
- $tmp = $sections[$idx];
- # NOTE: EXEC_DEPENDS is obsolete, so it should not be listed.
- @linestocheck = qw(
- EXTRACT_DEPENDS LIB_DEPENDS PATCH_DEPENDS BUILD_DEPENDS RUN_DEPENDS
- FETCH_DEPENDS DEPENDS DEPENDS_TARGET
- );
- if ($tmp =~ /(LIB_|BUILD_|RUN_|FETCH_)?DEPENDS/) {
- &checkearlier($file, $tmp, @varnames);
- my %seen_depends;
- if (!defined $ENV{'PORTSDIR'}) {
- $ENV{'PORTSDIR'} = $portsdir;
- }
- foreach my $i (grep(/^[A-Z_]*DEPENDS[?+]?=/, split(/\n/, $tmp))) {
- $i =~ s/^([A-Z_]*DEPENDS)[?+]?=[ \t]*//;
- $j = $1;
- $seen_depends{$j}++;
- if ($j ne 'DEPENDS' &&
- $i =~ /^\${([A-Z_]+DEPENDS)}\s*$/ &&
- $seen_depends{$1} &&
- $j ne $1)
- {
- print "OK: $j refers to $1, skipping checks.\n"
- if ($verbose);
- next;
- }
- print "OK: checking ports listed in $j.\n"
- if ($verbose);
- foreach my $k (split(/\s+/, $i)) {
- my @l = split(':', $k);
- print "OK: checking dependency value for $j.\n"
- if ($verbose);
- if (($j eq 'DEPENDS'
- && scalar(@l) != 1 && scalar(@l) != 2)
- || ($j ne 'DEPENDS'
- && scalar(@l) != 2 && scalar(@l) != 3)) {
- &perror("WARN: $file: wrong dependency value ".
- "for $j. $j requires ".
- ($j eq 'DEPENDS'
- ? "1 or 2 "
- : "2 or 3 ").
- "colon-separated tuples.");
- next;
- }
- my %m = ();
- if ($j eq 'DEPENDS') {
- $m{'dir'} = $l[0];
- $m{'tgt'} = $l[1];
- } else {
- $m{'dep'} = $l[0];
- $m{'dir'} = $l[1];
- $m{'tgt'} = $l[2];
- }
- print "OK: dep=\"$m{'dep'}\", ".
- "dir=\"$m{'dir'}\", tgt=\"$m{'tgt'}\"\n"
- if ($verbose);
- # check USE_PERL5
- if ($m{'dep'} =~ /^perl5(\.\d+)?$/) {
- &perror("WARN: $file: dependency to perl5 ".
- "listed in $j. consider using ".
- "USE_PERL5.");
- }
- # check USE_GMAKE
- if ($m{'dep'} =~ /^(gmake|\${GMAKE})$/) {
- &perror("WARN: $file: dependency to $1 ".
- "listed in $j. consider using ".
- "USE_GMAKE.");
- }
- # check USE_QT
- if ($m{'dep'} =~ /^(qt\d)+$/) {
- &perror("WARN: $file: dependency to $1 ".
- "listed in $j. consider using ".
- "USE_QT.");
- }
- # check USE_GETOPT_LONG
- if ($m{'dep'} =~ /^(gnugetopt\.\d)+$/) {
- &perror("WARN: $file: dependency to $1 ".
- "listed in $j. consider using ".
- "USE_GETOPT_LONG.");
- }
- # check backslash in LIB_DEPENDS
- if ($osname eq 'NetBSD' && $j eq 'LIB_DEPENDS'
- && $m{'dep'} =~ /\\\\./) {
- &perror("WARN: $file: use of backslashes in ".
- "$j is deprecated.");
- }
- # check for PREFIX
- if ($m{'dep'} =~ /\${PREFIX}/) {
- &perror("FATAL: $file: \${PREFIX} must not be ".
- "contained in *_DEPENDS. ".
- "use \${LOCALBASE} or ".
- "\${X11BASE} instead.");
- }
- # check port dir existence
- $k = $m{'dir'};
- $k =~ s/\${PORTSDIR}/$ENV{'PORTSDIR'}/;
- $k =~ s/\$[\({]PORTSDIR[\)}]/$ENV{'PORTSDIR'}/;
- if (! -d $k) {
- &perror("WARN: $file: no port directory $k ".
- "found, even though it is ".
- "listed in $j.");
- } else {
- print "OK: port directory $k found.\n"
- if ($verbose);
- }
- }
- }
- foreach my $i (@linestocheck) {
- $tmp =~ s/$i[?+]?=[^\n]+\n//g;
- }
- &checkextra($tmp, '*_DEPENDS', $file);
- $idx++;
- }
- push(@varnames, @linestocheck);
- &checkearlier($file, $tmp, @varnames);
- #
- # Makefile 6: check the rest of file
- #
- print "OK: checking the rest of the $file.\n" if ($verbose);
- $tmp = join("\n\n", @sections[$idx .. scalar(@sections)-1]);
- $tmp = "\n" . $tmp; # to make the begin-of-line check easier
- &checkearlier($file, $tmp, @varnames);
- # check WRKSRC/NO_WRKSUBDIR
- #
- # do not use DISTFILES/DISTNAME to control over WRKSRC.
- # DISTNAME is for controlling distribution filename.
- # example:
- # DISTNAME= package
- # DISTFILES=package-1.0.tgz
- # should be
- # DISTNAME= package-1.0
- # EXTRACT_SUFX=.tgz
- # WRKSRC= ${WRKDIR}/package
- #
- print "OK: checking WRKSRC.\n" if ($verbose);
- $wrksrc = $nowrksubdir = '';
- $wrksrc = $1 if ($tmp =~ /\nWRKSRC[+?]?=[ \t]*([^\n]*)\n/);
- $nowrksubdir = $1 if ($tmp =~ /\nNO_WRKSUBDIR[+?]?=[ \t]*([^\n]*)\n/);
- if ($nowrksubdir eq '') {
- $realwrksrc = $wrksrc ? "$wrksrc/$distname"
- : "\${WRKDIR}/$distname";
- } else {
- $realwrksrc = $wrksrc ? $wrksrc : '${WRKDIR}';
- }
- print "OK: WRKSRC seems to be $realwrksrc.\n" if ($verbose);
- if ($nowrksubdir eq '') {
- print "OK: no NO_WRKSUBDIR, checking value of WRKSRC.\n"
- if ($verbose);
- if ($wrksrc eq 'work' || $wrksrc =~ /^$[\{\(]WRKDIR[\}\)]/) {
- &perror("WARN: $file: WRKSRC is set to meaningless value ".
- "\"$1\".".
- ($nowrksubdir eq ''
- ? " use \"NO_WRKSUBDIR=yes\" instead."
- : ""));
- }
- if ($bogusdistfiles) {
- if ($distname ne '' && $wrksrc eq '') {
- &perror("WARN: $file: do not use DISTFILES and DISTNAME ".
- "to control WRKSRC. how about ".
- "\"WRKSRC=\${WRKDIR}/$distname\"?");
- } else {
- &perror("WARN: $file: DISTFILES/DISTNAME affects WRKSRC. ".
- "take caution when changing them.");
- }
- }
- } else {
- print "OK: seen NO_WRKSUBDIR, checking value of WRKSRC.\n"
- if ($verbose);
- if ($wrksrc eq 'work' || $wrksrc =~ /^$[\{\(]WRKDIR[\}\)]/) {
- &perror("WARN: $file: definition of WRKSRC not necessary. ".
- "WRKSRC is \${WRKDIR} by default.");
- }
- }
- # check RESTRICTED/NO_CDROM/NO_PACKAGE
- print "OK: checking RESTRICTED/NO_CDROM/NO_PACKAGE.\n" if ($verbose);
- if ($committer && $tmp =~ /\n(RESTRICTED|NO_CDROM|NO_PACKAGE)[+?]?=/) {
- &perror("WARN: $file: \"$1\" found. do not forget to update ".
- "ports/LEGAL.");
- }
- # check NO_CONFIGURE/NO_PATCH
- print "OK: checking NO_CONFIGURE/NO_PATCH.\n" if ($verbose);
- if ($tmp =~ /\n(NO_CONFIGURE|NO_PATCH)[+?]?=/) {
- &perror("FATAL: $file: \"$1\" was obsoleted. remove this.");
- }
- # check MAN[1-9LN]
- print "OK: checking MAN[0-9LN].\n" if ($verbose);
- foreach my $i (keys %plistmanall) {
- print "OK: pkg-plist MAN$i=$plistmanall{$i}\n" if ($verbose);
- }
- foreach my $i (split(//, $manchapters)) {
- if ($tmp =~ /MAN\U$i\E=\s*([^\n]*)\n/) {
- print "OK: Makefile MAN\U$i\E=$1\n" if ($verbose);
- }
- }
- foreach my $i (split(//, $manchapters)) {
- next if ($i eq '');
- if ($tmp =~ /MAN\U$i\E=\s*([^\n]*)\n/) {
- @mman = grep($_ !~ /^\s*$/, split(/\s+/, $1));
- @pman = grep($_ !~ /^\s*$/,
- split(/\s+/, $plistmanall{$i}));
- foreach my $j (@mman) {
- print "OK: checking $j (Makefile)\n"
- if ($verbose);
- if ($automan && grep($_ eq $j, @pman)) {
- &perror("FATAL: $file: duplicated manpage ".
- "entry $j: content of ".
- "MAN\U$i\E will be automatically ".
- "added to pkg-plist.");
- } elsif (!$automan && !grep($_ eq $j, @pman)) {
- &perror("WARN: $file: manpage $j ".
- "MAN\U$i\E but not in pkg-plist.");
- }
- }
- foreach my $j (@pman) {
- print "OK: checking $j (pkg-plist)\n" if ($verbose);
- if (!grep($_ eq $j, @mman)) {
- &perror("WARN: $file: manpage $j in pkg-plist ".
- "but not in MAN\U$i\E.");
- }
- }
- } else {
- if ($plistmanall{$i}) {
- if ($manstrict) {
- &perror("FATAL: $file: manpage for chapter ".
- "$i must be listed in ".
- "MAN\U$i\E. ");
- } else {
- &perror("WARN: $file: manpage for chapter ".
- "$i should be listed in ".
- "MAN\U$i\E, ".
- "even if compression is ".
- "not necessary.");
- }
- }
- if ($mancompress && $plistman{$i}) {
- &perror("WARN: $file: MAN\U$i\E will help you ".
- "compressing manual page in chapter ".
- "\"$i\".");
- } elsif (!$mancompress && $plistmangz{$i}) {
- &perror("WARN: $file: MAN\U$i\E will help you ".
- "uncompressing manual page in chapter ".
- "\"$i\".");
- }
- }
- }
- if ($tmp !~ /MANLANG/ && scalar(keys %manlangs)) {
- $i = (keys %manlangs)[0];
- &perror("WARN: $file: how about using MANLANG for ".
- "designating manual language, such as \"$i\"?");
- }
- # check INFO
- print "OK: checking INFO.\n" if ($verbose);
- if ($autoinfo && $tmp =~ /\nINFO=\s*([^\n]*)\n/) {
- my @minfo = grep($_ !~ /^\s*$/, split(/\s+/, $1));
- foreach $i (@minfo) {
- if ($i =~ /\.info(-\d+)?$/) {
- &perror("FATAL: $file: do not include the .info extension ".
- "on files listed in the INFO macro.");
- }
- }
- }
- # check USE_X11 and USE_IMAKE
- if ($tmp =~ /\nUSE_IMAKE[?+]?=/
- && $tmp =~ /\n(USE_X11)[?+]?=/) {
- &perror("WARN: $file: since you already have USE_IMAKE, ".
- "you don't need $1.");
- }
- # check USE_X11 and USE_IMAKE
- if ($newxdef && $tmp =~ /\nUSE_IMAKE[?+]?=/
- && $tmp =~ /\n(USE_X_PREFIX)[?+]?=/) {
- &perror("WARN: $file: since you already have USE_IMAKE, ".
- "you don't need $1.");
- }
- # check USE_X11 and USE_X_PREFIX
- if ($newxdef && $tmp =~ /\nUSE_X11[?+]?=/
- && $tmp !~ /\nUSE_X_PREFIX[?+]?=/) {
- &perror("FATAL: $file: meaning of USE_X11 was changed in Aug 1998. ".
- "use USE_X_PREFIX instead.");
- }
- # check direct use of important make targets.
- if ($tmp =~ /\n(fetch|extract|patch|configure|build|install):/) {
- &perror("FATAL: $file: direct redefinition of make target \"$1\" ".
- "discouraged. redefine \"do-$1\" instead.");
- }
- # check for incorrect use of the pre-everything target.
- if ($tmp =~ /\npre-everything:[^:]/) {
- &perror("FATAL: $file: use pre-everything:: instead of pre-everything:");
- }
- if ($tmp =~ /^pre-patch:/m && $use_gnome_hack) {
- &perror("FATAL: $file: pre-patch target overwrites gnomehack component. ".
- "use post-patch instead.");
- }
- 1;
- }
- sub perror {
- my(@msg) = @_;
- if ($msg[0] =~ /^FATAL/) {
- $err++;
- } else {
- $warn++;
- }
- print join("\n", @msg) . "\n";
- }
- sub checkextra {
- my($str, $section, $file) = @_;
- $str = "\n" . $str if ($str !~ /^\n/);
- $str =~ s/\n#[^\n]*/\n/g;
- $str =~ s/\n\.[^\n]+/\n/g;
- $str =~ s/\n\n+/\n/g;
- $str =~ s/^\s+//;
- $str =~ s/\s+$//;
- return if ($str eq '');
- if ($str =~ /^([\w\d]+)/) {
- &perror("WARN: $file: extra item placed in the ".
- "$section section, ".
- "for example, \"$1\".");
- } else {
- &perror("WARN: $file: extra item placed in the ".
- "$section section.");
- }
- }
- sub checkorder {
- my($section, $str, $file, @order) = @_;
- my(@items, $i, $j, $k, $invalidorder);
- print "OK: checking the order of $section section.\n" if ($verbose);
- @items = ();
- foreach my $i (split("\n", $str)) {
- $i =~ s/[+?]?=.*$//;
- push(@items, $i);
- }
- @items = reverse(@items);
- $j = -1;
- $invalidorder = 0;
- while (scalar(@items)) {
- $i = pop(@items);
- $k = 0;
- while ($k < scalar(@order) && $order[$k] ne $i) {
- $k++;
- }
- if ($order[$k] eq $i) {
- if ($k < $j) {
- &perror("FATAL: $file: $i appears out-of-order.");
- $invalidorder++;
- } else {
- print "OK: seen $i, in order.\n" if ($verbose);
- }
- $j = $k;
- # This if condition tests for .if, .else (in all forms),
- # .for and .endfor and .include
- } elsif ($i !~ m/^\.(if|el|endif|for|endfor|include)/) {
- &perror("FATAL: $file: extra item \"$i\" placed in the ".
- "$section section.");
- }
- }
- if ($invalidorder) {
- &perror("FATAL: $file: order must be " . join('/', @order) . '.');
- } else {
- print "OK: $section section is ordered properly.\n"
- if ($verbose);
- }
- }
- sub checkearlier {
- my($file, $str, @varnames) = @_;
- my($i);
- print "OK: checking items that has to appear earlier.\n" if ($verbose);
- foreach my $i (@varnames) {
- if ($str =~ /\n$i\??=/) {
- &perror("WARN: $file: \"$i\" has to appear earlier.");
- }
- }
- }
- sub linenumber {
- my $text = shift;
- my @lines;
- @lines = split /\n/, $text;
- return scalar(@lines);
- }
- sub abspathname {
- my($str, $file) = @_;
- my($s, $i, %cmdnames);
- my($pre);
- # ignore parameter string to echo command
- $str =~ s/[ \t][\@-]?(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+("(\\'|\\"|[^"])*"|'(\\'|\\"|[^"])*')[ \t]*[;\n]//; #'
- print "OK: checking direct use of full pathnames in $file.\n"
- if ($verbose);
- foreach my $s (split(/\n+/, $str)) {
- $i = '';
- if ($s =~ /(^|[ \t\@'"-])(\/[\w\d])/) { #'
- # suspected pathnames are recorded.
- $i = $2 . $';
- $pre = $` . $1;
- if ($pre =~ /MASTER_SITE_SUBDIR/) {
- # MASTER_SITE_SUBDIR lines are ok.
- $i = '';
- }
- }
- if ($i ne '') {
- $i =~ s/\s.*$//;
- $i =~ s/['"].*$//; #'
- $i = substr($i, 0, 20) . '...' if (20 < length($i));
- &perror("WARN: $file: possible use of absolute pathname ".
- "\"$i\".") unless ($i =~ m,^/compat/,);
- }
- }
- print "OK: checking direct use of pathnames, phase 1.\n" if ($verbose);
- %cmdnames = split(/\n|\t+/, <<EOF);
- /usr/opt \${PORTSDIR} instead
- $portsdir \${PORTSDIR} instead
- $localbase \${PREFIX} or \${LOCALBASE}, as appropriate
- /usr/X11 \${PREFIX} or \${X11BASE}, as appropriate
- EOF
- foreach my $i (keys %cmdnames) {
- if ($str =~ /$i/) {
- &perror("WARN: $file: possible direct use of \"$&\" ".
- "found. if so, use $cmdnames{$i}.");
- }
- }
- print "OK: checking direct use of pathnames, phase 2.\n" if ($verbose);
- %cmdnames = split(/\n|\t+/, <<EOF);
- distfiles \${DISTDIR} instead
- pkg \${PKGDIR} instead
- files \${FILESDIR} instead
- scripts \${SCRIPTDIR} instead
- patches \${PATCHDIR} instead
- work \${WRKDIR} instead
- EOF
- foreach my $i (keys %cmdnames) {
- if ($str =~ /(\.\/|\$[\{\(]\.CURDIR[\}\)]\/|[ \t])(\b$i)\//) {
- &perror("WARN: $file: possible direct use of \"$i\" ".
- "found. if so, use $cmdnames{$i}.");
- }
- }
- }
- sub is_predefined {
- my($url, $file) = @_;
- my($site, $site_re);
- my $subdir_re = quotemeta quotemeta '/%SUBDIR%/';
- for my $site (keys %predefined) {
- $site_re = quotemeta $site;
- $site_re =~ s,$subdir_re,/(.*)/,;
- if ($url =~ /$site_re/) {
- &perror("WARN: $file: how about using ".
- "\"\${MASTER_SITE_$predefined{$site}}\" with ".
- "\"MASTER_SITE_SUBDIR=$1\", instead of \"$url\"?");
- return &TRUE;
- }
- }
- undef;
- }
- sub urlcheck {
- my ($url, $file) = @_;
- if ($url !~ m#^\w+://#) {
- &perror("WARN: $file: \"$url\" doesn't appear to be a URL to me.");
- }
- if ($url !~ m#/(:[^/:]+)?$#) {
- &perror("FATAL: $file: URL \"$url\" should ".
- "end with \"/\" or a group name (e.g. :something).");
- }
- if ($url =~ m#://[^/]*:/#) {
- &perror("FATAL: $file: URL \"$url\" contains ".
- "extra \":\".");
- }
- if ($osname == 'FreeBSD' && $url =~ m#(www\.freebsd\.org)/~.+/#i) {
- &perror("WARN: $file: URL \"$url\", ".
- "$1 should be ".
- "people.FreeBSD.org");
- }
- }
- sub TRUE {1;}
- # Local variables:
- # tab-width: 4
- # End:
|