#!/usr/bin/perl

use strict;
use warnings;

use App::eachperl;
use Getopt::Long qw( :config no_ignore_case pass_through );

STDOUT->autoflush;

GetOptions(
   'no-system-perl' => \( my $NO_SYSTEM_PERL ),
   'no-test'        => \( my $NO_TEST ),
   'since=s'        => \( my $SINCE_VERSION ),
   'until=s'        => \( my $UNTIL_VERSION ),
   'only-if=s'      => \( my $ONLY_IF ),
   'devel!'         => \( my $USE_DEVEL ),
   'reverse|r'      => \( my $REVERSE ),
   'stop-on-fail|s' => \( my $STOP_ON_FAIL ),
) or exit 1;

exit App::eachperl->new(
   no_system_perl => $NO_SYSTEM_PERL || $ENV{NO_SYSTEM_PERL},
   no_test        => $NO_TEST,
   since_version  => $SINCE_VERSION,
   until_version  => $UNTIL_VERSION,
   only_if        => $ONLY_IF,
   use_devel      => $USE_DEVEL,
   reverse        => $REVERSE,
   stop_on_fail   => $STOP_ON_FAIL,
)->run( @ARGV );

__END__

=head1 NAME

F<eachperl> - a wrapper script for iterating multiple F<perl> binaries

=head1 SYNOPSIS

   $ eachperl exec -E 'say "Hello"'

     --- perl5.30.0 --- 
   Hello

     --- bleadperl --- 
   Hello

   ----------
   perl5.30.0          : 0
   bleadperl           : 0

=head1 DESCRIPTION

This script iterates over a collection of multiple F<perl> installations,
allowing the same command to be invoked across each of them. The list of
available perl binaries is given by a config file (see L</CONFIG>). The main
mode of operation is that each perl binary in turn is executed with supplied
commandline arguments; though several other convenience commands are provided
for common actions.

=head1 COMMANDS

=head2 list

Prints a list of each configured F<perl> binary and the detected version.

All configured versions are printed; the selected versions are prefixed by an
asterisk.

   $ eachperl --since 5.31 list
     perl5.30.0: /usr/bin/perl5.30.0 (v5.30.0)
   * bleadperl: /home/user/bin/bleadperl (v5.32.0)

=head2 exec

The default command. Invokes each F<perl> binary with the given arguments.

Afterwards a table of exit codes is printed, to summarize the run in case the
output was long and scrolled away.

   $ eachperl exec -E 'say $]'

     --- perl5.30.0 --- 
   5.030000

     --- bleadperl --- 
   5.032000

   ----------
   perl5.30.0          : 0
   bleadperl           : 0

The word C<exec> is optional if the commandline otherwise begins with a
hyphenated option name - which it usually does for short one-line scripts
with C<-M> or C<-E>

   $ eachperl -E 'say 1+2'

   $ eachperl -MConfig -E 'say $Config{nvsize}'

=head2 install

A convenient wrapper for installing a module using L<CPAN>.

   $ eachperl install A::CPAN::Module

When the module name is exactly C<.> this command is an alias for
C<install-local>.

=head2 install-local

Install the distribution in the current working directory by directly invoking
the build script.

This command implies the C<--no-system-perl> option.

=head2 test

A convenient wrapper for testing a module using L<CPAN>.

   $ eachperl test A::CPAN::Module

When the module name is exactly C<.> this command is an alias for
C<test-local>.

=head2 test-local

Install the distribution in the current working directory by directly invoking
the build script.

=head2 build-then-perl

Builds and tests the distribution in the current working directory, then
invokes perl on the remaining commandline. Remember to include C<-Mblib> to
instruct the perl to use the newly-built code

   $ eachperl build-then-perl -Mblib -MMy::Module -E'say My::Module::func()'

=head2 modversion

Prints the version of the named module.

   $ eachperl modversion CPAN
   perl5.30.0: 2.22
   bleadperl: 2.27

=head2 modpath

Prints the path to the named module.

   $ eachperl modpath CPAN
   perl5.30.0: /usr/share/perl/5.30/CPAN.pm
   bleadperl: /home/user/perl5/perlbrew/perls/bleadperl/lib/5.32.0/CPAN.pm

=head1 OPTIONS

=head2 --since VER

Selects only perl versions that are at least as new as the requested version.
Any perl binaries older than this will be skipped.

=head2 --until VER

Selects only perl versions that are at least as old as the requested version.
Any perl binaries newer than this will be skipped.

=head2 --devel, --no-devel

Selects only perl versions that are (or are not) development versions (i.e.
having an odd-numbered minor version).

=head2 --only-if EXPR

An additional perl expression that will be evaluated within the target perl
which must additionally return true, to select that perl version. If it
returns false then this version will be skipped.

The L<Config> module will already be loaded here; this is useful for
expressions like

   --only-if '$Config{usethreads}'

=head2 --reverse, -r

Reverses the order in which perl versions are invoked.

=head2 --stop-on-fail, -s

Stops running after the first failure. Without this option, every version is
attempted even if some fail.

Useful when combined with C<--reverse> to test a module to see how far back in
earlier perl versions it will support.

=head2 --no-system-perl

Deselects the system perl version. The perl version matching the system
version (or rather, the version running this script) is skipped.

=head2 --no-test

Skip the C<Build test> or C<make test> step when building a local
distribution.

=head1 CONFIG

The list of available perls is given by a config file, which is found in the
user's home directory at F<$HOME/.eachperlrc>. This should be a file in INI
format.

In addition, a file of the same name can be placed at the current working
directory (presumably the root directory of a project) to override any
settings in the main file.

The following keys are recognised

=head2 perls

A space-separated list of command names. Each should be searchable using
C<$PATH> but need not be specified as a fully-qualified path.

   perls = perl5.30.0 bleadperl

=head2 Default Commandline Options

Default values for the following commandline options can also be supplied:

   since_version = 5.16
   until_version = 5.30
   only_if = EXPR

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>
