#!perl

our $DATE = '2015-04-07'; # DATE
our $VERSION = '0.14'; # VERSION

use 5.010;
use strict;
use warnings;

use Module::List qw(list_modules);
use Perinci::CmdLine::Any;

my $prefix = '/App/lcpan/';
my $mods = list_modules("App::lcpan::Cmd::", {list_modules=>1});
my $subcommands = {};
for my $mod (keys %$mods) {
    (my $sc_name = $mod) =~ s/App::lcpan::Cmd:://;
    $sc_name =~ s/_/-/g;

    # disable these first, they are too slow
    next if $sc_name =~ /\A(authors-by-mod-count|authors-by-rel-count)\z/;

    (my $url = $mod) =~ s!::!/!g;
    $subcommands->{$sc_name} = {
        url => "/$url/handle_cmd",
    };
}

Perinci::CmdLine::Any->new(
    url => $prefix,
    log => 1,
    subcommands => $subcommands,
)->run;

# ABSTRACT: Manage your local CPAN mirror
# PODNAME: lcpan

__END__

=pod

=encoding UTF-8

=head1 NAME

lcpan - Manage your local CPAN mirror

=head1 VERSION

This document describes version 0.14 of lcpan (from Perl distribution App-lcpan), released on 2015-04-07.

=head1 SYNOPSIS

=head2 Update (download and index) your local CPAN mirror

 % lcpan update

A mini CPAN mirror will be downloaded in your C<~/cpan> directory. This will
take a while (it downloads +- 4GB of files, as of this writing; subsequent
update will of course take shorter time.)

A SQLite database is also created/updated in C<~/cpan/index.db> which contains
information about authors, modules/packages, distributions. This database is
used for quickly answer various queries.

You can run the above command e.g. daily to keep your mirror up-to-date.

=head2 Using your local CPAN mirror to install modules

 % lcpanm -n Some::Module

C<lcpanm> is a thin wrapper for C<cpanm>, the above command is equivalent to:

 % cpanm --mirror ~/cpan --mirror-only -n Some::Module

=head2 Querying your local CPAN mirror

Info about your local CPAN mirror:

 % lcpan stats
 +------------------------------+----------------------+
 | key                          | value                |
 | last_index_time              | 2015-01-15T13:09:25Z |
 | mirror_mtime                 | 2015-01-15T13:09:22Z |
 | num_authors                  | 11981                |
 | num_dists                    | 30376                |
 | num_modules                  | 151927               |
 | num_releases                 | 31877                |
 | num_releases_with_buildpl    | 6521                 |
 | num_releases_with_makefilepl | 28948                |
 | num_releases_with_metajson   | 10625                |
 | num_releases_with_metayml    | 10689                |
 | schema_version               | 3                    |
 +------------------------------+----------------------+

Add C<--verbose> if you want more stats which normally are skipped because they
can take a while to get (e.g. disk-space).

B<List modules:>

 % lcpan modules
 % lcpan modules SOMEQUERY --detail
 % lcpan modules --author PERLANCAR ;# modules by some author only
 % lcpan modules --dist libwww-perl ;# from certain dist only

B<List distributions:>

 % lcpan dists
 % lcpan dists SOMEQUERY --detail
 % lcpan dists --author PERLANCAR ;# from certain author only

B<List authors:>

 % lcpan authors
 % lcpan authors SOMEQUERY --detail

B<List releases (tarballs):>

 % lcpan releases
 % lcpan releases SOMEQUERY --detail
 % lcpan releases --author PERLANCAR ;# from certain authors only
 % lcpan releases --author PERLANCAR ;# from certain authors only

B<Show dependencies and reverse dependencies>:

 % lcpan deps Text::ANSITable    ;# which modules does Text::ANSITable depend on?
 % lcpan deps Text::ANSITable -R ;# recursive
 % lcpan deps Task::BeLike::CSSON --phase build
 % lcpan deps Text::ANSITable --phase ALL --rel ALL

 % lcpan rdeps Text::ANSITable ;# which dists depend on Text::ANSITable?

