#!/usr/bin/perl
use warnings;
use strict;

use Carp qw(croak);
use Getopt::Long qw(:config no_ignore_case pass_through);
use File::Find;
use Module::Load;
use Test::BrewBuild;

our $VERSION = '1.03_03';

my $log = Test::BrewBuild->new()->log()->child('brewbuild');
my (%args, $help);

GetOptions(
    "on=s@"         => \$args{on},
    "new=i"         => \$args{new},
    "r|remove"      => \$args{remove},
    "R|revdep"      => \$args{revdep},
    "plugin=s"      => \$args{plugin},
    "args=s@"       => \$args{args},
    "debug=i"       => \$args{debug},
    "version=s@"    => \$args{version},
    "help"          => \$help,
);

my @valid_args = qw(
    on o new n remove r revdep R plugin p args a debug d version v help h
);

if ($^O =~ /MSWin/ && $args{on}){
    warn "\nwe can't use --on with Windows... running on all\n\n";
    delete $args{on};
}

if (@ARGV){
    my @args = grep /^-/, @ARGV;
    for my $arg (@args){
        $arg =~ s/-//g;
        if (! grep { $arg eq $_ } @valid_args){
            $help = 1;
        }
    }
}

if ($help){
    print <<EOF;

Usage: perl build/brewbuild.pl [options]

Options:

--on     | -o:  String, perl version number to run against (can be supplied multiple times). Can not be used on Windows
--plugin | -p:  String, the module name of the exec command plugin to use
--args   | -a:  List of args to pass into the plugin (one arg per loop)
--revdep | -R   Run tests, install, then run tests on all CPAN reverse dependency modules
--debug  | -d:  Int (0-7), sets logging verbosity
--new    | -n:  Integer, how many random versions of perl to install
--remove | -r:  Bool, remove all installed perls (less the current one) before installation of new ones
--verion | -v:  String, the number portion of an available perl version according to "*brew available". Multiple versions can besent in at once
--help   | -h:  print this help message
EOF
exit;
}

if (! -d 't/'){
    croak "\nthere's no 't/' directory, nothing to test. Exiting...\n";
}

my $is_win = $^O =~ /MSWin/ ? 1 : 0;
my $brew_prog = $is_win ? 'berrybrew.exe' : 'perlbrew';
my $brew_link = $is_win 
    ? 'https://github.com/dnmfarrell/berrybrew'
    : 'http://perlbrew.pl';
my $sep = $is_win ? ';' : ':';
my @modules;

if (! grep { -x "$_/$brew_prog"}split /$sep/,$ENV{PATH}){
    warn "\nYou need to install '$brew_prog' to use this program...\n\n" .
         "See $brew_link\n\n";
    exit;
}

if ($args{revdep}){

    $log->_6('running --revdep');

    delete $args{args};
    load 'CPAN::ReverseDependencies';

    find({ wanted => \&_module_find, no_chdir => 1}, 'lib/');
    my $mod = $modules[0];

    $log->_7("using '$mod' as the project we're working on");

    $mod =~ s|lib/||;
    $mod =~ s|/|-|g;
    $mod =~ s|\.pm||;

    $log->_7("working module translated to $mod");

    my $rvdep = CPAN::ReverseDependencies->new;
    my @revdeps = $rvdep->get_reverse_dependencies($mod);

    $log->_0("working on reverse dependencies: " . join ', ', @revdeps);

    $args{plugin} = 'Test::BrewBuild::Plugin::TestAgainst';

    for (@revdeps){
        s/-/::/g;
        $args{plugin_arg} = $_;
        _exec_brew(%args);
    }
}
elsif (defined $args{args}){
    my %opts = %args;

    $log->_7("running a plugin with args");

    delete $args{args};

    for (@{ $opts{args} }) {
        $args{plugin_arg} = $_;
        _exec_brew( %args );
    }

    delete $args{new};
    delete $args{remove};
}
else {
    $log->_7("default run");
    _exec_brew(%args);
}
sub _exec_brew {
    my $brew = Test::BrewBuild->new(%args);

    $log = $log->child('_exec_brew');

    my @opts;
    for (keys %args){
        push @opts, "$_ => $args{$_}" if defined $args{$_};
    }

    $log->_6("executing Test::BrewBuild run() with args: " . join ', ', @opts);

    $brew->run;
}
sub _module_find {
    $log = $log->child('_module_find');
    $log->_7("finding modules");
    push @modules, $_ if -f $_;
}
=pod

