summaryrefslogtreecommitdiff
path: root/pkgtools
diff options
context:
space:
mode:
authorrillig <rillig>2006-07-27 13:05:09 +0000
committerrillig <rillig>2006-07-27 13:05:09 +0000
commitb3371e901a5e9e5572e99071d49c586d513e346c (patch)
treedea7364a7bcd3f99de5e918b8f7cd1113bd488d9 /pkgtools
parent7391d1b78f62240511cfdcfe1cc3f377e8a3a02e (diff)
downloadpkgsrc-b3371e901a5e9e5572e99071d49c586d513e346c.tar.gz
Removed the --debug option, which has been superseded by the various
-D... options. Removed the check for the :Q operator in C preprocessor macro definitions, since we generally don't expect directory names with embedded special characters in pkgsrc. In buildlink3.mk files, the only BUILDLINK_* variables that may be set are those of the current package. The shell variables $@ and $? are now recognized. Since the shell parser is able to parse the complete code in all pkgsrc packages, make parse errors show in the normal pkglint output. These errors had been hidden before. Fixed the regular expressions in the shell parser to only match at the beginning of the string. That way, when the shell command contains $$@, the $@ is not removed, leaving a single $ behind. Added some code to deal with the different parsing styles of bmake in variable assignments and shell commands. For that, the PkgLint::Line class has been extended to contain arbitrary additional data. This will also allow to reduce the number of duplicate warnings later. The assert() procedure has got a second parameter, the message to be printed. Variable assignment lines start start with a space character (\u0020) are now recognized, but no warning is printed. In pathnames and pathmasks, the '#' character is allowed, since some packages need to remove the .#* files from CVS before installing.
Diffstat (limited to 'pkgtools')
-rw-r--r--pkgtools/pkglint/files/pkglint.pl296
1 files changed, 211 insertions, 85 deletions
diff --git a/pkgtools/pkglint/files/pkglint.pl b/pkgtools/pkglint/files/pkglint.pl
index a6aeb4cfd47..96f9ddbc29a 100644
--- a/pkgtools/pkglint/files/pkglint.pl
+++ b/pkgtools/pkglint/files/pkglint.pl
@@ -1,5 +1,5 @@
#! @PERL@
-# $NetBSD: pkglint.pl,v 1.662 2006/07/24 09:25:57 rillig Exp $
+# $NetBSD: pkglint.pl,v 1.663 2006/07/27 13:05:09 rillig Exp $
#
# pkglint - static analyzer and checker for pkgsrc packages
@@ -57,12 +57,12 @@ use constant true => 1;
use constant dont_know => 2;
use constant doesnt_matter => 3;
-sub assert($) {
- my ($cond) = @_;
+sub assert($$) {
+ my ($cond, $msg) = @_;
my (@callers, $n);
if (!$cond) {
- print STDERR ("FATAL: Assertion failed.\n");
+ print STDERR ("FATAL: Assertion failed: ${msg}.\n");
for ($n = 0; my @info = caller($n); $n++) {
push(@callers, [$info[2], $info[3]]);
@@ -70,7 +70,7 @@ sub assert($) {
for (my $i = $#callers; $i >= 0; $i--) {
my $info = $callers[$i];
- printf STDERR (" at line %4d in %s\n", $info->[0], $info->[1]);
+ printf STDERR (" line %4d called %s\n", $info->[0], $info->[1]);
}
exit(1);
}
@@ -468,12 +468,16 @@ sub highlight($$) {
# Some other methods allow modification of the physical lines, but leave
# the logical line (the C<text>) untouched. These methods are used in the
# --autofix mode.
+#
+# A line can have some "extra" fields that allow the results of parsing to
+# be saved under a name.
#==========================================================================
package PkgLint::Line;
BEGIN {
import PkgLint::Util qw(
false true
+ assert
);
}
@@ -484,10 +488,11 @@ use constant PHYSLINES => 3;
use constant CHANGED => 4;
use constant BEFORE => 5;
use constant AFTER => 6;
+use constant EXTRA => 7;
sub new($$$$) {
my ($class, $fname, $lines, $text, $physlines) = @_;
- my ($self) = ([$fname, $lines, $text, $physlines, false, [], []]);
+ my ($self) = ([$fname, $lines, $text, $physlines, false, [], [], {}]);
bless($self, $class);
return $self;
}
@@ -498,6 +503,22 @@ sub text($) { return shift(@_)->[TEXT]; }
# Note: physlines is _not_ a usual getter method.
sub is_changed($) { return shift(@_)->[CHANGED]; }
+# querying, getting and setting the extra values.
+sub has($$) {
+ my ($self, $name) = @_;
+ return exists($self->[EXTRA]->{$name});
+}
+sub get($$) {
+ my ($self, $name) = @_;
+ assert(exists($self->[EXTRA]->{$name}), "Field ${name} does not exist.");
+ return $self->[EXTRA]->{$name};
+}
+sub set($$$) {
+ my ($self, $name, $value) = @_;
+ assert(!exists($self->[EXTRA]->{$name}), "Field ${name} already exists.");
+ $self->[EXTRA]->{$name} = $value;
+}
+
sub physlines($) {
my ($self) = @_;
return [@{$self->[BEFORE]}, @{$self->[PHYSLINES]}, @{$self->[AFTER]}];
@@ -1679,7 +1700,6 @@ my (%warnings) = (
);
my $opt_autofix = false;
-my $opt_debug = false;
my $opt_dumpmakefile = false;
my $opt_import = false;
my $opt_klickibunti = false; # experimental
@@ -1718,8 +1738,6 @@ my (@options) = (
my ($opt, $val) = @_;
parse_multioption($val, \%warnings);
} ],
- [ "-d|--debug", "Print additional warnings that are mostly of use to pkglint's author",
- "debug|d", \$opt_debug ],
[ "-e|--explain", "Explain the diagnostics or give further help",
"explain|e", sub {
PkgLint::Logging::set_explain();
@@ -1764,17 +1782,20 @@ use constant regex_dependency_wildcard
=> qr"^((?:\$\{[\w_]+\}|[\w_]|-[^\d\[])+)-(?:\[0-9\]|\d.*)$";
use constant regex_gnu_configure_volatile_vars
=> qr"^(?:CFLAGS||CPPFLAGS|CXXFLAGS|FFLAGS|LDFLAGS|LIBS)$";
+use constant regex_mk_comment => qr"^ *\s*#(.*)$";
use constant regex_mk_cond => qr"^\.(\s*)(if|ifdef|ifndef|else|elif|endif|for|endfor|undef)(?:\s+([^\s#][^#]*?))?\s*(?:#.*)?$";
use constant regex_mk_dependency=> qr"^([^\s:]+(?:\s*[^\s:]+)*):\s*([^#]*?)(?:\s*#.*)?$";
use constant regex_mk_include => qr"^\.\s*s?include\s+\"([^\"]+)\"(?:\s*#.*)?$";
use constant regex_mk_shellvaruse => qr"(?:^|[^\$])\$\$\{?(\w+)\}?"; # XXX: not perfect
use constant regex_pkgname => qr"^((?:[\w.+]|-[^\d])+)-(\d(?:\w|\.\d)*)$";
-use constant regex_shellcmd => qr"^\t(.*)$";
+use constant regex_mk_shellcmd => qr"^\t(.*)$";
use constant regex_unresolved => qr"\$\{";
use constant regex_validchars => qr"[\011\040-\176]";
# Note: the following regular expression looks more complicated than
# necessary to avoid a stack overflow in the Perl interpreter.
-use constant regex_varassign => qr"^([-*+A-Z_a-z0-9.\${}\[]+?)\s*(=|\?=|\+=|:=|!=)\s*((?:[^\\#\s]+|\s+?|(?:\\#)+|\\)*?)(?:\s*(#.*))?$";
+# The leading white-space may only consist of \040 characters, otherwise
+# the order of regex_varassign and regex_mk_shellcmd becomes important.
+use constant regex_varassign => qr"^ *([-*+A-Z_a-z0-9.\${}\[]+?)\s*(=|\?=|\+=|:=|!=)\s*((?:[^\\#\s]+|\s+?|(?:\\#)+|\\)*?)(?:\s*(#.*))?$";
use constant regex_sh_varassign => qr"^([A-Z_a-z][0-9A-Z_a-z]*)=";
# The following "constants" are often used in contexts where
@@ -1785,6 +1806,8 @@ use constant regex_sh_varassign => qr"^([A-Z_a-z][0-9A-Z_a-z]*)=";
# it will catch almost all shell programs that are portable enough to be
# used in pkgsrc.
my $regex_shellword = qr"\s*(
+ \#.* # shell comment
+ |
(?: '[^']*' # single quoted string
| \"(?:\\.|[^\"\\])*\" # double quoted string
| \`[^\`]*\` # backticks string
@@ -1793,9 +1816,10 @@ my $regex_shellword = qr"\s*(
| \$\([^()]+\) # make(1) variable, $(...)
| \$[/\@<^] # special make(1) variables
| \$\$[0-9A-Z_a-z]+ # shell variable
+ | \$\$[?@] # special shell variables
| \$\$\{[0-9A-Z_a-z]+\} # shell variable in braces
| \$\$\( # POSIX-style backticks replacement
- | [^\(\)'\"\\\s;&\|<>\#\`\$] # non-special character
+ | [^\(\)'\"\\\s;&\|<>\`\$] # non-special character
| \$\{[^\s\"'`]+ # HACK: nested make(1) variables
)+ | ;;? | &&? | \|\|? | \( | \) | >& | <<? | >>? | \#.*)"sx;
my $regex_varname = qr"[-*+.0-9A-Z_a-z{}\[]+";
@@ -2242,7 +2266,7 @@ sub load_dist_sites() {
# ignore multiple inclusion guards
} else {
- $line->log_error("Unknown line type.");
+ $line->log_fatal("Unknown line type.");
}
}
@@ -2329,7 +2353,7 @@ sub load_tool_names() {
}
}
}
- assert(scalar(@tool_files) > 1);
+ assert(scalar(@tool_files) > 1, "Too few tool files. Maybe the files have been renamed again?");
#
# Scan the tool files for the actual definitions of the tools.
@@ -2814,7 +2838,7 @@ sub unescape_shellword($) {
my ($text) = @_;
# TODO: implement this.
- assert(false);
+ assert(false, "unescape_shellword is not yet implemented.");
}
# Removes all uses of make variables from a string.
@@ -2841,8 +2865,6 @@ sub strings_to_lines($) {
sub backtrace() {
my (@callers);
- return unless $opt_debug;
-
my $n = 0;
while (my @info = caller($n)) {
push(@callers, [$info[2], $info[3]]);
@@ -2925,7 +2947,7 @@ sub extract_used_variables($$) {
}
if ($rest ne "") {
- $opt_debug and $line->log_warning("Could not extract variables: ${rest}");
+ $opt_debug_misc and $line->log_warning("Could not extract variables: ${rest}");
}
return $result;
@@ -2967,8 +2989,8 @@ sub check_pkglint_version() {
sub lines_log_warning($$$) {
my ($lines, $lineno, $msg) = @_;
- assert(0 <= $lineno);
- assert(@{$lines} != 0);
+ assert(0 <= $lineno, "The line number is negative (${lineno}).");
+ assert(@{$lines} != 0, "The lines may not be empty.");
if ($lineno <= $#{$lines}) {
$lines->[$lineno]->log_warning($msg);
@@ -3015,7 +3037,7 @@ sub get_variable_type($$) {
my ($line, $varname) = @_;
my ($type);
- assert(defined($varname));
+ assert(defined($varname), "The varname parameter must be defined.");
if (exists(get_vartypes_map()->{$varname})) {
return get_vartypes_map()->{$varname};
@@ -3202,6 +3224,86 @@ sub variable_needs_quoting($$$) {
}
#
+# Parsing.
+#
+
+# This procedure fills in the extra fields of a line, depending on the
+# line type. These fields can later be queried without having to parse
+# them again and again.
+#
+sub parseline_mk($) {
+ my ($line) = @_;
+ my $text = $line->text;
+
+ if ($text =~ regex_varassign) {
+ my ($varname, $op, $value, $comment) = ($1, $2, $3, $4);
+
+ # In variable assignments, a '#' character is preceded
+ # by a backslash. In shell commands, it is interpreted
+ # literally.
+ $value =~ s/\\\#/\#/g;
+
+ $line->set("is_varassign", true);
+ $line->set("varname", $varname);
+ $line->set("op", $op);
+ $line->set("value", $value);
+ defined($comment) and $line->set("comment", $comment);
+
+ } elsif ($text =~ regex_mk_shellcmd) {
+ my ($shellcmd) = @_;
+
+ # Shell command lines cannot have embedded comments.
+ $line->set("is_shellcmd", true);
+ $line->set("shellcmd", $shellcmd);
+
+ } elsif ($text =~ regex_mk_comment) {
+ my ($comment) = @_;
+
+ $line->set("is_comment", true);
+ $line->set("comment", $comment);
+
+ } elsif ($text eq "") {
+
+ $line->set("is_empty", true);
+
+ } elsif ($text =~ regex_mk_cond) {
+ my ($indent, $directive, $args, $comment) = ($1, $2, $3, $4);
+
+ $line->set("is_cond", true);
+ $line->set("indent", $indent);
+ $line->set("directive", $directive);
+ defined($args) and $line->set("args", $args);
+ defined($comment) and $line->set("comment", $comment);
+
+ } elsif ($text =~ regex_mk_include) {
+ my ($includefile, $comment) = ($1, $2);
+
+ $line->set("is_include", true);
+ $line->set("includefile", $includefile);
+ defined($comment) and $line->set("comment", $comment);
+
+ } elsif ($text =~ regex_mk_dependency) {
+ my ($targets, $sources, $comment) = ($1, $2, $3);
+
+ $line->set("is_dependency", true);
+ $line->set("targets", $targets);
+ $line->set("sources", $sources);
+ defined($comment) and $line->set("comment", $comment);
+
+ } else {
+ assert(false, "Unknown line format: " . $line->to_string());
+ }
+}
+
+sub parselines_mk($) {
+ my ($lines) = @_;
+
+ foreach my $line (@{$lines}) {
+ parseline_mk($line);
+ }
+}
+
+#
# Loading package-specific data from files.
#
@@ -3215,6 +3317,7 @@ sub readmakefile($$$$) {
if (!$lines) {
return false;
}
+ parselines_mk($lines);
$is_main_Makefile = (@{$main_lines} == 0);
@@ -3283,8 +3386,8 @@ sub readmakefile($$$$) {
}
}
- } elsif ($text =~ regex_varassign) {
- my ($varname, $op, $value, $comment) = ($1, $2, $3, $4);
+ } elsif ($line->has("is_varassign")) {
+ my ($varname, $op, $value) = ($line->get("varname"), $line->get("op"), $line->get("value"));
# Record all variables that are defined in these lines, so that they
# are not reported as "used but not defined".
@@ -3410,12 +3513,8 @@ sub checkline_valid_characters_in_variable($$) {
my ($line, $re_validchars) = @_;
my ($varname, $rest);
- $rest = $line->text;
- if ($rest =~ regex_varassign) {
- ($varname, undef, $rest) = ($1, $2, $3);
- } else {
- return;
- }
+ $varname = $line->get("varname");
+ $rest = $line->get("value");
$rest =~ s/$re_validchars//g;
if ($rest ne "") {
@@ -3632,7 +3731,7 @@ sub checkline_cpp_macro_names($$) {
sub checkline_mk_varuse($$$$) {
my ($line, $varname, $mod, $context) = @_;
- assert(defined($varname));
+ assert(defined($varname), "The varname parameter must be defined");
$opt_debug_trace and $line->log_debug("checkline_mk_varuse(\"${varname}\", \"${mod}\", ".$context->to_string().")");
# Check for spelling mistakes.
@@ -3739,7 +3838,7 @@ sub checkline_mk_varuse($$$$) {
}
}
- assert(defined($mkctx_build_defs));
+ assert(defined($mkctx_build_defs), "The build_defs variable must be defined here.");
if (exists(get_userdefined_variables()->{$varname}) && !exists(get_system_build_defs()->{$varname}) && !exists($mkctx_build_defs->{$varname})) {
$line->log_warning("The user-defined variable ${varname} is used but not added to BUILD_DEFS.");
}
@@ -3845,10 +3944,19 @@ sub checkline_mk_shellword($$$) {
# make variables have the same syntax, no matter in which
# state we are currently.
- if ($rest =~ s/^\$\{(${regex_varname})(:[^\{]+)?\}//
- || $rest =~ s/^\$\((${regex_varname})(:[^\)]+)?\)//) {
+ if ($rest =~ s/^\$\{(${regex_varname}|[\@])(:[^\{]+)?\}//
+ || $rest =~ s/^\$\((${regex_varname}|[\@])(:[^\)]+)?\)//
+ || $rest =~ s/^\$(\@)//) {
my ($varname, $mod) = ($1, $2);
+ if ($varname eq "\@") {
+ $line->log_warning("Please use \"\${.TARGET}\" instead of \"\$\@\".");
+ $line->explain_warning(
+ "The variable \$\@ can easily be confused with the shell variable of the",
+ "same name, which has a completely different meaning.");
+ $varname = ".TARGET";
+ }
+
if ($state == SWST_PLAIN && defined($mod) && $mod =~ qr":Q$") {
# Fine.
@@ -3878,24 +3986,39 @@ sub checkline_mk_shellword($$$) {
: VUC_SHELLWORD_UNKNOWN,
VUC_EXTENT_WORD_PART
);
- checkline_mk_varuse($line, $varname, defined($mod) ? $mod : "", $ctx);
+ if ($varname ne "\@") {
+ checkline_mk_varuse($line, $varname, defined($mod) ? $mod : "", $ctx);
+ }
} elsif ($state == SWST_PLAIN) {
- if ($rest =~ s/^[!\%&\(\)*+,\-.\/0-9:;<=>?\@A-Z\[\]^_a-z{|}~]+//) {
+ if ($rest =~ s/^[!#\%&\(\)*+,\-.\/0-9:;<=>?\@A-Z\[\]^_a-z{|}~]+//) {
} elsif ($rest =~ s/^\'//) {
$state = SWST_SQUOT;
} elsif ($rest =~ s/^\"//) {
$state = SWST_DQUOT;
} elsif ($rest =~ s/^\`//) {
$state = SWST_BACKT;
- } elsif ($rest =~ s/^\\[ !"#'\(\)*;\\^{}]//) {
+ } elsif ($rest =~ s/^\\[ !"#'\(\)*;\\^{|}]//) {
} elsif ($rest =~ s/^\$\$([0-9A-Z_a-z]+)//
|| $rest =~ s/^\$\$\{([0-9A-Z_a-z]+)\}//) {
my ($shvarname) = ($1);
if ($opt_warn_quoting && $check_quoting) {
$line->log_warning("Unquoted shell variable \"${shvarname}\".");
}
- } elsif ($rest =~ s/\$\$\(/(/) {
+
+ } elsif ($rest =~ s/^\$\@//) {
+ $line->log_warning("Please use \"\${.TARGET}\" instead of \"\$@\".");
+ $line->explain_warning(
+ "It is more readable and prevents confusion with the shell variable of",
+ "the same name.");
+
+ } elsif ($rest =~ s/^\$\$\@//) {
+ $line->log_warning("The \$@ shell variable should only be used in double quotes.");
+
+ } elsif ($rest =~ s/^\$\$\?//) {
+ $line->log_warning("The \$? shell variable is often not available in \"set -e\" mode.");
+
+ } elsif ($rest =~ s/^\$\$\(/(/) {
$line->log_warning("Invoking subshells via \$(...) is not portable enough.");
$line->explain_warning(
"The Solaris /bin/sh does not know this way to execute a command in a",
@@ -3925,7 +4048,7 @@ sub checkline_mk_shellword($$$) {
$opt_debug_shell and $line->log_debug("[checkline_mk_shellword] Found double-quoted variable ${shvarname}.");
} elsif ($rest =~ s/^\$\$//) {
$line->log_warning("Unquoted \$ or strange shell variable found.");
- } elsif ($rest =~ s/^\\([\(\)*\-.0-9n])//) {
+ } elsif ($rest =~ s/^\\(.)//) {
my ($char) = ($1);
$line->log_warning("Please use \"\\\\${char}\" instead of \"\\${char}\".");
$line->explain_warning(
@@ -3980,8 +4103,8 @@ sub checkline_mk_shellword($$$) {
last;
}
}
- if ($rest ne "") {
- $opt_debug_shell and $line->log_debug("Unparseable shell word in " . statename->[$state] . ": ${rest}");
+ if ($rest !~ qr"^\s*$") {
+ $line->log_error("Internal pkglint error: " . statename->[$state] . ": rest=${rest}");
}
}
@@ -4388,8 +4511,8 @@ sub checkline_mk_shelltext($$) {
};
}
- if ($rest ne "") {
- $opt_debug and $line->log_error("[checkline_mk_shelltext] " . scst_statename->[$state] . ": rest=${rest}");
+ if ($rest !~ qr"^\s*$") {
+ $line->log_error("Internal pkglint error: " . scst_statename->[$state] . ": rest=${rest}");
}
}
@@ -4533,19 +4656,10 @@ sub checkline_mk_vartype_basic($$$$$$$$) {
if ($value =~ qr"^-D([0-9A-Z_a-z]+)=(.*)") {
my ($macname, $macval) = ($1, $2);
- if ($macval =~ qr"^\\\"(?:\$\{[A-Z0-9_]+:Q\}|[^\$])*\\\"") {
- # Everything's fine.
+ # No checks needed, since the macro definitions
+ # are usually directory names, which don't need
+ # any quoting.
- } elsif ($macval =~ qr"^\"\\\"[^\$]*\$\{[A-Z0-9_]+\}.*\\\"\"") {
- $opt_debug and $line->log_note("Not the best style for CPP macros, but accepted.");
-
- } elsif ($macval =~ regex_unresolved && $macval =~ qr"[\"']") {
- $line->log_warning("Unusual macro value ${macval}.");
- $line->explain_warning(
- "String macro definitions should start and end with an escaped quote",
- "(\\\"). Between these quotes, there should be quoted variables in the",
- "form \${VARNAME:Q} or arbitrary non-dollar characters.");
- }
} elsif ($value =~ qr"^-[DU]([0-9A-Z_a-z]+)") {
my ($macname) = ($1);
@@ -4751,10 +4865,10 @@ sub checkline_mk_vartype_basic($$$$$$$$) {
));
my $license_file = "${cwd_pkgsrcdir}/licenses/${value}";
- if (defined($pkgctx_vardef) && exists($pkgctx_vardef->{"LICENSE_FILE"}) && $pkgctx_vardef->{"LICENSE_FILE"}->text =~ regex_varassign) {
- my ($varname, $op, $value, $comment) = ($1, $2, $3, $4);
+ if (defined($pkgctx_vardef) && exists($pkgctx_vardef->{"LICENSE_FILE"})) {
+ my $license_file_line = $pkgctx_vardef->{"LICENSE_FILE"};
- $license_file = "${current_dir}/" . resolve_relative_path($value, false);
+ $license_file = "${current_dir}/" . resolve_relative_path($license_file_line->get("value"), false);
}
if (!-f $license_file) {
$line->log_warning("License file ".normalize_pathname($license_file)." does not exist.");
@@ -4831,13 +4945,13 @@ sub checkline_mk_vartype_basic($$$$$$$$) {
}
} elsif ($type eq "Pathmask") {
- if ($value_novar !~ qr"^[-0-9A-Za-z._~+%*?/\[\]]*$") {
+ if ($value_novar !~ qr"^[#\-0-9A-Za-z._~+%*?/\[\]]*$") {
$line->log_warning("\"${value}\" is not a valid pathname mask.");
}
checkline_mk_absolute_pathname($line, $value);
} elsif ($type eq "Pathname") {
- if ($value_novar !~ qr"^[-0-9A-Za-z._~+%/]*$") {
+ if ($value_novar !~ qr"^[#\-0-9A-Za-z._~+%/]*$") {
$line->log_warning("\"${value}\" is not a valid pathname.");
}
checkline_mk_absolute_pathname($line, $value);
@@ -5023,7 +5137,7 @@ sub checkline_mk_vartype_basic($$$$$$$$) {
} elsif ($value =~ regex_unresolved) {
# No further checks
- } elsif ($value =~ qr"^(https?|ftp|gopher)://([-0-9A-Za-z.]+)(?::(\d+))?/([-%&+,./0-9:=?\@A-Z_a-z~]|\\#)*$") {
+ } elsif ($value =~ qr"^(https?|ftp|gopher)://([-0-9A-Za-z.]+)(?::(\d+))?/([-%&+,./0-9:=?\@A-Z_a-z~]|#)*$") {
my ($proto, $host, $port, $path) = ($1, $2, $3, $4);
my $sites = get_dist_sites();
@@ -5200,7 +5314,7 @@ sub checkline_mk_vartype($$$$$) {
}
if ($rest !~ qr"^\s*$") {
- $opt_debug and $line->log_warning("Invalid shell word \"${value}\" at the end.");
+ $line->log_error("Internal pkglint error: rest=${rest}");
}
} else {
@@ -5283,7 +5397,7 @@ sub checkline_mk_varassign($$$$$) {
}
if ($varname eq "BUILD_DEFS") {
- assert(defined($mkctx_build_defs));
+ assert(defined($mkctx_build_defs), "The build_defs variable must be defined here.");
foreach my $bdvar (split(qr"\s+", $value)) {
$mkctx_build_defs->{$bdvar} = true;
$opt_debug_misc and $line->log_debug("${bdvar} is added to BUILD_DEFS.");
@@ -5453,8 +5567,8 @@ sub checklines_package_Makefile_varorder($) {
if ($text =~ qr"^#") {
$lineno++;
- } elsif ($text =~ regex_varassign) {
- my ($varname, $op, $value, $comment) = ($1, $2, $3, $4);
+ } elsif ($line->has("varname")) {
+ my $varname = $line->get("varname");
if (exists($below->{$varname})) {
if (defined($below->{$varname})) {
@@ -5511,7 +5625,7 @@ sub checklines_mk($) {
my ($allowed_targets) = ({});
my ($substcontext) = PkgLint::SubstContext->new();
- assert(@{$lines} != 0);
+ assert(@{$lines} != 0, "checklines_mk may only be called with non-empty lines.");
$opt_debug_trace and log_debug($lines->[0]->fname, NO_LINES, "checklines_mk()");
# Define global variables for the Makefile context.
@@ -5537,16 +5651,18 @@ sub checklines_mk($) {
checkline_trailing_whitespace($line);
checkline_spellcheck($line);
- if ($text =~ qr"^\s*$") {
+ if ($line->has("is_empty")) {
$substcontext->check_end($line);
- } elsif ($text =~ qr"^#") {
+ } elsif ($line->has("is_comment")) {
# No further checks.
} elsif ($text =~ regex_varassign) {
- my ($varname, $op, $value, $comment) = ($1, $2, $3, $4);
+ my ($varname, $op, undef, $comment) = ($1, $2, $3, $4);
my $space1 = substr($text, $+[1], $-[2] - $+[1]);
my $align = substr($text, $+[2], $-[3] - $+[2]);
+ my $value = $line->get("value");
+
if ($align !~ qr"^(\t*|[ ])$") {
$opt_warn_space && $line->log_note("Alignment of variable values should be done with tabs, not spaces.");
my $prefix = "${varname}${space1}${op}";
@@ -5559,7 +5675,7 @@ sub checklines_mk($) {
checkline_mk_varassign($line, $varname, $op, $value, $comment);
$substcontext->check_varassign($line, $varname, $op, $value);
- } elsif ($text =~ regex_shellcmd) {
+ } elsif ($text =~ regex_mk_shellcmd) {
my ($shellcmd) = ($1);
checkline_mk_shellcmd($line, $shellcmd);
@@ -5746,7 +5862,7 @@ sub checklines_buildlink3_inclusion($) {
my ($lines) = @_;
my ($included_files);
- assert(@{$lines} != 0);
+ assert(@{$lines} != 0, "The lines array must be non-empty.");
$opt_debug_trace and log_debug($lines->[0]->fname, NO_LINES, "checklines_buildlink3_inclusion()");
if (!defined($pkgctx_bl3)) {
@@ -5816,6 +5932,7 @@ sub checkfile_buildlink3_mk($) {
return;
}
+ parselines_mk($lines);
checklines_mk($lines);
$lineno = 0;
@@ -5955,6 +6072,14 @@ sub checkfile_buildlink3_mk($) {
}
}
+ if ($varname =~ qr"^BUILDLINK_[\w_]+\.(.*)$") {
+ my ($varparam) = ($1);
+
+ if ($varparam ne $bl_pkgbase) {
+ $line->log_warning("Only buildlink variables for ${bl_pkgbase}, not ${varparam} may be set in this file.");
+ }
+ }
+
# TODO: More checks.
} elsif (expect($lines, \$lineno, qr"^(?:#.*)?$")) {
@@ -6255,6 +6380,7 @@ sub checkfile_mk($) {
return;
}
+ parselines_mk($lines);
checklines_mk($lines);
autofix($lines);
}
@@ -6310,27 +6436,24 @@ sub checkfile_package_Makefile($$$) {
if (exists($pkgctx_vardef->{"GNU_CONFIGURE"}) && exists($pkgctx_vardef->{"USE_LANGUAGES"})) {
my $languages_line = $pkgctx_vardef->{"USE_LANGUAGES"};
+ my $value = $languages_line->get("value");
- if ($languages_line->text =~ regex_varassign) {
- my (undef, $op, $value, $comment) = ($1, $2, $3, $4);
+ if ($languages_line->has("comment") && $languages_line->get("comment") =~ qr"(?:^|\s+)c(?:\s+|$)"i) {
+ # Don't emit a warning, since the comment
+ # probably contains a statement that C is
+ # really not needed.
- if (defined($comment) && $comment =~ qr"(?:^|\s+)c(?:\s+|$)"i) {
- # Don't emit a warning, since the comment
- # probably contains a statement that C is
- # really not needed.
-
- } elsif ($value !~ qr"(?:^|\s+)(?:c|objc)(?:\s+|$)") {
- $pkgctx_vardef->{"GNU_CONFIGURE"}->log_warning("GNU_CONFIGURE almost always needs a C compiler, ...");
- $languages_line->log_warning("... but \"c\" is not added to USE_LANGUAGES.");
- }
+ } elsif ($value !~ qr"(?:^|\s+)(?:c|objc)(?:\s+|$)") {
+ $pkgctx_vardef->{"GNU_CONFIGURE"}->log_warning("GNU_CONFIGURE almost always needs a C compiler, ...");
+ $languages_line->log_warning("... but \"c\" is not added to USE_LANGUAGES.");
}
}
my $distname_line = $pkgctx_vardef->{"DISTNAME"};
my $pkgname_line = $pkgctx_vardef->{"PKGNAME"};
- my $distname = (defined($distname_line) && $distname_line->text =~ regex_varassign) ? $3 : undef;
- my $pkgname = (defined($pkgname_line) && $pkgname_line->text =~ regex_varassign) ? $3 : undef;
+ my $distname = defined($distname_line) ? $distname_line->get("value") : undef;
+ my $pkgname = defined($pkgname_line) ? $pkgname_line->get("value") : undef;
if (defined($pkgname) && defined($distname) && ($pkgname eq $distname || $pkgname eq "\${DISTNAME}")) {
$pkgname_line->log_note("PKGNAME is \${DISTNAME} by default. You don't need to define PKGNAME.");
@@ -6526,7 +6649,7 @@ sub checkfile_patch($) {
(defined($addlines) && $addlines > 0))) {
if (defined($context_scanning_leading)) {
if ($leading_context_lines != $trailing_context_lines) {
- $opt_debug and $line->log_warning("The hunk that ends here does not have as many leading (${leading_context_lines}) as trailing (${trailing_context_lines}) lines of context.");
+ $opt_debug_patches and $line->log_warning("The hunk that ends here does not have as many leading (${leading_context_lines}) as trailing (${trailing_context_lines}) lines of context.");
}
}
$nextstate = $newstate;
@@ -6864,7 +6987,7 @@ sub checkfile_PLIST($) {
} elsif ($text =~ qr"^etc/") {
my $f = "mk/pkginstall/bsd.pkginstall.mk";
- assert(-f "${cwd_pkgsrcdir}/${f}");
+ assert(-f "${cwd_pkgsrcdir}/${f}", "${cwd_pkgsrcdir}/${f} is not a regular file.");
$line->log_error("Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in ${f}.");
} elsif ($text =~ qr"^include/.*\.(?:h|hpp)$") {
@@ -7094,6 +7217,7 @@ sub checkdir_root() {
return;
}
+ parselines_mk($lines);
if (0 <= $#{$lines}) {
checkline_rcsid_regex($lines->[0], qr"#\s+", "# ");
}
@@ -7147,6 +7271,7 @@ sub checkdir_category() {
log_error($fname, NO_LINE_NUMBER, "Cannot be read.");
return;
}
+ parselines_mk($lines);
$lineno = 0;
@@ -7360,6 +7485,7 @@ sub checkdir_package() {
foreach my $fname (@files) {
if ($fname =~ qr"^((?:.*/)?Makefile\..*|.*\.mk)$"
&& (defined(my $lines = load_lines($fname, true)))) {
+ parselines_mk($lines);
determine_used_variables($lines);
}
}