B<Some other utilities>:

 % lcpan mod2dist Text::ANSITable::ColorTheme::Default ;# -> Text-ANSITable

 % lcpan mod2rel  Text::ANSITable::ColorTheme::Default ;# -> Text-ANSITable-0.39.tar.gz
 % lcpan mod2rel  Text::ANSITable --full-path          ;# -> /cpan/authors/id/P/PE/PERLANCAR/Text-ANSITable-0.39.tar.gz

 % lcpan dist2rel Text-ANSITable             ;# -> Text-ANSITable-0.39.tar.gz
 % lcpan dist2rel Text-ANSITable --full-path ;# -> /cpan/authors/id/P/PE/PERLANCAR/Text-ANSITable-0.39.tar.gz

 % lcpan distmods Text-ANSITable ;# list modules in a distribution
 Text::ANSITable
 Text::ANSITable::BorderStyle::Default
 Text::ANSITable::ColorTheme::Default
 Text::ANSITable::StyleSet::AltRow

 % lcpan authormods PERLANCAR   ;# list an author's modules
 % lcpan authordists PERLANCAR  ;# list an author's dists
 % lcpan authorrels PERLANCAR   ;# list an author's releases

More subcommands are available. lcpan is plugin-based, see/install
C<App::lcpan::Cmd::*> modules for more subcommands.

=head1 DESCRIPTION

This application is a convenient bundling of C<CPAN::Mini> and an indexer so in
addition to creating your local CPAN mirror and installing modules from it, you
can also query various things about your local CPAN mirror quickly from the
command-line (as well as programmatically). Powerful and more convenient
querying is the main reason C<lcpan> is created.

=head1 SUBCOMMANDS

=head2 B<authordists>

List distributions of an author.

=head2 B<authormods>

List modules of an author.

=head2 B<authorrels>

List releases of an author.

=head2 B<authors>

List authors.

=head2 B<deps>

List dependencies of a module, data from local CPAN.

By default only runtime requires are displayed. To see prereqs for other phases
(e.g. configure, or build, or ALL) or for other relationships (e.g. recommends,
or ALL), use the C<--phase> and C<--rel> options.

Note that dependencies information are taken from C<META.json> or C<META.yml>
files. Not all releases (especially older ones) contain them. C<lcpan> (like
MetaCPAN) does not extract information from C<Makefile.PL> or C<Build.PL> because
that requires running (untrusted) code.

Also, some releases specify dynamic config, so there might actually be more
dependencies.


=head2 B<dist2rel>

Get (latest) release name of a distribution.

=head2 B<distmods>

List modules in a distribution.

=head2 B<dists>

List distributions.

=head2 B<mod2dist>

Get distribution name of a module.

=head2 B<mod2rel>

Get (latest) release name of a module.

=head2 B<modules>

List packages/modules.

=head2 B<rdeps>

List reverse dependencies of a module, data from local CPAN.

=head2 B<releases>

List releases/tarballs.

=head2 B<stats>

Statistics of your local CPAN mirror.

=head2 B<update>

Update local CPAN mirror files, followed by create/update the index.db.

This subcommand calls the C<update-files> followed by C<update-index>.


=head2 B<update-files>

Update local CPAN mirror files using minicpan command.

This subcommand runs the C<minicpan> command to download/update your local CPAN
mirror files.

Note: you can also run C<minicpan> yourself.


=head2 B<update-index>

Create/update index.db in local CPAN mirror.

This subcommand is called by the C<update> subcommand after C<update-files> but
can be performed separately via C<update-index>. Its task is to create/update
C<index.db> SQLite database containing list of authors, modules, dists, and
dependencies.

It gets list of authors from parsing C<authors/01mailrc.txt.gz> file.

It gets list of packages from parsing C<modules/02packages.details.txt.gz>.
Afterwards, it tries to extract dist metadata C<META.yml> or C<META.json> from
each release file to get distribution name, abstract, and dependencies
information.

