## MakeAll.pl -- See pod at bottom. use strict; use warnings; use Data::Dumper; use File::Find; use File::Spec; use Getopt::Long; use Pod::Usage; use Text::Wrap qw(wrap); use Cwd; use vars qw/$VERSION/; $VERSION='0.1'; sub _join { return join("\n",map { wrap ""," ",$_ } @_),"\n"; } GetOptions( 'help|?' => \(my $Help =0 ), 'run|r!' => \(my $Run =1 ), 'install|i!' => \(my $Install =0 ), 'verbose|v:+'=> \(my $Verbose =0 ), 'debug|d:+' => \(my $Debug =0 ), 'scan|s!' => \(my $Scan =0 ), 'man' => \(my $Man =0 ) ) or pod2usage(2); pod2usage(1) if $Help; pod2usage(-exitstatus => 0, -verbose => 2) if $Man; warn "Run:$Run : Install:$Install : Verbose:$Verbose : Scan:$Scan\n" if $Debug; if($Scan) { $Run=0; $Verbose||=1; } my $fs='File::Spec'; my @vers; foreach my $dir (split /;/,$ENV{PATH}) { foreach (glob $fs->catdir("$dir","perl*.*")) { if(/(perl(?:\d+\.\d+\.\d+)?(\.exe)?)$/i and -e $_){ my $name=$1; my $spec=$_; chomp( my ($ver,$arch,@V)=`$spec -V:version -V:archname -V`); s/\w+='([^'']+)';/$1/g for $ver,$arch; my $V=join "\n",@V; push @vers,[$name,$spec,$ver,$arch,$V]; } } } my %seen; my %vers; @vers=reverse grep { if (!$seen{$_->[-1]}) { $seen{$_->[-1]}=$_->[0]; printf "--- Found %s at %s version %s on %s ---\n",@$_ if $Verbose; $vers{$_->[2]}{$_->[3]}++; 1 } else { printf "--- Skipping duplicate of %s at %s version %s on %s ---\n", $seen{$_->[-1]},@{$_}[1..$#$_-1] if $Verbose>2; 0 } } sort { $b->[0] cmp $a->[0] || $b->[2] cmp $a->[2] || $b->[3] cmp $a->[3] } @vers; exit(0) unless $Run; print "--- Work Dir: ".cwd()." ---\n"; my %status; foreach my $perl (@vers) { my ($name,$spec,$ver,$arch,$V)=@$perl; my $test_name="Perl$ver ($arch) ".($vers{$perl->[2]}{$perl->[3]}>1 ? "[$spec]" : ''); $status{$test_name}=0; print "--- Testing $test_name ---\n"; unlink 'Makefile'; print "Makefile.PL\n" if $Verbose; my $makefile=`$spec Makefile.PL 2>&1 `; unless(-e 'Makefile') { warn "Failed to build with $test_name\nMakefile.PL output:\n$makefile\n"; next; } elsif ($Verbose>2) { print "$makefile\n"; } #print $makefile,"\n"; my $maker='make'; $maker="n$maker" if $arch=~/Win32/i; print "$maker\n" if $Verbose; my $make_out=`$maker 2>&1 `; my $exit=$? >> 8; if ($exit) { warn "Failed to build with $test_name\n$maker output:\n$make_out\n"; next; } elsif ($Verbose>2) { print "$make_out\n"; } print "$maker test\n" if $Verbose; chomp(my @res=`$maker test 2>&1 `); if ($exit) { warn "Failed test with $test_name\n$maker test output:\n"._join(@res)."\n"; next; } if (join("",@res)=~/No tests defined/i) { warn "No tests defined for the module\n"; next; } unless ($Verbose>4) { # remove some stuff at the front, like possible version # copyright crap from the maker. shift @res while @res and $res[0]!~/\Q$name\E/; shift @res if @res and $res[0]=~/\Q$name\E/; } #print Dumper(\@res),"\n\n"; #All tests successful, 38 subtests skipped. #Files=16, Tests=279, 12 wallclock secs ( 0.00 cusr + 0.00 csys = 0.00 CPU) if ($res[-1]=~/Stop|Error|Failed/i) { pop @res while @res and $res[-1]!~/$maker/i; pop @res; if ($Verbose>2) { print _join(@res)."\n"; } else { my @out; unshift @out,pop @res until $res[-1]=~/^\s*Failed\s+\d+/; unshift @out,pop @res; print _join(@out); } } else { #all goood if ($Verbose>2) { print _join(@res); } else { #all goood print "$res[-2]\n$res[-1]\n"; } $status{$test_name}=1; if ($Install) { # should trap errors here... my $install=`$maker install 2>&1 `; my $exit=$? >> 8; if ($exit) { warn "Exitcode $exit.\nFailed install with $test_name\n$maker install output:\n$install\n"; next; } elsif ($Verbose>2) { print "$install\n"; } } } print "---End Test---\n\n"; } __END__ =head1 NAME MakeAll.pl - Build, test and optionally install a module on all versions of perl located in path. =head1 SYNOPSIS MakeAll.pl [options] [file ...] Options: --help brief help message --man full documentation --verbose be talkative, repeat or assign a higher value for more --install do an install in each perl if build is good --no-run don't run test, just scan path --scan short for --verbose --no-run =head1 DESCRIPTION B will run the standard perl Makefile.PL make make test and optionally make install for each distinct perl executable it finds in the path (it uses some tricks to make sure they aren't dupes). On Win32 it will use make or nmake as is necessary based on whether the script itself is run under Activestate perl or Cygwin perl. On non win32 machines it will use make. =head1 NOTES Theres probably issues with this on some platform or another. Patches welcome. =head1 AUTHOR AND COPYRIGHT Copyright Yves Orton 2004. Released under the same terms as Perl itself. Please see the Perl Artistic License distributed with Perl for details. =cut