check-non-portable-shell: support Perl versions older than 5.10
authorEric Sunshine <sunshine@sunshineco.com>
Sat, 11 May 2019 00:18:53 +0000 (20:18 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 13 May 2019 02:50:20 +0000 (11:50 +0900)
For thoroughness when checking for one-shot environment variable
assignments at shell function call sites, check-non-portable-shell
stitches together incomplete lines (those ending with backslash). This
allows it to correctly flag such undesirable usage even when the
variable assignment and function call are split across lines, for
example:

FOO=bar \
func

where 'func' is a shell function.

The stitching is accomplished like this:

while (<>) {
chomp;
# stitch together incomplete lines (those ending with "\")
while (s/\\$//) {
$_ .= readline;
chomp;
}
# detect unportable/undesirable shell constructs
...
}

Although this implementation is well supported in reasonably modern Perl
versions (5.10 and later), it fails with older versions (such as Perl
5.8 shipped with ancient Mac OS 10.5). In particular, in older Perl
versions, 'readline' is not connected to the file handle associated with
the "magic" while (<>) {...} construct, so 'readline' throws a
"readline() on unopened filehandle" error. Work around this problem by
dropping readline() and instead incorporating the stitching of
incomplete lines directly into the existing while (<>) {...} loop.

Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/check-non-portable-shell.pl
index 166d64d4a2f05e76f3966080f188b864bf6bf4bb..38bfeebd881ae8930d965536a42305771b066477 100755 (executable)
@@ -27,14 +27,14 @@ sub err {
        close $f;
 }
 
+my $line = '';
 while (<>) {
        chomp;
+       $line .= $_;
        # stitch together incomplete lines (those ending with "\")
-       while (s/\\$//) {
-               $_ .= readline;
-               chomp;
-       }
+       next if $line =~ s/\\$//;
 
+       $_ = $line;
        /\bcp\s+-a/ and err 'cp -a is not portable';
        /\bsed\s+-[^efn]\s+/ and err 'sed option not portable (use only -n, -e, -f)';
        /\becho\s+-[neE]/ and err 'echo with option is not portable (use printf)';
@@ -48,6 +48,7 @@ sub err {
        /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
        /^\s*([A-Z0-9_]+=(\w+|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
                err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
+       $line = '';
        # this resets our $. for each file
        close ARGV if eof;
 }