=head1 OPTIONS

C<*> marks required options.

=head2 Common options

=over

=item B<--cpan>=I<s>

Location of your local CPAN mirror, e.g. /path/to/cpan.

Defaults to C<~/cpan>.


=item B<--index-name>=I<s>

Filename of index.

Default value:

 "index.db"

=back

=head2 Options for subcommand authordists

=over

=item B<--author>=I<s>*

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--latest>

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand authormods

=over

=item B<--author>=I<s>*

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand authorrels

=over

=item B<--author>=I<s>*

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--full-path>

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--latest>

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand authors

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--detail>

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--query>=I<s>, B<-q>

Search query.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand deps

=over

=item B<--all>

Equivalent to --phase ALL --rel ALL.

See C<--phase>.

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--include-core>

Include Perl core modules.

=item B<--json>

Set output format to json.

=item B<--level>=I<i>, B<-l>

Recurse for a number of levels (-1 means unlimited).

Default value:

 1

=item B<--log-level>=I<s>

Set log level.

=item B<--module>=I<s>*

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--perl-version>=I<s>, B<-V>

Set base Perl version for determining core modules.

Default value:

 "v5.18.4"

=item B<--phase>=I<s>

Default value:

 "runtime"

Valid values:

 ["develop","configure","build","runtime","test","ALL"]

=item B<--quiet>

Set log level to quiet.

=item B<--rel>=I<s>

Default value:

 "requires"

Valid values:

 ["requires","recommends","suggests","conflicts","ALL"]

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=item B<-R>

Recurse (alias for `--level -1`).

See C<--level>.

=back

=head2 Options for subcommand dist2rel

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--dist>=I<s>*

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--full-path>

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand distmods

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--dist>=I<s>*

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand dists

=over

=item B<--author>=I<s>, B<-a>

Filter by author.

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--detail>

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--latest>

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--query>=I<s>, B<-q>

Search query.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand mod2dist

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--module>=I<s>*

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand mod2rel

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--full-path>

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--module>=I<s>*

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand modules

=over

=item B<--author>=I<s>, B<-a>

Filter by author.

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--detail>

=item B<--dist>=I<s>, B<-d>

Filter by distribution.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--query>=I<s>, B<-q>

Search query.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand rdeps

=over

=item B<--author-isnt-json>=I<s>

Filter out certain author (JSON-encoded).

See C<--author-isnt>.

=item B<--author-isnt>=I<s@>

Filter out certain author.

This can be used to filter out certain author(s). For example if you want to
know whether a module is being used by another CPAN author instead of just
herself.


Can be specified multiple times.

=item B<--author-json>=I<s>

Filter certain author (JSON-encoded).

See C<--author>.

=item B<--author>=I<s@>

Filter certain author.

This can be used to select certain author(s).


Can be specified multiple times.

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--module>=I<s>*

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand releases

=over

=item B<--author>=I<s>, B<-a>

Filter by author.

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--detail>

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--full-path>

=item B<--has-buildpl>

=item B<--has-makefilepl>

=item B<--has-metajson>

=item B<--has-metayml>

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--latest>

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--query>=I<s>, B<-q>

Search query.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand stats

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand update

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand update-files

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--max-file-size>=I<i>

If set, skip downloading files larger than this.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--quiet>

Set log level to quiet.

=item B<--remote-url>=I<s>

Select CPAN mirror to download from.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head2 Options for subcommand update-index

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--debug>

Set log level to debug.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--json>

Set output format to json.

=item B<--log-level>=I<s>

Set log level.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--num-backups>=I<i>

Keep a number of backups.

Default value:

 7

Will create `index.db.1`, `index.db.2` and so on containing the older indexes.


=item B<--quiet>

Set log level to quiet.

=item B<--subcommands>

List available subcommands.

=item B<--trace>

Set log level to trace.

=item B<--verbose>

Set log level to info.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head1 MORE EXAMPLE QUERIES AND COMMANDS FOR CPAN USERS

