#!perl

use strict;
use warnings;

my $showversion;
my $showhelp;
while($ARGV[0] =~ /^-/) {
    if($ARGV[0] eq '--showmoduleversions') {
        $showversion = 1;
        shift;
    } elsif($ARGV[0] =~ /^(-h|--help)$/) {
        $showhelp = 1;
        shift;
    }
}
if($showhelp || $ARGV[0] eq 'help') { exec('perldoc', $0); }

eval "use CPAN::FindDependencies;";
if($@) {
    die "Couldn't load CPAN::FindDependencies.\n";
}

my $target = shift;
my @deps = CPAN::FindDependencies::finddeps(
    $target,
    nowarnings => 1,
    @ARGV
);

foreach my $dep (@deps) {
    print '  ' x $dep->depth();
    print '*' if($dep->warning());
    print $dep->name().' (dist: '.$dep->distribution();
    print ', mod ver: '.$dep->version() if($showversion && $dep->name() ne $target);
    print ")\n";
}

=head1 NAME

cpandeps - show a module on the CPAN's dependency tree.

=head1 DESCRIPTION

This program is a simple wrapper around CPAN::FindDependencies.

=head1 SYNOPSIS

    cpandeps CPAN::FindDependencies

    cpandeps CPAN::FindDependencies perl 5.8.8 cachedir ../foo/bar

    cpandeps --showmoduleversions CPAN::FindDependencies

Given a module name, this program will show you the module's
dependency tree.  It takes exactly the same arguments as the
C<finddeps> function of CPAN::FindDependencies, with the exception
that C<nowarnings> is turned *on* by default.

=over

=item nowarnings

Warnings about modules where we can't find their META.yml or Makefile.PL, and
so can't divine their pre-requisites, will be suppressed;

=item fatalerrors

Failure to get a module's dependencies will be a fatal error
instead of merely emitting a warning;

=item perl

Use this version of perl to figure out what's in core.  If not
specified, it defaults to 5.005.  Three part version numbers
(eg 5.8.8) are supported but discouraged.

=item cachedir

A directory to use for caching.  It defaults to no caching.  Even if
caching is turned on, this is only for META.yml or Makefile.PL files.

The cache is never automatically cleared out. It is your responsibility
to clear out old data.

=item maxdepth

Cuts off the dependency tree at the specified depth.  Your specified
module is at depth 0, your dependencies at depth 1, their dependencies
at depth 2, and so on.

If you don't specify any maxdepth at all it will grovel over the
entire tree.

=item mirror

This can be provided more than once, if for example you want to use
a private L<Pinto> repository for your own code while using a public
CPAN mirror for open source dependencies. The argument comes in two parts
separated by a comma - the base URL from which to fetch files, and
optionally the URL or a file from which to fetch the index
C<02packages.details.txt.gz> file to use with that mirror.

  mirror https://cpan.mydomain.net,file:///home/me/mycache/02packages.txt.gz

If you want to use the default CPAN mirror (https://cpan.metacpan.org/)
but also specify an index location you can use C<DEFAULT> for the mirror URL.

So for example, to use your own special private mirror, including fetching
02packages from it, but also use the default mirror with a cached local
copy of its 02packages, specify two mirrors thus:

  mirror => 'https://cpan.mydomain.net',
  mirror => 'DEFAULT,file:///home/me/mycache/02packages.txt.gz'

The index is cached for three minutes or until your process finishes, whichever is soonest. This is because it is HUMUNGOUS and parsing it takes ages even when it's loaded from a local disk, and I don't want the tests to take forever.

=item usemakefilepl

If set to true, then for any module that doesn't have a META.yml,
try to use its Makefile.PL as well.  Note that this involves
downloading code from the Internet and running it.  This obviously
opens you up to all kinds of bad juju, hence why it is disabled
by default. NB that this fetches Makefile.PL from
L<https://fastapi.metacpan.org> B<only> so will not work for private mirrors.
This is a deliberate choice, your own private code ought to be packaged
properly with a META file, you should only care about divining dependencies
from Makefile.PL if you rely on really old stuff on public CPAN mirrors.

=item recommended

Adds recommended modules to the list of dependencies, if set to a true value.

=item suggested

Adds suggested modules to the list of dependencies, if set to a true value.


=back

It also takes the following extra parameter, which must be the first one:

=over

=item --showmoduleversions

If present, the required version of each module is also shown

=back

It shows the module name, its distribution, and if any warnings were
raised (such as if a module's dependencies couldn't be fetched) this
is indicated with an asterisk before the module's name.

=head1 INCOMPATIBLE CHANGES

Up to version 2.49 you used the C<02packages> argument to specify where a
cached C<02packages.details.txt.gz> could be found. That argument no longer
exists as of version 3.00, use the C<mirror> argument instead.

Up to version 2.49, C<maxdepth =E<gt> 0> would incorrectly return the whole
tree. From version 3.00 it cuts the tree off at its root so will only return
the module that you asked about. Not very useful, but correct.

In version 2.49 you used the C<configreqs> argument to specify that you were
interested in configure-time requirements as well as build- and run-time
requirements. That option no longer exists as of version 3.00, it will always
report on configure, build, test, and run-time requirements.


=head1 WARNINGS, BUGS and FEEDBACK

This script has not been thoroughly tested.

I welcome feedback about my code, including constructive criticism.
Bug reports should be made on Github or by email.

=head1 SEE ALSO

L<CPAN::FindDependencies>

L<http://deps.cpantesters.org/>

=head1 AUTHOR, LICENCE and COPYRIGHT

Copyright 2007 - 2020 David Cantrell E<lt>F<david@cantrell.org.uk>E<gt>

This software is free-as-in-speech software, and may be used,
distributed, and modified under the terms of either the GNU
General Public Licence version 2 or the Artistic Licence. It's
up to you which one you use. The full text of the licences can
be found in the files GPL2.txt and ARTISTIC.txt, respectively.

=head1 CONSPIRACY

This software is also free-as-in-mason.

=cut
