diff options
Diffstat (limited to 'pkgtools/pkglint')
-rw-r--r-- | pkgtools/pkglint/Makefile | 47 | ||||
-rw-r--r-- | pkgtools/pkglint/files/CHANGELOG | 139 | ||||
-rw-r--r-- | pkgtools/pkglint/files/lintpkgsrc.sh | 31 | ||||
-rw-r--r-- | pkgtools/pkglint/files/pkglint.1 | 128 | ||||
-rw-r--r-- | pkgtools/pkglint/files/pkglint.pl | 1275 | ||||
-rw-r--r-- | pkgtools/pkglint/files/plist-clash.pl | 98 | ||||
-rw-r--r-- | pkgtools/pkglint/pkg/COMMENT | 1 | ||||
-rw-r--r-- | pkgtools/pkglint/pkg/DESCR | 10 | ||||
-rw-r--r-- | pkgtools/pkglint/pkg/PLIST | 6 |
9 files changed, 1735 insertions, 0 deletions
diff --git a/pkgtools/pkglint/Makefile b/pkgtools/pkglint/Makefile new file mode 100644 index 00000000000..ac41d552397 --- /dev/null +++ b/pkgtools/pkglint/Makefile @@ -0,0 +1,47 @@ +# $NetBSD: Makefile,v 1.1 1998/08/07 22:11:40 tsarna Exp $ +# + +DISTNAME= pkglint-1.65 +CATEGORIES= devel +MASTER_SITES= # empty +DISTFILES= # empty + +MAINTAINER= frueauf@netbsd.org + +USE_PERL5= YES + +EXTRACT_ONLY= # empty +NO_WRKSUBDIR= yes +NO_CHECKSUM= yes +NO_PATCH= yes +NO_CONFIGURE= yes + +MAKE_ENV= PKGSRCDIR=${.CURDIR}/../.. + +do-build: + ${SED} -e 's|@PREFIX@|${PREFIX}|g' \ + -e 's|@PORTSDIR@|${PKGSRCDIR}|g' \ + < ${FILESDIR}/pkglint.pl \ + > ${WRKSRC}/pkglint + ${SED} -e 's|@PREFIX@|${PREFIX}|g' \ + -e 's|@PORTSDIR@|${PKGSRCDIR}|g' \ + < ${FILESDIR}/lintpkgsrc.sh \ + > ${WRKSRC}/lintpkgsrc + ${SED} -e 's|@PREFIX@|${PREFIX}|g' \ + -e 's|@PORTSDIR@|${PKGSRCDIR}|g' \ + < ${FILESDIR}/plist-clash.pl \ + > ${WRKSRC}/plist-clash + ${SED} -e 's|@PREFIX@|${PREFIX}|g' \ + -e 's|@PORTSDIR@|${PKGSRCDIR}|g' \ + < ${FILESDIR}/pkglint.1 \ + > ${WRKSRC}/pkglint.1 + nroff -mandoc ${WRKSRC}/pkglint.1 >${WRKSRC}/pkglint.0 + +do-install: + ${INSTALL_SCRIPT} ${WRKSRC}/pkglint ${PREFIX}/bin/pkglint + ${INSTALL_SCRIPT} ${WRKSRC}/lintpkgsrc ${PREFIX}/bin/lintpkgsrc + ${INSTALL_SCRIPT} ${WRKSRC}/plist-clash ${PREFIX}/bin/plist-clash + ${INSTALL_MAN} ${WRKSRC}/pkglint.1 ${PREFIX}/man/man1 + ${INSTALL_MAN} ${WRKSRC}/pkglint.0 ${PREFIX}/man/cat1 + +.include "../../mk/bsd.pkg.mk" diff --git a/pkgtools/pkglint/files/CHANGELOG b/pkgtools/pkglint/files/CHANGELOG new file mode 100644 index 00000000000..5f85a8683da --- /dev/null +++ b/pkgtools/pkglint/files/CHANGELOG @@ -0,0 +1,139 @@ +$NetBSD: CHANGELOG,v 1.1 1998/08/07 22:13:43 tsarna Exp $ + +TODO + - report line# for each errors/warnings in Makefile + (need a complete rewrite) + +--- + +r1.65 Fri Aug 7 14:43:24 CDT 1998 + - Rename to pkglint + - apply patches to sources and keep files under ${FILESDIR}. + We're diverged too much to share this well, so we might as + well keep the sources in-tree and under CVS control. + +r1.64 Sat Feb 28 11:34:13 JST 1998 + - manpage checks (Hubert Feyrer) + - FreeBSD/NetBSD support (Hubert Feyrer) + - PKGNAME check for packages/Latest (satoshi) + +r1.63 Mon Jan 19 10:27:11 JST 1998 + - install-info related fix (thanks satoshi) + - display RCS tag in patches/* (thanks goes to Hubert Feyrer, for the + rest of the items) + - RCS tag is configurable + - PORTSDIR (/usr/ports) is configurable + - extra colon in URL + - USE_GMAKE + +r1.62 Thu Dec 18 12:36:09 JST 1997 + - info/dir should not be listed in pkg/PLIST. (thanks satoshi) + +r1.61 Tue Nov 25 20:41:55 JST 1997 + - checks improved for comments in Makefile. + - add check for PKG_DIST_STRIP. (thanks satoshi) + +r1.60 Thu Nov 20 12:20:41 JST 1997 + - show the line # on check for contiguous blank lines (thanks goes to + fenner@freebsd) + - *_DEPENDS ordering check improved (thanks satoshi) + +r1.59 Thu Nov 13 22:29:30 JST 1997 + - "-B #" allowed as well as "-B#" + - pkg/COMMENT has to be 70 chars (previously, check was for 80 chars) + - EXTRACT_SUFX unnecessery if DISTFILES is defined. + (thanks sheldonh@axl.iafrica.com) + +r1.58 Tue Nov 11 09:05:16 JST 1997 + - option -B#: set # of contiguous blank lines allowed + - warn on distfile improved (to some extent) + - Id string check improved. + +r1.57 Sun Nov 9 09:28:54 JST 1997 + - fixed RCS ident string check (Id, History and others) + - blank lines check (thanks goes to obrien@nuxi.com) + +r1.56 Wed Nov 5 11:10:56 JST 1997 + - warn for emacs backup file (committers mode) + - warn for *.orig and *.rej (committers mode) + +r1.55 Mon Oct 13 20:27:56 JST 1997 + - accept DEPENDS_TARGET in *_DEPENDS section (input from satoshi) + +r1.54 Sun Oct 12 09:20:40 JST 1997 + - predefined URLs check fix (info from obrien@nuxi.com) + +r1.52 Wed Oct 8 23:21:39 JST 1997 + - check ${MKDIR} -p + +r1.51 Wed Oct 8 07:57:50 JST 1997 + - generate output to stdout. (we may have to think again about it) + - DISTNAME/CATEGORIES has to be there. disallow "?=". + +r1.50 Sun Sep 21 11:07:37 JST 1997 + - typo + +r1.49 Sun Sep 21 11:03:28 JST 1997 + - check for ports listed in *_DEPENDS + +r1.48 Sun Sep 14 23:23:58 JST 1997 + - USE_IMAKE includes USE_X11, so you can omit USE_X11 + - use of make target "fetch" or "install" discouraged. + use "do-fetch" or "do-install" for override. + - check full pathname in pkg/PLIST + +r1.46 Tue Aug 12 11:45:26 JST 1997 + - pkg/PLIST checker fix + +r1.45 Tue Aug 12 10:57:39 JST 1997 + - simple typo fixes + +r1.44 Fri Aug 8 15:20:01 JST 1997 + - bug fix: install-info in pkg/PLIST + +r1.43 Mon Aug 4 10:17:19 JST 1997 + - removed stupid debug message + +r1.42 Thu Jul 31 23:18:16 JST 1997 + - omit checks for parameter to "echo" command + +r1.41 Wed Jul 30 09:43:50 JST 1997 + - fixes on glob (thanks arai-san) + - fixes on direct pathname detection (thanks arai-san) + +r1.40 Mon Jul 28 11:28:23 JST 1997 + - fixes on pkg/* check + - fixes on WRKSRC checks + - check for empty trailing lines in various files + - check for RCS tag (need to commit as binary file) + +r1.39 Mon Jul 21 08:03:48 JST 1997 + - enhancement to comitter mode + +r1.37 Fri Jul 18 00:00:42 JST 1997 + - check for uncompressed man files (MAN[1-9NL]) + - check for localized man files path (MANLANG) + - check for "@unexec install-info --delete" and "@exec install-info" + - check for PKGNAME suffix ("1.2.1" in "foobaa-1.2.1") + - tiny fix to *_DEPENDS section + +r1.33 Wed Jul 16 02:21:03 JST 1997 + - added -c option: committer mode + - added check for RESTRICTED/NO_CDROM/NO_PACKAGES + +r1.31 + - check existence of files/md5 + +r1.30 + - check empty MASTER_SITES + +r1.29 + - pkg/DESCR restriction change: 20lines -> 24lines + +r1.26 + - added -b option: warn $(FOOBAA) + +r1.23 + - check for DISTNAME/PKGNAME/DISTFILES + +r1.1 6/13/97 diff --git a/pkgtools/pkglint/files/lintpkgsrc.sh b/pkgtools/pkglint/files/lintpkgsrc.sh new file mode 100644 index 00000000000..c2128c97a43 --- /dev/null +++ b/pkgtools/pkglint/files/lintpkgsrc.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# $NetBSD: lintpkgsrc.sh,v 1.1 1998/08/07 22:13:43 tsarna Exp $ + +PORTLINT=@PREFIX@/bin/portlint +PORTLINTFLAGS="-a -b -c -v" + +cd @PORTSDIR@ +for i in * +do + if [ -d $i/. -a $i != distfiles -a $i != packages ]; then + cd $i + for j in * + do + if [ -d $j/. -a $j != "CVS" -a $j != "pkg" ]; then + ${PORTLINT} ${PORTLINTFLAGS} $j \ + | grep -v '^OK' \ + | grep -v '^WARN: be sure to cleanup .*/work before committing the port' \ + | grep -v '^WARN: is it a new port' \ + >tmp$$ + if [ `cat tmp$$ | wc -l` -gt 1 ]; then + echo "" + echo "===> $i/$j" + echo ${PORTLINT} ${PORTLINTFLAGS} $j + cat tmp$$ + fi + rm -f tmp$$ + fi + done + cd .. + fi +done diff --git a/pkgtools/pkglint/files/pkglint.1 b/pkgtools/pkglint/files/pkglint.1 new file mode 100644 index 00000000000..990746b1b13 --- /dev/null +++ b/pkgtools/pkglint/files/pkglint.1 @@ -0,0 +1,128 @@ +.\" $NetBSD: pkglint.1,v 1.1 1998/08/07 22:13:43 tsarna Exp $ +.\" From FreeBSD: portlint.1,v 1.8 1997/11/25 14:53:14 itojun Exp +.\" +.\" Copyright (c) 1997 by Jun-ichiro Itoh <itojun@itojun.org>. +.\" All Rights Reserved. Absolutely no warranty. +.\" +.Dd July 11, 1997 +.Dt PKGLINT 1 +.Sh NAME +.Nm pkglint +.Nd a verifier for pkgsrc directories +.Sh SYNOPSIS +.Nm pkglint +.Op Fl abchvN +.Op Fl B Ar n +.Op Ar dir +.Sh DESCRIPTION +.Nm +tries to verify the content of a pkgsrc directory. +The purpose of +.Nm +can be separated into two parts: +.Pq 1 +to let the submitters easily polish her/his own pkgsrc directory, and +.Pq 2 +to decrease the labor of the committers. +.Pp +.Nm +uses very simple regular-expression matching for verifying +files that make up a pkgsrc directory. +Note that it does NOT implement complete parser for those files. +Because of this the user may see some extra warnings, +especially when checking complex +.Pa Makefile Ns No s . +.Pp +.Sy Options +.Bl -tag -width Fl +.It Fl a +Perform additional checks for extra files, such as +.Pa scripts/* +and +.Pa pkg/* . +.It Fl b +Warn the use of +.Pa $(VARIABLE) . +Some of the committers prefer +.Pa ${VARIABLE} +instead of +.Pa $(VARIABLE) , +even though they are semantically same. +.It Fl c +Committer flag. +It will add several checks useful only for committers. +If you are a committer and performing check just before commiting a port, +use this option. +.It Fl h +Show the summary of command line options, then exit. +.It Fl v +Be verbose. +Show the progress report for items that are being checked. +.It Fl N +New pkg flag. +Adds several checks specific to newly submitted pkg. +If you are willing to submit the directory to be checked as a new pkg, +use this option. +.It Fl B Ar n +Set the number of contiguous blank lines allowed in +.Pa Makefile +to +.Ar n . +(by default, +.Ar n +is 1) +.It dir +The pkgsrc directory to be checked. +If omitted, check will be performed over the current directory. +.El +.Sh DIAGNOSTICS +Messages will be sent to standard output, not standard error output. +.Bl -tag -width WARN: foobaa +.It FATAL: ... +This type of error messages suggest that there is some fatal error +in the pkgsrc directory. +For example, if some files need a rewrite, or if +some inevitable files are missing, this message will show up. +This kind of errors should be avoided BEFORE submitting +a pkgsrc via send-pr to the comitters. +.\"If a submitter submit it without update, committers will need to rewrite +.\"on behalf of the submitters, which may result in delay of +.\"the development of operating system itself. +.It WARN: ... +This type of error messages suggest that some files may (or may not) +need some fixes. +Basically, warnings are produced when +.Nm +is not completely sure about the result. +For example, complex +.Pa Makefile Ns No s +may need some statements that can match the regular expression +.Nm +uses for sanity checks. +In those cases, the user should evaluate the result manually, +and obey/ignore the result. +.It OK: ... +This type of messages are used in verbose mode +.Pq Fl v . +.El +.Sh FILES +.Bl -tag -width /usr/share/mk/bsd.port.mk -compact +.\".It FreeBSD: +.\".It Pa /usr/share/mk/bsd.port.mk +.\"master Makefile for ports +.\".It Pa /usr/ports/* +.\"port collection +.\".Pp +.\".It NetBSD: +.It Pa /usr/pkgsrc/mk/bsd.pkg.mk +master Makefile for pkgsrc +.It Pa /usr/pkgsrc/* +pkgsrc collection +.Sh AUTHORS +Jun-ichiro Itoh <itojun@itojun.org> +and +Yoshishige Arai <ryo2@on.rim.or.jp>. +Many people has contributed patches and comments/suggestions. +.Sh BUGS +.Nm +is not a magic wand, as described above. diff --git a/pkgtools/pkglint/files/pkglint.pl b/pkgtools/pkglint/files/pkglint.pl new file mode 100644 index 00000000000..3da98c4f9c7 --- /dev/null +++ b/pkgtools/pkglint/files/pkglint.pl @@ -0,0 +1,1275 @@ +#!@PREFIX@/bin/perl +# +# portlint - lint for port directory +# implemented by: +# Jun-ichiro itojun Itoh <itojun@itojun.org> +# Yoshishige Arai <ryo2@on.rim.or.jp> +# visit ftp://ftp.foretune.co.jp/pub/tools/portlint/ for latest version. +# +# Copyright(c) 1997 by Jun-ichiro Itoh <itojun@itojun.org>. +# 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.1 1998/08/07 22:13:44 tsarna Exp $ +# +# This version contains some changes necessary for NetBSD packages +# done by Hubert Feyrer <hubertf@netbsd.org> and +# Thorsten Frueauf <frueauf@netbsd.org> +# + +$err = $warn = 0; +$extrafile = $parenwarn = $committer = $verbose = $newport = 0; +$contblank = 1; +$portdir = '.'; + +# default setting - for FreeBSD +$portsdir = '/usr/ports'; +$rcsidstr = 'Id'; +$multiplist = 0; +$ldconfigwithtrue = 0; +$rcsidinplist = 0; +$mancompress = 1; +$manstrict = 0; +$manchapters = '123456789ln'; +$localbase = "/usr/local"; + +#select(STDERR); +while (@ARGV > 0) { + $_ = shift; + /^-h/ && do { + ($prog) = ($0 =~ /([^\/]+)$/); + print STDERR <<EOF; +usage: $prog [-abcvN] [-B#] [port_directory] + -a additional check for scripts/* and pkg/* + -b warn \$(VARIABLE) + -c committer mode + -v verbose mode + -N writing a new port + -B# allow # contiguous blank lines (default: $contblank line) +EOF + exit 0; + }; + /^-a/ && do {$extrafile = 1; next;}; + /^-b/ && do {$parenwarn = 1; next;}; + /^-c/ && do {$committer = 1; next;}; + /^-v/ && do {$verbose = 1; next;}; + /^-N/ && do {$newport = 1; next;}; + /^-B(\d+)$/ && do { $contblank = $1; next; }; + @ARGV > 0 && /^-B$/ && do { + $contblank = shift; + if ($contblank !~ /^\d+$/) { + print STDERR "FATAL: -B must come with number.\n"; + exit 1; + } + next; + }; + $portdir = $_; +} + +# OS dependent configs +# os portsdir rcsid mplist ldcfg plist-rcsid mancompresss strict localbase +@osdep = split(/\n/, <<EOF); +FreeBSD /usr/ports Id 0 0 0 1 0 /usr/local +NetBSD @PORTSDIR@ NetBSD 1 1 1 0 1 @PREFIX@ +EOF +$osname = `uname -s`; +$osname =~ s/\n$//; +foreach $i (@osdep) { + if ($i =~ /^$osname\t(.*)/) { + print "OK: found OS config for $osname.\n" if ($verbose); + ($portsdir, $rcsidstr, $multiplist, $ldconfigwithtrue, + $rcsidinplist, $mancompress, $manstrict, $localbase) + = split(/\t+/, $1); + last; + } +} +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; +} + +# +# variables for global checks. +# +$sharedocused = 0; +%plistmanall = (); +%plistmangz = (); +%plistman = (); +%manlangs = (); + +%predefined = (); +foreach $i (split("\n", <<EOF)) { +XCONTRIB ftp://ftp.x.org/contrib/ +XCONTRIB ftp://crl.dec.com/pub/X11/contrib/ +GNU ftp://prep.ai.mit.edu/pub/gnu/ +GNU ftp://wuarchive.wustl.edu/systems/gnu/ +PERL_CPAN ftp://ftp.digital.com/pub/plan/perl/CPAN/modules/by-module/ +PERL_CPAN ftp://ftp.cdrom.com/pub/perl/CPAN/modules/by-module/ +TEX_CTAN ftp://ftp.cdrom.com/pub/tex/ctan/ +TEX_CTAN ftp://wuarchive.wustl.edu/packages/TeX/ +TEX_CTAN ftp://ftp.funet.fi/pub/TeX/CTAN/ +TEX_CTAN ftp://ftp.tex.ac.uk/public/ctan/tex-archive/ +TEX_CTAN ftp://ftp.dante.de/tex-archive/ +SUNSITE ftp://sunsite.unc.edu/pub/Linux/ +SUNSITE ftp://ftp.infomagic.com/pub/mirrors/linux/sunsite/ +SUNSITE ftp://ftp.funet.fi/pub/mirrors/sunsite.unc.edu/pub/Linux/ +EOF + ($j, $k) = split(/\t+/, $i); + $predefined{$k} = $j; +} + +# +# check for files. +# +@checker = ('pkg/COMMENT', 'pkg/DESCR', 'Makefile', 'files/md5'); +%checker = ('pkg/COMMENT', 'checkdescr', + 'pkg/DESCR', 'checkdescr', 'Makefile', 'checkmakefile', + 'files/md5', 'TRUE'); +if ($extrafile) { + foreach $i ((<$portdir/scripts/*>, <$portdir/pkg/*>)) { + next if (! -T $i); + $i =~ s/^\Q$portdir\E\///; + next if (defined $checker{$i}); + if ($i =~ /pkg\/PLIST$/ || + ($multiplist && $i =~ /pkg\/PLIST/)) { + unshift(@checker, $i); + $checker{$i} = 'checkplist'; + } else { + push(@checker, $i); + $checker{$i} = 'checkpathname'; + } + } +} +foreach $i (<$portdir/patches/patch-??>) { + next if (! -T $i); + $i =~ s/^\Q$portdir\E\///; + next if (defined $checker{$i}); + push(@checker, $i); + $checker{$i} = 'checkpatch'; +} +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("Cannot open the file $i\n"); + if ($i !~ /^patches\//) { + &checklastline($i) + || &perror("Cannot open the file $i\n"); + } + } +} +if ($committer) { + if (scalar(@_ = <$portdir/work/*>) || -d "$portdir/work") { + &perror("WARN: be sure to cleanup $portdir/work ". + "before committing the port."); + } + if (scalar(@_ = <$portdir/*/*~>) || scalar(@_ = <$portdir/*~>)) { + &perror("WARN: for safety, be sure to cleanup ". + "emacs backup files before committing the port."); + } + 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 port."); + } +} +if ($err || $warn) { + print "$err fatal errors and $warn warnings found.\n" +} else { + print "looks fine.\n"; +} +exit $err; + +# +# pkg/COMMENT, pkg/DESCR +# +sub checkdescr { + local($file) = @_; + local(%maxchars) = ('pkg/COMMENT', 70, 'pkg/DESCR', 80); + local(%maxlines) = ('pkg/COMMENT', 1, 'pkg/DESCR', 24); + local(%errmsg) = ('pkg/COMMENT', "must be one-liner.", + 'pkg/DESCR', "exceeds $maxlines{'pkg/DESCR'} ". + "lines, make it shorter if possible."); + local($longlines, $linecnt, $tmp) = (0, 0, ""); + + open(IN, "< $portdir/$file") || return 0; + while (<IN>) { + $linecnt++; + $longlines++ if ($maxchars{$file} < length($_)); + $tmp .= $_; + } + 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: $i includes lines that exceed $maxchars{$file} ". + "charactors."); + } + if ($tmp =~ /[\033\200-\377]/) { + &perror("WARN: pkg/DESCR includes iso-8859-1, or ". + "other local characters. $file should be". + "plain ascii file."); + } + close(IN); +} + +# +# pkg/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 (<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 ($_ =~ /^\@/) { + 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 = $. + if (($osname ne "NetBSD") || ("$1" eq "%D/bin/")); + # On NetBSD, we enforce %D/bin/... + } elsif ($_ =~ /^\@unexec[ \t]+(.*\/)?install-info[ \t]+--delete/) { + $inforemoveseen = $. + if (($osname ne "NetBSD") || ("$1" eq "%D/bin/")); + # On NetBSD, we enforce %D/bin/... + } elsif ($_ =~ /^\@(exec|unexec)/) { + if ($ldconfigwithtrue + && /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 + } 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 ($_ =~ m#man/([^/]+/)?man([$manchapters])/(.+\.[$manchapters])(\.gz)?#) { # was bugg for manpages w/ . in name - HF + if ($osname eq "FreeBSD") { + 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: seen installation to share/doc in $file. ". + "($curdir/$_)\n" if ($verbose); + $sharedocused++; + } + } + + if ($rcsidinplist && !$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 ".(($osname eq "NetBSD")?"%D/bin/":"")."install-info must be used to ". + "add/delete entries into \"info/dir\"."); + } + &perror("FATAL: \"\@exec ".(($osname eq "NetBSD")?"%D/bin/":"")."install-info\" must be placed ". + "after all the info files."); + } elsif ($infoafterinstall) { + &perror("FATAL: move \"\@exec ".(($osname eq "NetBSD")?"%D/bin/":"")."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 ".(($osname eq "NetBSD")?"%D/bin/":"")."install-info --delete\" must ". + "be placed before any of the info files listed."); + } elsif ($infobeforeremove) { + &perror("FATAL: move \"\@exec ".(($osname eq "NetBSD")?"%D/bin/":"")."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 (<IN>) { + $whole .= $_; + } + &abspathname($whole, $file); + close(IN); +} + +sub checklastline { + local($file) = @_; + local($whole); + + open(IN, "< $portdir/$file") || return 0; + $whole = ''; + while (<IN>) { + $whole .= $_; + } + 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 unnecessery blank lines ". + "at the last part."); + } + + close(IN); +} + +sub checkpatch { + local($file) = @_; + local($whole); + + open(IN, "< $portdir/$file") || return 0; + $whole = ''; + while (<IN>) { + $whole .= $_; + } + if ($committer && $whole =~ /.\$([A-Za-z0-9]+)[:\$]/) { # 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."); + } + + close(IN); +} + +# +# Makefile +# +sub checkmakefile { + local($file) = @_; + local($rawwhole, $whole, $idx, @sections); + local($tmp); + local($i, $j, $k, $l); + local(@varnames) = (); + local($distfiles, $pkgname, $distname, $extractsufx) = ('', '', '', ''); + local($bogusdistfiles) = (0); + local($realwrksrc, $wrksrc, $nowrksubdir) = ('', '', ''); + local(@mman, @pman); + + open(IN, "< $portdir/$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"); + } +# +# 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; + 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: IS_INTERACTIVE/NOPORTDOCS + # + $whole =~ s/\n#[^\n]*/\n/g; + $whole =~ s/\n\n+/\n/g; + print "OK: checking IS_INTERACTIVE.\n" if ($verbose); + if ($whole =~ /\nIS_INTERACTIVE/) { + if ($whole !~ /defined\((BATCH|FOR_CDROM)\)/) { + &perror("WARN: 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 ($sharedocused && $whole !~ /defined\(NOPORTDOCS\)/ + && $whole !~ m#(\$[\{\(]PREFIX[\}\)]|$localbase)/share/doc#) { + &perror("WARN: use \".if !defined(NOPORTDOCS)\" to wrap ". + "installation of files into $localbase/share/doc.") + if $osname ne "NetBSD"; # how do you get this out of PLIST? + } + + # + # whole file: direct use of command names + # + print "OK: checking direct use of command names.\n" if ($verbose); + foreach $i (split(/\s+/, <<EOF)) { +awk basename cat cp echo false gmake grep gzcat install +ldconfig md5 mkdir mv patch rm rmdir sed setenv touch tr xmkmf +EOF + $cmdnames{$i} = "\$\{\U$i\E\}"; + } + $cmdnames{'gunzip'} = '${GUNZIP_CMD}'; + $cmdnames{'gzip'} = '${GZIP_CMD}'; + # + # 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][\@-]?)(echo|\$[\{\(]ECHO[\}\)]|\$[\{\(]ECHO_MSG[\}\)])[ \t]+("(\\'|\\"|[^"])*"|'(\\'|\\"|[^'])*')[ \t]*[;\n]/$1$2;/; + foreach $i (keys %cmdnames) { + if ($j =~ /[ \t\/]$i[ \t\n;]/) { + &perror("WARN: possible direct use of command \"$i\" ". + "found. use $cmdnames{$i} instead."); + } + } + + # + # whole file: ldconfig must come with "true" command + # + if ($ldconfigwithtrue + && $j =~ /(ldconfig|\$[{(]LDCONFIG[)}])/ + && $j !~ /(\/usr\/bin\/true|\$[{(]TRUE[)}])/) { + &perror("FATAL: ldconfig must be used with \"||\${TRUE}\"."); + } + + # + # whole file: ${MKDIR} -p + # + if ($j =~ /\${MKDIR}\s+-p/) { + &perror("WARN: possible use of \"\${MKDIR} -p\" ". + "found. \${MKDIR} includes \"-p\" by default."); + } + + # + # whole file: full path name + # + &abspathname($whole, $file); + + # + # break the makefile into sections. + # + @sections = split(/\n\n+/, $rawwhole); + for ($i = 0; $i < scalar(@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); + if($osname ne "NetBSD"){ + @linestocheck = split("\n", <<EOF); +Whom +Version [rR]equired +Date [cC]reated +EOF + 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: non-comment line in comment section of $file."); + } + foreach $i (@linestocheck) { + $j = $i; + $j =~ s/\(.*\)\?//g; + $j =~ s/\[(.)[^\]]*\]/$1/g; + if ($tmp !~ /# $i:[ \t]+\S+/) { + &perror("FATAL: no \"$j\" line in ". + "comment section of $file."); + } else { + print "OK: \"$j\" seen in $file.\n" if ($verbose); + } + } + } else { + $tmp = $sections[$idx++]; + } + if ((($tmp !~ /#(\s+)\$$rcsidstr([^\$]*)\$/) && ($osname eq "NetBSD")) + || (($tmp !~ /#\n#(\s+)\$$rcsidstr([^\$]*)\$/) && + ($osname eq "FreeBSD"))) { + &perror("FATAL: no \$$rcsidstr\$ line in $file comment ". + "section."); + } else { + print "OK: \$$rcsidstr\$ seen in $file.\n" if ($verbose); + if ($1 ne ' ') { + &perror("WARN: please use single whitespace ". + "right before \$$rcsidstr\$ tag."); + } + if ($2 ne '') { + if ($verbose || $newport) { # XXX + &perror("WARN: ". + ($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] =~ s/\n#[^\n]*//g; + $sections[$i] =~ s/\n\n+/\n/g; + $sections[$i] =~ s/\\\n/ /g; + } + + # + # + # section 2: DISTNAME/PKGNAME/... + # + print "OK: checking first section of $file. (DISTNAME/...)\n" + if ($verbose); + $tmp = $sections[$idx++]; + + # check the order of items. + @tocheck=split(/\s+/, <<EOF); +DISTNAME PKGNAME WRKSRC NO_WRKSUBDIR CATEGORIES MASTER_SITES MASTER_SITE_SUBDIR +EXTRACT_SUFX DISTFILES +EOF + if ($osname eq "NetBSD") { + push(@tocheck,"ONLY_FOR_ARCHS"); + push(@tocheck,"MIRROR_DISTFILES"); + } + &checkorder('DISTNAME', $tmp, @tocheck); + + # check the items that has to be there. + $tmp = "\n" . $tmp; + foreach $i ('DISTNAME', 'CATEGORIES') { + if ($tmp !~ /\n$i=/) { + &perror("FATAL: $i has to be there."); + } + if ($tmp =~ /\n$i(\?=)/) { + &perror("FATAL: $i has to be set by \"=\", ". + "not by \"$1\"."); + } + } + + # check the URL + if ($tmp =~ /\nMASTER_SITES[+?]?=[ \t]*([^\n]*)\n/ + && $1 !~ /^[ \t]*$/) { + print "OK: seen MASTER_SITES, sanity checking URLs.\n" + if ($verbose); + @sites = split(/\s+/, $1); + foreach $i (@sites) { + if ($i =~ m#^\w+://#) { + if ($i !~ m#/$#) { + &perror("FATAL: URL \"$i\" should ". + "end with \"/\"."); + } + if ($i =~ m#://[^/]*:/#) { + &perror("FATAL: URL \"$i\" contains ". + "extra \":\"."); + } + unless (&is_predefined($i)) { + print "OK: URL \"$i\" ok.\n" + if ($verbose); + } + } else { + print "OK: non-URL \"$i\" ok.\n" + if ($verbose); + } + } + } else { + &perror("WARN: no MASTER_SITES found. is it ok?"); + } + + # check DISTFILES and related items. + $distfiles = $1 if ($tmp =~ /\nDISTFILES[+?]?=[ \t]*([^\n]+)\n/); + $pkgname = $1 if ($tmp =~ /\nPKGNAME[+?]?=[ \t]*([^\n]+)\n/); + $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: no need to define EXTRACT_SUFX if ". + "DISTFILES is defined."); + } + if ($extractsufx eq '.tar.gz') { + &perror("WARN: 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 PKGNAME.\n" if ($verbose); + if ($pkgname ne '' && $pkgname eq $distname) { + &perror("WARN: PKGNAME is \${DISTNAME} by default, ". + "you don't need to define PKGNAME."); + } + $i = ($pkgname eq '') ? $distname : $pkgname; + 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.")); + } + 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. should modify \"-$k\"" . + ($osname ne "NetBSD"?" to obey the handbook.":".")); + } + } 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 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 necessery. ". + "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 port."); + } + + push(@varnames, split(/\s+/, <<EOF)); +DISTNAME PKGNAME CATEGORIES MASTER_SITES MASTER_SITE_SUBDIR +EXTRACT_SUFX DISTFILES +EOF + + # + # section 3: PATCH_SITES/PATCHFILES(optional) + # + print "OK: checking second section of $file, (PATCH*: optinal).\n" + if ($verbose); + $tmp = $sections[$idx]; + + if ($tmp =~ /(PATCH_SITES|PATCH_SITE_SUBDIR|PATCHFILES|PATCH_DIST_STRIP)/) { + &checkearlier($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_SITES.\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'); + + $idx++; + } + + push(@varnames, split(/\s+/, <<EOF)); +PATCH_SITES PATCHFILES PATCH_DIST_STRIP +EOF + + # + # section 4: MAINTAINER + # + print "OK: checking third section of $file (MAINTAINER).\n" + if ($verbose); + $tmp = $sections[$idx++]; + + &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.port.mk - HF + } + $tmp =~ s/\n\n+/\n/g; + + &checkextra($tmp, 'MAINTAINER'); + + push(@varnames, 'MAINTAINER'); + + # + # 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 = split(/\s+/, <<EOF); +LIB_DEPENDS BUILD_DEPENDS RUN_DEPENDS FETCH_DEPENDS DEPENDS DEPENDS_TARGET +EOF + $warn_lib_depends_backslashes=0 + if $osname eq "NetBSD"; + if ($tmp =~ /(LIB_|BUILD_|RUN_|FETCH_)?DEPENDS/) { + &checkearlier($tmp, @varnames); + + if (!defined $ENV{'PORTSDIR'}) { + $ENV{'PORTSDIR'} = $portsdir; + } + foreach $i (grep(/^[A-Z_]*DEPENDS[?+]?=/, split(/\n/, $tmp))) { + $i =~ s/^([A-Z_]*DEPENDS)[?+]?=[ \t]*//; + $j = $1; + print "OK: checking ports listed in $j.\n" + if ($verbose); + foreach $k (split(/\s+/, $i)) { + # check USE_PERL5 + $l = (split(':', $k))[0]; + if ($l =~ /^perl5(\.\d+)?$/) { + &perror("WARN: dependency to perl5 ". + "listed in $j. consider using ". + "USE_PERL5."); + } + + # check USE_GMAKE + if ($l =~ /^(gmake|\${GMAKE})$/) { + &perror("WARN: dependency to $1 ". + "listed in $j. consider using ". + "USE_GMAKE."); + } + # check for LIB_DEPENDS w/o backslashes + if ($osname eq "NetBSD") { + if (("$j" eq "LIB_DEPENDS") && ($l =~ /\\\\\./)) { + $warn_lib_depends_backslashes=1; + } + } + + # check port dir existence + $k = (split(':', $k))[1]; + if ($osname eq "NetBSD") { + $k =~ s/..\/../$ENV{'PORTSDIR'}/; + } else { + $k =~ s/\${PORTSDIR}/$ENV{'PORTSDIR'}/; + } + if (! -d $k) { + &perror("WARN: no port directory $k ". + "found, even though it is ". + "listed in $j."); + } else { + print "OK: port directory $k found.\n" + if ($verbose); + } + } + } + if (($osname eq "NetBSD") && ($warn_lib_depends_backslashes == 1)) { + &perror("WARN: use of backslashes in LIB_DEPENDS is deprecated."); + } + foreach $i (@linestocheck) { + $tmp =~ s/$i[?+]?=[^\n]+\n//g; + } + + &checkextra($tmp, '*_DEPENDS'); + + $idx++; + } + + push(@varnames, @linestocheck); + &checkearlier($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($tmp, @varnames); + + # check WRKSRC/NO_WRKSUBDIR + # + # do not use DISTFILES/DISTNAME to control over WRKSRC. + # DISTNAME is for controlling distribution filename. + # example: + # DISTNAME= package + # PKGNAME= package-1.0 + # 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: WRKSRC is set to meaningless value ". + "\"$1\".". + ($nowrksubdir eq '' + ? " use \"NO_WRKSUBDIR=yes\" instead." + : "")); + } + if ($bogusdistfiles) { + if ($distname ne '' && $wrksrc eq '') { + &perror("WARN: do not use DISTFILES and DISTNAME ". + "to control WRKSRC. how about ". + "\"WRKSRC=\${WRKDIR}/$distname\"?"); + } else { + &perror("WARN: 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: definition of WRKSRC not necessery. ". + "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: \"$1\" found. do not forget to update ". + "ports/LEGAL."); + } + + # check MAN[1-9LN] + if ($extrafile && $osname ne "NetBSD") { + print "OK: checking MAN[0-9LN].\n" if ($verbose); + foreach $i (split(//, $manchapters)) { + next if ($i eq ''); + if ($tmp =~ /MAN\U$i\E=\s*([^\n]*)\n/) { + @mman = split(/\s+/, $1); + @pman = split(/\s+/, $plistmanall{$i}); + foreach $j (@mman) { + next if ($j eq ''); + if (!grep($_ eq $j, @pman)) { + &perror("WARN: manpage $j in $file ". + "MAN$i but not in PLIST."); + } + } + foreach $j (@pman) { + next if ($j eq ''); + if (!grep($_ eq $j, @mman)) { + &perror("WARN: manpage $j in PLIST ". + "but not in $file MAN$i."); + } + } + } else { + if ($plistmanall{$i}) { + if ($manstrict) { + &perror("FATAL: manpage for chapter ". + "$i must be listed in ". + "$file MAN\U$i\E. "); + } else { + &perror("WARN: manpage for chapter ". + "$i should be listed in ". + "MAN\U$i\E, ". + "even if compression is ". + "not necessery."); + } + } + if ($mancompress && $plistman{$i}) { + &perror("WARN: MAN\U$i\E? will help you ". + "compressing manual page in chapter ". + "\"$i\"."); + } elsif (!$mancompress && $plistmangz{$i}) { + &perror("WARN: 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: how about using MANLANG for ". + "designating manual language, such as \"$i\"?"); + } + } + + # check USE_X11 and USE_IMAKE + if ($tmp =~ /\nUSE_IMAKE[?+]?=/ && $tmp =~ /\nUSE_X11[?+]?=/) { + &perror("WARN: since you already have USE_IMAKE, ". + "you don't need USE_X11."); + } + + # check direct use of important make targets. + if ($tmp =~ /\n(fetch|extract|patch|configure|build|install):/) { + &perror("FATAL: direct redefinition of make target \"$1\" ". + "discouraged. redefine \"do-$1\" instead."); + } + + 1; +} + +sub perror { + local(@msg) = @_; + if ($msg[0] =~ /^FATAL/) { + $err++; + } else { + $warn++; + } + print join("\n", @msg) . "\n"; +} + +sub checkextra { + local($str, $section) = @_; + + $str = "\n" . $str if ($str !~ /^\n/); + $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: extra item placed in the ". + "$section section, ". + "for example, \"$1\"."); + } else { + &perror("WARN: extra item placed in the ". + "$section section."); + } +} + +sub checkorder { + local($section, $str, @order) = @_; + local(@items, $i, $j, $k, $invalidorder); + + print "OK: checking the order of $section section.\n" if ($verbose); + + @items = (); + foreach $i (split("\n", $tmp)) { + $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: $i appears out-of-order."); + $invalidorder++; + } else { + print "OK: seen $i, in order.\n" if ($verbose); + } + $j = $k; + } else { + &perror("FATAL: extra item \"$i\" placed in the ". + "$section section."); + } + } + if ($invalidorder) { + &perror("FATAL: order must be " . join('/', @order) . '.'); + } else { + print "OK: $section section is ordered properly.\n" + if ($verbose); + } +} + +sub checkearlier { + local($str, @varnames) = @_; + local($i); + + print "OK: checking items that has to appear earlier.\n" if ($verbose); + foreach $i (@varnames) { + if ($str =~ /\n$i[?+]?=/) { + &perror("WARN: \"$i\" has to appear earlier in $file."); + } + } +} + +sub abspathname { + local($str, $file) = @_; + local($s, $i, %cmdnames); + local($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 $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: possible use of absolute pathname ". + "\"$i\", in $file."); + } + } + + 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 $i (keys %cmdnames) { + if ($str =~ /$i/) { + &perror("WARN: possible direct use of \"$&\" ". + "found in $file. 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 $i (keys %cmdnames) { + if ($str =~ /(\.\/|\$[\{\(]\.CURDIR[\}\)]\/|[ \t])(\b$i)\//) { + &perror("WARN: possible direct use of \"$i\" ". + "found in $file. if so, use $cmdnames{$i}."); + } + } +} + +sub is_predefined { + local($url) = @_; + local($site); + local($subdir); + if ($site = (grep($url =~ $_, keys %predefined))[0]) { + $url =~ /$site/; + $subdir = $'; + $subdir =~ s/\/$//; + &perror("WARN: how about using ". + "\${MASTER_SITE_$predefined{$site}} with ". + "\"MASTER_SITE_SUBDIR=$subdir\", instead of \"$url\?"); + return &TRUE; + } + undef; +} + +sub TRUE {1;} diff --git a/pkgtools/pkglint/files/plist-clash.pl b/pkgtools/pkglint/files/plist-clash.pl new file mode 100644 index 00000000000..976870e2ae4 --- /dev/null +++ b/pkgtools/pkglint/files/plist-clash.pl @@ -0,0 +1,98 @@ +#!@PREFIX@/bin/perl +# +# $NetBSD: plist-clash.pl,v 1.1 1998/08/07 22:13:44 tsarna Exp $ +# +# Scan all ports and look for filenames used by more than one port. +# + +if(`uname -s` eq "FreeBSD"){ + $OS="FreeBSD"; + $PORTSDIR="/usr/ports"; +}else{ + $OS="NetBSD"; + $PORTSDIR="@PORTSDIR@"; +} + +########################################################################### +sub read_plist +{ + local($pkg)=@_; + local($base); + + $prefix="\$LOCALBASE"; + + if(! -d $pkg){ + print "$pkg: no such dir\n"; + return; + } + + open(M,"$pkg/Makefile") || die "Can't read $pkg/Makefile: $!\n"; + while(<M>){ + $prefix="\$X11BASE" if /USE_X11/; + $prefix="\$X11BASE" if /USE_IMAKE/; + $prefix=$1 if /^PREFIX\??=\s*(\S+)/; + } + close(M); + + # printf "%-40s prefix=%s\n","$pkg:",$prefix; + + # NetBSD may have more than one PLIST file + opendir(D,"$pkg/pkg/.") || die "Can't readdir($pkg/pkg/.): $!\n"; + while($f=readdir(D)){ + if($f =~ /^PLIST/){ + next if $f=~/.orig$/; + + # printf("%-40s PLIST=$f\n","",$f); + + open(P,"$pkg/pkg/$f") or die "Can't read $pkg/pkg/$f: $!\n"; + while(<P>){ + next if /^@/; + chomp; + + # strip .gz off manpages - handled via MANZ + s/.gz$// if /^man/; + + ($p) = $pkg =~ m@$PORTSDIR/(.+)@; + if(0 and $F{"$prefix/$_"}){ + print "$prefix/$_ already used by ",$F{"$prefix/$_"},"\n"; + } + $F{"$prefix/$_"} .= " $p"; + } + close(P); + } + } + closedir(D); +} + + +########################################################################### +# M A I N +########################################################################### + +if($#ARGV < 0){ + die "Usage: $0 portsdir1 ...\n"; +} + +# loop to parse all PLIST files +foreach $pkg (@ARGV){ + print "===> $pkg\n"; + &read_plist($pkg); +} + +# Output diplicates +foreach $file (sort keys %F){ + $pkgs=$F{$file}; + $pkgs=~s/^\s+//g; + + # clean up duplicates (e.g. via PLIST-*) + undef %pF; + foreach $p (split(/ /,$pkgs)){ + $pF{$p}=1; + } + @pkgs=sort keys %pF; + + $n=$#pkgs+1; + if($n>1){ + print "$n for $file: ",join(", ",@pkgs),"\n"; + } +} diff --git a/pkgtools/pkglint/pkg/COMMENT b/pkgtools/pkglint/pkg/COMMENT new file mode 100644 index 00000000000..94309919a61 --- /dev/null +++ b/pkgtools/pkglint/pkg/COMMENT @@ -0,0 +1 @@ +A verifier for NetBSD package directory. diff --git a/pkgtools/pkglint/pkg/DESCR b/pkgtools/pkglint/pkg/DESCR new file mode 100644 index 00000000000..aa677c3672e --- /dev/null +++ b/pkgtools/pkglint/pkg/DESCR @@ -0,0 +1,10 @@ +pkglint tries to verify the content of a package directory. +The purpose of pkglint can be separated into two parts: + (1) to let the submitters easily polish her/his own package + directory, and + (2) to decrease the labor of the committers. + +pkglint uses very simple regular-expression matching for verifying +files that make up a package directory. Note that it does NOT implement +complete parser for those files. Because of this the user may see some +extra warnings, especially when checking complex Makefiles. diff --git a/pkgtools/pkglint/pkg/PLIST b/pkgtools/pkglint/pkg/PLIST new file mode 100644 index 00000000000..d8b9609774d --- /dev/null +++ b/pkgtools/pkglint/pkg/PLIST @@ -0,0 +1,6 @@ +@comment $NetBSD: PLIST,v 1.1 1998/08/07 22:13:44 tsarna Exp $ +bin/lintpkgsrc +bin/pkglint +bin/plist-clash +man/man1/pkglint.1 +man/cat1/pkglint.0 |