Tue Nov 4 21:45:13 2008 UTC ()
Added a check that detects a downgrade of a package. To do this, it
loads the changes in doc/CHANGES-*.


(rillig)
diff -r1.779 -r1.780 pkgsrc/pkgtools/pkglint/files/pkglint.pl

cvs diff -r1.779 -r1.780 pkgsrc/pkgtools/pkglint/files/Attic/pkglint.pl (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/pkglint.pl 2008/10/20 11:09:07 1.779
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkglint.pl 2008/11/04 21:45:13 1.780
@@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
1#! @PERL@ 1#! @PERL@
2# $NetBSD: pkglint.pl,v 1.779 2008/10/20 11:09:07 rillig Exp $ 2# $NetBSD: pkglint.pl,v 1.780 2008/11/04 21:45:13 rillig Exp $
3# 3#
4 4
5# pkglint - static analyzer and checker for pkgsrc packages 5# pkglint - static analyzer and checker for pkgsrc packages
6# 6#
7# Written by: 7# Written by:
8# Roland Illig <rillig@NetBSD.org> 8# Roland Illig <rillig@NetBSD.org>
9# 9#
10# Based on work by: 10# Based on work by:
11# Hubert Feyrer <hubertf@NetBSD.org> 11# Hubert Feyrer <hubertf@NetBSD.org>
12# Thorsten Frueauf <frueauf@NetBSD.org> 12# Thorsten Frueauf <frueauf@NetBSD.org>
13# Thomas Klausner <wiz@NetBSD.org> 13# Thomas Klausner <wiz@NetBSD.org>
14# and others. 14# and others.
15# 15#
@@ -1131,26 +1131,44 @@ use enum qw(FNAME REVISION MTIME TAG); @@ -1131,26 +1131,44 @@ use enum qw(FNAME REVISION MTIME TAG);
1131 1131
1132sub new($$$$$) { 1132sub new($$$$$) {
1133 my ($class, $fname, $revision, $date, $tag) = @_; 1133 my ($class, $fname, $revision, $date, $tag) = @_;
1134 my $self = [ $fname, $revision, $date, $tag ]; 1134 my $self = [ $fname, $revision, $date, $tag ];
1135 bless($self, $class); 1135 bless($self, $class);
1136 return $self; 1136 return $self;
1137} 1137}
1138sub fname($) { return shift()->[FNAME]; } 1138sub fname($) { return shift()->[FNAME]; }
1139sub revision($) { return shift()->[REVISION]; } 1139sub revision($) { return shift()->[REVISION]; }
1140sub mtime($) { return shift()->[MTIME]; } 1140sub mtime($) { return shift()->[MTIME]; }
1141sub tag($) { return shift()->[TAG]; } 1141sub tag($) { return shift()->[TAG]; }
1142#== End of CVS_Entry ====================================================== 1142#== End of CVS_Entry ======================================================
1143 1143
 1144package PkgLint::Change;
 1145#==========================================================================
 1146# A change entry from doc/CHANGES-*
 1147#==========================================================================
 1148
 1149sub new($$$$$$) {
 1150 my ($class, $line, $action, $pkgpath, $version, $author, $date) = @_;
 1151 my $self = [ $line, $action, $pkgpath, $version, $author, $date ];
 1152 bless($self, $class);
 1153 return $self;
 1154}
 1155sub line($) { return shift()->[0]; }
 1156sub action($) { return shift()->[1]; }
 1157sub pkgpath($) { return shift()->[2]; }
 1158sub version($) { return shift()->[3]; }
 1159sub author($) { return shift()->[4]; }
 1160sub date($) { return shift()->[5]; }
 1161#== End of PkgLint::Change ================================================
1144 1162
1145package main; 1163package main;
1146#========================================================================== 1164#==========================================================================
1147# This package contains the application-specific code of pkglint. 1165# This package contains the application-specific code of pkglint.
1148# Most subroutines in this package follow a strict naming convention: 1166# Most subroutines in this package follow a strict naming convention:
1149# 1167#
1150# The get_*() functions provide easy access to important non-trivial data 1168# The get_*() functions provide easy access to important non-trivial data
1151# structures that are loaded from external files and are therefore cached. 1169# structures that are loaded from external files and are therefore cached.
1152# 1170#
1153# The is_*() functions return a boolean value and have no side effects. 1171# The is_*() functions return a boolean value and have no side effects.
1154# 1172#
1155# The checkline_*() procedures check a single line for compliance with some 1173# The checkline_*() procedures check a single line for compliance with some
1156# rules. 1174# rules.
@@ -2193,26 +2211,90 @@ sub get_doc_TODO_updates() { @@ -2193,26 +2211,90 @@ sub get_doc_TODO_updates() {
2193 } 2211 }
2194 return $get_doc_TODO_updates_result; 2212 return $get_doc_TODO_updates_result;
2195} 2213}
2196 2214
2197my $get_wip_TODO_updates_result = undef; 2215my $get_wip_TODO_updates_result = undef;
2198sub get_wip_TODO_updates() { 2216sub get_wip_TODO_updates() {
2199 2217
2200 if (!defined($get_wip_TODO_updates_result)) { 2218 if (!defined($get_wip_TODO_updates_result)) {
2201 $get_wip_TODO_updates_result = load_doc_TODO_updates("${cwd_pkgsrcdir}/wip/TODO"); 2219 $get_wip_TODO_updates_result = load_doc_TODO_updates("${cwd_pkgsrcdir}/wip/TODO");
2202 } 2220 }
2203 return $get_wip_TODO_updates_result; 2221 return $get_wip_TODO_updates_result;
2204} 2222}
2205 2223
 2224my $get_doc_CHANGES_docs = undef; # [ $fname, undef or $lines ]
 2225sub get_doc_CHANGES($) {
 2226 my ($pkgpath) = @_;
 2227
 2228 $opt_debug_trace and log_debug(NO_FILE, NO_LINES, "get_doc_CHANGES(\"$pkgpath\")");
 2229
 2230 # Make a reversed list of all the CHANGES-* files, but don't load
 2231 # them yet.
 2232 if (!defined($get_doc_CHANGES_docs)) {
 2233 opendir(DIR, "${cwd_pkgsrcdir}/doc") or die;
 2234 my @files = readdir(DIR);
 2235 closedir(DIR) or die;
 2236 foreach my $file (reverse sort @files) {
 2237 if ($file =~ m"^CHANGES-\d+$") {
 2238 push(@$get_doc_CHANGES_docs, [ $file, undef ]);
 2239 }
 2240 }
 2241 $opt_debug_misc and log_debug(NO_FILE, NO_LINES, "Found " . (scalar @$get_doc_CHANGES_docs) . " changes files.");
 2242 }
 2243
 2244 # Scan the *-CHANGES files in reverse order until some action
 2245 # matches the package directory.
 2246 my @result = ();
 2247 foreach my $doc (@$get_doc_CHANGES_docs) {
 2248 if (!defined($doc->[1])) {
 2249 $opt_debug_misc and log_debug(NO_FILE, NO_LINES, "loading $doc->[0]");
 2250 my $lines = load_file("${cwd_pkgsrcdir}/doc/$doc->[0]") or die;
 2251
 2252 my @changes = ();
 2253 foreach my $line (@$lines) {
 2254 my $text = $line->text;
 2255 next unless $text =~ m"^\t[A-Z]";
 2256
 2257 if ($text =~ m"^\t(Updated) (\S+) to (\S+) \[(\S+) (\d\d\d\d-\d\d-\d\d)\]$") {
 2258 push(@changes, PkgLint::Change->new($line, $1, $2, $3, $4, $5));
 2259 } elsif ($text =~ m"^\t(Added) (\S+) version (\S+) \[(\S+) (\d\d\d\d-\d\d-\d\d)\]$") {
 2260 push(@changes, PkgLint::Change->new($line, $1, $2, $3, $4, $5));
 2261 } elsif ($text =~ m"^\t(Removed) (\S+) (?:successor (\S+) )?\[(\S+) (\d\d\d\d-\d\d-\d\d)\]$") {
 2262 push(@changes, PkgLint::Change->new($line, $1, $2, undef, $3, $4));
 2263 } elsif ($text =~ m"^\t(Downgraded) (\S+) to (\S+) \[(\S+) (\d\d\d\d-\d\d-\d\d)\]$") {
 2264 push(@changes, PkgLint::Change->new($line, $1, $2, $3, $4, $5));
 2265 } elsif ($text =~ m"^\t(Renamed|Moved) (\S+) to (\S+) \[(\S+) (\d\d\d\d-\d\d-\d\d)\]$") {
 2266 push(@changes, PkgLint::Change->new($line, $1, $2, $3, $4, $5));
 2267 } else {
 2268 $line->log_warning("Unknown doc/CHANGES line: " . $line->text);
 2269 $line->explain_warning(
 2270"Maybe some developer didn't stick to the conventions that have been",
 2271"established by mk/misc/developer.mk?");
 2272 }
 2273 }
 2274 $doc->[1] = \@changes;
 2275 }
 2276
 2277 foreach my $change (@{$doc->[1]}) {
 2278 next unless $pkgpath eq $change->pkgpath;
 2279 push(@result, $change);
 2280 }
 2281 if (@result != 0) {
 2282 return @result;
 2283 }
 2284 }
 2285 return ();
 2286}
 2287