=head2 Show how many dists will need to be installed if I install this module

TODO

=head2 Install all modules from a certain CPAN author

 % lcpan authormods PERLANCAR | cpanm -n

or (if you want to install from local CPAN mirror):

 % lcpan authormods PERLANCAR | lcpanm -n

or (specify release files directly):

 % lcpan authorrels --latest PERLANCAR | cpanm -n

=head2 Update all modules on your system, from local CPAN mirror

 % cpan-outdated --mirror file:$HOME/cpan | cpanm -n

=head1 MORE EXAMPLE QUERIES AND COMMANDS FOR CPAN AUTHORS

=head2 Count your CPAN modules, dists, and releases

 % lcpan authormods  PERLANCAR | wc -l
 % lcpan authordists PERLANCAR | wc -l
 % lcpan authorrels  PERLANCAR | wc -l

=head2 Show your old releases (which you should probably delete from CPAN?)

 % setop --diff <(lcpan authorrels PERLANCAR) <(lcpan authorrels PERLANCAR --latest)

=head2 Show other people using your modules on CPAN

 % for mod in `lcpan modules --author CSSON`; do
     res=`lcpan rdeps "$mod" --author-isnt CSSON --format text-pretty`
     if [[ "$res" != "" ]]; then echo -e "$mod is used by:\n$res\n"; fi
   done

Sample output:

 Map::Metro::Plugin::Map is used by:
 +--------+-----------------------------+--------------+-------------+
 | cpanid | dist                        | dist_version | req_version |
 | SREZIC | Map-Metro-Plugin-Map-Berlin | 0.02         | 0.18        |
 +--------+-----------------------------+--------------+-------------+

 MojoX::CustomTemplateFileParser is used by:
 +--------+-------------------------------------+--------------+-------------+
 | cpanid | dist                                | dist_version | req_version |
 | RENEEB | Task-MojoliciousPlugins-PerlAcademy | 0.02         | 0.10        |
 +--------+-------------------------------------+--------------+-------------+

 Mojolicious::Plugin::BootstrapHelpers is used by:
 +--------+-------------------------------------+--------------+-------------+
 | cpanid | dist                                | dist_version | req_version |
 | RENEEB | Task-MojoliciousPlugins-PerlAcademy | 0.02         | 0.0187      |
 +--------+-------------------------------------+--------------+-------------+

 Test::Mojo::Trim is used by:
 +--------+----------------+--------------+-------------+
 | cpanid | dist           | dist_version | req_version |
 | LEEJO  | Test-Mojo-Most | 0.05         | 0.03        |
 +--------+----------------+--------------+-------------+

=head2 More complex queries

For more complex queries, you can always access the SQLite database directly.

=head1 FAQ

=head2 How to customize location of local CPAN mirror?

By default CPAN mirror is put in C<~/cpan>. To customize this, use the C<--cpan>
option, e.g.:

 % lcpan update --cpan /path/to/my/cpan

You can also create a configuration C<~/lcpan.conf> so you don't have to specify
the C<--cpan> option everytime:

 cpan=/path/to/my/cpan

=head2 Where is the SQLite database index located?

In C<$cpan/index.db>.

=head2 How do I reindex from scratch (without downloading the mirror)?

Just delete the C<index.db> and run C<lcpan update-index> again.

=head2 How do I download the mirror without indexing?

Run C<lcpan update-files>.

=head1 SEE ALSO

L<setop>

L<cpan-outdated>

=head1 COMPLETION

This script has shell tab completion capability with support for several
shells.

=head2 bash

To activate bash completion for this script, put:

 complete -C lcpan lcpan

