diff options
author | tsarna <tsarna> | 1998-08-07 22:11:40 +0000 |
---|---|---|
committer | tsarna <tsarna> | 1998-08-07 22:11:40 +0000 |
commit | 8f72fac0bec0c7cea63cc15f74b64cfc40802dfb (patch) | |
tree | c456a4f3577aed6fc15ecdad2f32461d2ea53bc1 | |
parent | 32bb94fcaee93c6e4d13305031767a2d1a52f878 (diff) | |
download | pkgsrc-8f72fac0bec0c7cea63cc15f74b64cfc40802dfb.tar.gz |
Our portlint has diverged significantly from FreeBSD's, so
rename portlint to pkglint, and keep the sources right under files.
This makes it much easier to maintain and keep up with changes to out
package system.
-rw-r--r-- | devel/pkglint/Makefile | 47 | ||||
-rw-r--r-- | devel/pkglint/files/CHANGELOG | 139 | ||||
-rw-r--r-- | devel/pkglint/files/lintpkgsrc.sh | 31 | ||||
-rw-r--r-- | devel/pkglint/files/pkglint.1 | 128 | ||||
-rw-r--r-- | devel/pkglint/files/pkglint.pl | 1275 | ||||
-rw-r--r-- | devel/pkglint/files/plist-clash.pl | 98 | ||||
-rw-r--r-- | devel/pkglint/pkg/COMMENT | 1 | ||||
-rw-r--r-- | devel/pkglint/pkg/DESCR | 10 | ||||
-rw-r--r-- | devel/pkglint/pkg/PLIST | 6 | ||||
-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 |
18 files changed, 3470 insertions, 0 deletions
diff --git a/devel/pkglint/Makefile b/devel/pkglint/Makefile new file mode 100644 index 00000000000..ac41d552397 --- /dev/null +++ b/devel/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/devel/pkglint/files/CHANGELOG b/devel/pkglint/files/CHANGELOG new file mode 100644 index 00000000000..5f85a8683da --- /dev/null +++ b/devel/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/devel/pkglint/files/lintpkgsrc.sh b/devel/pkglint/files/lintpkgsrc.sh new file mode 100644 index 00000000000..c2128c97a43 --- /dev/null +++ b/devel/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/devel/pkglint/files/pkglint.1 b/devel/pkglint/files/pkglint.1 new file mode 100644 index 00000000000..990746b1b13 --- /dev/null +++ b/devel/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/devel/pkglint/files/pkglint.pl b/devel/pkglint/files/pkglint.pl new file mode 100644 index 00000000000..3da98c4f9c7 --- /dev/null +++ b/devel/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/devel/pkglint/files/plist-clash.pl b/devel/pkglint/files/plist-clash.pl new file mode 100644 index 00000000000..976870e2ae4 --- /dev/null +++ b/devel/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/devel/pkglint/pkg/COMMENT b/devel/pkglint/pkg/COMMENT new file mode 100644 index 00000000000..94309919a61 --- /dev/null +++ b/devel/pkglint/pkg/COMMENT @@ -0,0 +1 @@ +A verifier for NetBSD package directory. diff --git a/devel/pkglint/pkg/DESCR b/devel/pkglint/pkg/DESCR new file mode 100644 index 00000000000..aa677c3672e --- /dev/null +++ b/devel/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/devel/pkglint/pkg/PLIST b/devel/pkglint/pkg/PLIST new file mode 100644 index 00000000000..d8b9609774d --- /dev/null +++ b/devel/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 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 |