2206sub get_suggested_package_updates() { 2288sub get_suggested_package_updates() {
2207 2289
2208 return ($is_wip) 2290 return ($is_wip)
2209 ? get_wip_TODO_updates() 2291 ? get_wip_TODO_updates()
2210 : get_doc_TODO_updates(); 2292 : get_doc_TODO_updates();
2211} 2293}
2212 2294
2213# Load all variables from mk/defaults/mk.conf. Since pkglint does not 2295# Load all variables from mk/defaults/mk.conf. Since pkglint does not
2214# load the infrastructure files during normal operation, these 2296# load the infrastructure files during normal operation, these
2215# definitions have to be added explicitly. 2297# definitions have to be added explicitly.
2216sub load_userdefined_variables() { 2298sub load_userdefined_variables() {
2217 my $fname = "${cwd_pkgsrcdir}/mk/defaults/mk.conf"; 2299 my $fname = "${cwd_pkgsrcdir}/mk/defaults/mk.conf";
2218 my ($lines, $vars); 2300 my ($lines, $vars);
@@ -3387,26 +3469,51 @@ sub checkword_absolute_pathname($$) { @@ -3387,26 +3469,51 @@ sub checkword_absolute_pathname($$) {
3387 $line->explain_warning( 3469 $line->explain_warning(
3388"Absolute pathnames are often an indicator for unportable code. As", 3470"Absolute pathnames are often an indicator for unportable code. As",
3389"pkgsrc aims to be a portable system, absolute pathnames should be", 3471"pkgsrc aims to be a portable system, absolute pathnames should be",
3390"avoided whenever possible.", 3472"avoided whenever possible.",
3391"", 3473"",
3392"A special variable in this context is \${DESTDIR}, which is used in GNU", 3474"A special variable in this context is \${DESTDIR}, which is used in GNU",
3393"projects to specify a different directory for installation than what", 3475"projects to specify a different directory for installation than what",
3394"the programs see later when they are executed. Usually it is empty, so", 3476"the programs see later when they are executed. Usually it is empty, so",
3395"if anything after that variable starts with a slash, it is considered", 3477"if anything after that variable starts with a slash, it is considered",
3396"an absolute pathname."); 3478"an absolute pathname.");
3397 } 3479 }
3398} 3480}
3399 3481
 3482sub checkpackage_possible_downgrade() {
 3483
 3484 $opt_debug_trace and log_debug(NO_FILE, NO_LINES, "checkpackage_possible_downgrade");
 3485
 3486 return unless defined $effective_pkgname;
 3487 return unless $effective_pkgname =~ regex_pkgname;
 3488 my ($pkgbase, $pkgversion) = ($1, $2);
 3489 my $line = $effective_pkgname_line;
 3490
 3491 my @changes = get_doc_CHANGES($pkgpath);
 3492 if (@changes == 0) {
 3493 $opt_debug_misc and $line->log_debug("No changes have been recorded for package $pkgpath.");
 3494 return;
 3495 }
 3496
 3497 my $last_change = $changes[-1];
 3498 return unless $last_change->action eq "Updated";
 3499
 3500 my $last_version = $last_change->version;
 3501
 3502 if (dewey_cmp($pkgversion, "<", $last_version)) {
 3503 $line->log_warning("The package is being downgraded from $last_version to $pkgversion.");
 3504 }
 3505}
 3506