in your bash startup (e.g. C<~/.bashrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is recommended, however, that you install L<shcompgen> which allows you to
activate completion scripts for several kinds of scripts on multiple shells.
Some CPAN distributions (those that are built with
L<Dist::Zilla::Plugin::GenShellCompletion>) will even automatically enable shell
completion for their included scripts (using C<shcompgen>) at installation time,
so you can immadiately have tab completion.

=head2 tcsh

To activate tcsh completion for this script, put:

 complete lcpan 'p/*/`lcpan`/'

in your tcsh startup (e.g. C<~/.tcshrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is also recommended to install C<shcompgen> (see above).

=head2 other shells

For fish and zsh, install C<shcompgen> as described above.

=head1 ENVIRONMENT

LCPAN_OPT

=head1 CONFIGURATION FILE

This script can read configuration file, which by default is searched at C<~/.config/lcpan.conf>, C<~/lcpan.conf> or C</etc/lcpan.conf> (can be changed by specifying C<--config-path>). All found files will be read and merged.

Configuration file is in the format of L<IOD>, which is basically INI with some extra features. Section names map to subcommand names. 

You can put multiple profiles in a single file by using section names like C<[profile=SOMENAME]> or C<[SUBCOMMAND_NAME profile=SOMENAME]>. Those sections will only be read if you specify the matching C<--config-profile SOMENAME>.

List of available configuration parameters:

=head2 Common for all subcommands

 cpan (see --cpan)
 index_name (see --index-name)

=head2 For subcommand 'authordists'

 author (see --author)
 format (see --format)
 latest (see --latest)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'authormods'

 author (see --author)
 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'authorrels'

 author (see --author)
 format (see --format)
 full_path (see --full-path)
 latest (see --latest)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'authors'

 detail (see --detail)
 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)
 query (see --query)

=head2 For subcommand 'deps'

 format (see --format)
 include_core (see --include-core)
 level (see --level)
 log_level (see --log-level)
 module (see --module)
 naked_res (see --naked-res)
 perl_version (see --perl-version)
 phase (see --phase)
 rel (see --rel)

=head2 For subcommand 'dist2rel'

 dist (see --dist)
 format (see --format)
 full_path (see --full-path)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'distmods'

 dist (see --dist)
 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'dists'

 author (see --author)
 detail (see --detail)
 format (see --format)
 latest (see --latest)
 log_level (see --log-level)
 naked_res (see --naked-res)
 query (see --query)

=head2 For subcommand 'mod2dist'

 format (see --format)
 log_level (see --log-level)
 module (see --module)
 naked_res (see --naked-res)

=head2 For subcommand 'mod2rel'

 format (see --format)
 full_path (see --full-path)
 log_level (see --log-level)
 module (see --module)
 naked_res (see --naked-res)

=head2 For subcommand 'modules'

 author (see --author)
 detail (see --detail)
 dist (see --dist)
 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)
 query (see --query)

=head2 For subcommand 'rdeps'

 author (see --author)
 author_isnt (see --author-isnt)
 format (see --format)
 log_level (see --log-level)
 module (see --module)
 naked_res (see --naked-res)

=head2 For subcommand 'releases'

 author (see --author)
 detail (see --detail)
 format (see --format)
 full_path (see --full-path)
 has_buildpl (see --has-buildpl)
 has_makefilepl (see --has-makefilepl)
 has_metajson (see --has-metajson)
 has_metayml (see --has-metayml)
 latest (see --latest)
 log_level (see --log-level)
 naked_res (see --naked-res)
 query (see --query)

=head2 For subcommand 'stats'

 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'update'

 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)

=head2 For subcommand 'update-files'

 format (see --format)
 log_level (see --log-level)
 max_file_size (see --max-file-size)
 naked_res (see --naked-res)
 remote_url (see --remote-url)

=head2 For subcommand 'update-index'

 format (see --format)
 log_level (see --log-level)
 naked_res (see --naked-res)
 num_backups (see --num-backups)

=head1 FILES

~/.config/lcpan.conf

~/lcpan.conf

/etc/lcpan.conf

~/.config/lcpan.conf

~/lcpan.conf

/etc/lcpan.conf

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/App-lcpan>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-App-lcpan>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-lcpan>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by perlancar@cpan.org.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
