[tpm] Checking perl syntax in isolation.

J Z Tam jztam at yahoo.com
Wed Apr 14 11:10:12 PDT 2010


#!/bin/ksh -- # -*- perl -*-
# perforce git rcs stuff
# who,when, how, why
eval `/home/yourid/bin/check-perl.ksh try.pl`;
# rest of source of try.pl

But you probably want to cook what check-perl.ksh returns or not before heading into the rest of source.  Perhaps even refactoring check-perl.ksh into checkPerl.pl ? ;-)
Maybe even add a BEGIN END block after the eval  with the path spidering code.
/jordan

The first attempts failed: perl -wc gives up if it can't locate
Some/Unlikely/Module.pm, if I remove the ; after the print then
perlcritic -5 considers the source OK:

$ perl -wc try.pl
Can't
locate Some/Unlikely/Module.pm in @INC (@INC contains:
/home/mstok/perl5/lib/perl5/i486-linux-gnu-thread-multi
/home/mstok/perl5/lib/perl5
/home/mstok/perl5/lib/perl5/i486-linux-gnu-thread-multi /etc/perl
/usr/local/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5
/usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8
/usr/local/lib/site_perl .) at try.pl line 3.
$ perlcritic -5 try.pl 
try.pl source OK
$ bin/check-perl try.pl
syntax error at try.pl line 11, near "$x
for "
try.pl had compilation errors.

What
I have ended up doing is using PPI::XS to tokenize the file.  I then
look at a the use / require / no directives and keep "use warnings;"
and "use vars ... ;", turn "use strict;" into "use strict; no strict
'subs';", and delete all other use / reqires.  That gets rid of issues
with uninstalled modules as the use (or require) has been removed.

Then I peel out all subroutine attributes, as they often rely on the effects of a use I have just deleted to be parsed.

Then
I write the file out to a temporaray file, and call perl -c on it to
check the syntax (or perl -wc if I'm not being lenient), filtering
stdout & stderr to replace the temporary file name with the
original so as not to confuse the reader of the output.

This
seems to pick up most of the trivial errors (the kind where I have
tested the code, realize there's some debugging left in it, delete the
debugging, and maybe the odd }, check it in, and run out to lunch...).

So
has anyone else tried this, and if so how did you end up doing it? Was
it successful, or were there better techniques for catching this type
of thing?

I'll have to see if I can show the code, but the outline should be enough to give a rough idea of what I was up to.

Mike

-- 

Mike Stok <mike at stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.





----- Original Message ----
From: Mike Stok <mike at stok.ca>
To: Toronto PerlMongers <tpm at to.pm.org>
Sent: Tue, April 13, 2010 10:02:07 PM
Subject: [tpm] Checking perl syntax in isolation.

Recently I was asked to come up with a script to check the syntax of perl programs and modules to give a level of confidence that code checked into a repository didn't have any obvious problems - later building and testing will find other issues.  I'll describe the outlines of what I have done, in case someone else has done it differently or more effectively.

This check was to be done on the source tree as pushed to the repository, so Perl files might not be in the same relative positions as when they are deployed, and no equivalent of a CPAN module's "perl Makefile.PL && make ..." would have been done.  The server running the checks would only have a "standard" perl installation with the usual core modules.  As it is intended to be run over multiple existing projects it would be best if there was no magic per project configuration (e.g. setting up @INC by checking a file in a known location).

The script is run by a shell wrapper which does a find to find all the .pl and .pm files, there's no snooping to try and figure out if a file is a Perl script.

If I can assume that no source filters are allowed, and that the Perl on the server running the checks is "close enough" to the Perl running on the production hosts then the best I was able to come up with was something that can deal with code like this:

#!/usr/bin/perl

use Some::Unlikely::Module 'foo';
use Another::Module ':all';

use strict;
use warnings;

my $x =  foo('bar');
print "Hello\n" if $x     # missing ;
for my $y ( 1 .. 10 ) {
    ice_cream('please');
}

exit 1;

sub :banana ice_cream {
    my ($arg) = @_;

    return $arg ? 'baz' : 'plugh';
}

__END__

The first attempts failed: perl -wc gives up if it can't locate Some/Unlikely/Module.pm, if I remove the ; after the print then perlcritic -5 considers the source OK:

$ perl -wc try.pl
Can't locate Some/Unlikely/Module.pm in @INC (@INC contains: /home/mstok/perl5/lib/perl5/i486-linux-gnu-thread-multi /home/mstok/perl5/lib/perl5 /home/mstok/perl5/lib/perl5/i486-linux-gnu-thread-multi /etc/perl /usr/local/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at try.pl line 3.
$ perlcritic -5 try.pl 
try.pl source OK
$ bin/check-perl try.pl
syntax error at try.pl line 11, near "$x
for "
try.pl had compilation errors.

What I have ended up doing is using PPI::XS to tokenize the file.  I then look at a the use / require / no directives and keep "use warnings;" and "use vars ... ;", turn "use strict;" into "use strict; no strict 'subs';", and delete all other use / reqires.  That gets rid of issues with uninstalled modules as the use (or require) has been removed.

Then I peel out all subroutine attributes, as they often rely on the effects of a use I have just deleted to be parsed.

Then I write the file out to a temporaray file, and call perl -c on it to check the syntax (or perl -wc if I'm not being lenient), filtering stdout & stderr to replace the temporary file name with the original so as not to confuse the reader of the output.

This seems to pick up most of the trivial errors (the kind where I have tested the code, realize there's some debugging left in it, delete the debugging, and maybe the odd }, check it in, and run out to lunch...).

So has anyone else tried this, and if so how did you end up doing it? Was it successful, or were there better techniques for catching this type of thing?

I'll have to see if I can show the code, but the outline should be enough to give a rough idea of what I was up to.

Mike

-- 

Mike Stok <mike at stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.




_______________________________________________
toronto-pm mailing list
toronto-pm at pm.org
http://mail.pm.org/mailman/listinfo/toronto-pm





More information about the toronto-pm mailing list