3400# 3507#
3401# Subroutines to check a single line. 3508# Subroutines to check a single line.
3402# 3509#
3403 3510
3404sub checkline_length($$) { 3511sub checkline_length($$) {
3405 my ($line, $maxlength) = @_; 3512 my ($line, $maxlength) = @_;
3406 3513
3407 if (length($line->text) > $maxlength) { 3514 if (length($line->text) > $maxlength) {
3408 $line->log_warning("Line too long (should be no more than $maxlength characters)."); 3515 $line->log_warning("Line too long (should be no more than $maxlength characters).");
3409 $line->explain_warning( 3516 $line->explain_warning(
3410"Back in the old time, terminals with 80x25 characters were common.", 3517"Back in the old time, terminals with 80x25 characters were common.",
3411"And this is still the default size of many terminal emulators.", 3518"And this is still the default size of many terminal emulators.",
3412"Moderately short lines also make reading easier."); 3519"Moderately short lines also make reading easier.");
@@ -6779,26 +6886,28 @@ sub checkfile_package_Makefile($$$) { @@ -6779,26 +6886,28 @@ sub checkfile_package_Makefile($$$) {
6779 6886
6780 if (!defined($pkgname) && defined($distname) && $distname !~ regex_unresolved && $distname !~ regex_pkgname) { 6887 if (!defined($pkgname) && defined($distname) && $distname !~ regex_unresolved && $distname !~ regex_pkgname) {
6781 $distname_line->log_warning("As DISTNAME is not a valid package name, please define the PKGNAME explicitly."); 6888 $distname_line->log_warning("As DISTNAME is not a valid package name, please define the PKGNAME explicitly.");
6782 } 6889 }
6783 6890
6784 ($effective_pkgname, $effective_pkgname_line, $effective_pkgbase, $effective_pkgversion) 6891 ($effective_pkgname, $effective_pkgname_line, $effective_pkgbase, $effective_pkgversion)
6785 = (defined($pkgname) && $pkgname !~ regex_unresolved && $pkgname =~ regex_pkgname) ? ($pkgname, $pkgname_line, $1, $2) 6892 = (defined($pkgname) && $pkgname !~ regex_unresolved && $pkgname =~ regex_pkgname) ? ($pkgname, $pkgname_line, $1, $2)
6786 : (defined($distname) && $distname !~ regex_unresolved && $distname =~ regex_pkgname) ? ($distname, $distname_line, $1, $2) 6893 : (defined($distname) && $distname !~ regex_unresolved && $distname =~ regex_pkgname) ? ($distname, $distname_line, $1, $2)
6787 : (undef, undef, undef, undef); 6894 : (undef, undef, undef, undef);
6788 if (defined($effective_pkgname_line)) { 6895 if (defined($effective_pkgname_line)) {
6789 $opt_debug_misc and $effective_pkgname_line->log_debug("Effective name=${effective_pkgname} base=${effective_pkgbase} version=${effective_pkgversion}."); 6896 $opt_debug_misc and $effective_pkgname_line->log_debug("Effective name=${effective_pkgname} base=${effective_pkgbase} version=${effective_pkgversion}.");
6790 } 6897 }
6791 6898
 6899 checkpackage_possible_downgrade();
 6900
6792 if (!exists($pkgctx_vardef->{"COMMENT"})) { 6901 if (!exists($pkgctx_vardef->{"COMMENT"})) {
6793 log_warning($fname, NO_LINE_NUMBER, "No COMMENT given."); 6902 log_warning($fname, NO_LINE_NUMBER, "No COMMENT given.");
6794 } 6903 }
6795 6904
6796 if (exists($pkgctx_vardef->{"USE_IMAKE"}) && exists($pkgctx_vardef->{"USE_X11"})) { 6905 if (exists($pkgctx_vardef->{"USE_IMAKE"}) && exists($pkgctx_vardef->{"USE_X11"})) {
6797 $pkgctx_vardef->{"USE_IMAKE"}->log_note("USE_IMAKE makes ..."); 6906 $pkgctx_vardef->{"USE_IMAKE"}->log_note("USE_IMAKE makes ...");
6798 $pkgctx_vardef->{"USE_X11"}->log_note("... USE_X11 superfluous."); 6907 $pkgctx_vardef->{"USE_X11"}->log_note("... USE_X11 superfluous.");
6799 } 6908 }
6800 6909
6801 if (defined($effective_pkgbase)) { 6910 if (defined($effective_pkgbase)) {
6802 6911
6803 foreach my $suggested_update (@{get_suggested_package_updates()}) { 6912 foreach my $suggested_update (@{get_suggested_package_updates()}) {
6804 my ($line, $suggbase, $suggver, $suggcomm) = @{$suggested_update}; 6913 my ($line, $suggbase, $suggver, $suggcomm) = @{$suggested_update};