=head1 NAME

brewbuild - This is the front-end script for L<Test::BrewBuild>

=head1 NOTICE

This is a devel version and shouldn't be used. I'm working out the myriad of
caveats that encompass Windows' 'berrybrew' that doesn't exist on Unix-type
platforms.

By v1.05, I'll have the majority of the problems resolved, the code cleaned up,
and documentation on suitable setups for pristine testing platforms written.

Pass or fail, I need this on CPAN for internal testing.

=head1 SYNOPSIS

You must be in the root directory of the distribution you want to test. Also,
it is imperative that you have C<cpanm> installed in a global location (eg:
C<perlbrew install-cpanm>.

Run all unit tests against all installed instances with no other action

    brewbuild

    # output

    perl-5.8.9 :: PASS
    perl-5.20.3 :: PASS
    perl-5.22.1 :: PASS

Run tests on the local working copy of the current module, then run all tests
of all reverse dependencies of this module (as reported by CPAN), to ensure
the down river modules will work with your new build

    brewbuild --revdep # or -R

Print usage information

    brewbuild -h

Run on specific versions only (Unix)

    brewbuild --on 5.20.3 -o 5.8.9

Install three new instances of perl, randomly

    brewbuild --new 3

Enable verbose output. Default is 0, maximum is 7

    brewbuild --debug 5

Remove all perl instances (less the currently used one), install two new random
versions, and run tests against all installed perls

    brewbuild --remove --new 2

Install all available perl versions, and run tests against all of them

    brewbuild --new -1

Install a specific version and run tests on all instances (include just the
number portion of the version per "perlbrew available" or "berrybrew available"

    brewbuild --version 5.20.3

...multiple versions can be passed in at once

    brewbuild -v 5.20.3 -v 5.14.4 -v 5.23.5

=head1 DESCRIPTION

This C<brewbuild> script installed by the L<Test::Brewbuild> module allows you
to perform your unit tests across all of your Perlbrew (Unix) or Berrybrew
(Windows) Perl instances, with the ability to very easily create your own
plugins that contain the code that C<perlbrew/berrybrew exec> will process.
(See L<Test::BrewBuild::Plugin::DefaultExec> for an example).

For Windows, you'll need to install Berrybrew (see L<SEE ALSO> for details).
For Unix, you'll need Perlbrew.

It allows you to remove and reinstall on each test run, install random versions
of perl, or install specific versions.

All unit tests are run against all installed instances.

The actual module is just a helper for the installed script, and isn't designed
for end-user use.

=head1 AUTHOR

Steve Bertrand, C<< <steveb at cpan.org> >>

=head2 CONTRIBUTING

Any and all feedback and help is appreciated. A Pull Request is the preferred
method of receiving changes (L<https://github.com/stevieb9/p5-test-brewbuild>),
but regular patches through the bug tracker, or even just email discussions are
welcomed.

=head1 BUGS

L<https://github.com/stevieb9/p5-test-brewbuild/issues>

=head1 SUPPORT

You can find documentation for this script and module with the perldoc command.

    perldoc brewbuild
    perldoc Test::BrewBuild

=head1 SEE ALSO

Berrybrew for Windows:

L<https://github.com/dnmfarrell/berrybrew>

Perlbrew for Unixes:

L<http://perlbrew.pl>

=head1 LICENSE AND COPYRIGHT

Copyright 2016 Steve Bertrand.

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See L<http://dev.perl.org/licenses/> for more information.
