#!/usr/bin/perl
use v5.16;

use strict;
use Pod::Usage 1.12;
use Getopt::Long;
use YAML qw( Load );
use CPAN::Mini::Inject;
use Env;
use File::Slurp 'write_file';
use File::Temp;

our $VERSION = '0.38';
our %options = ();

sub print_version {
  printf( "mcpani v%s, using CPAN::Mini::Inject v%s and Perl v%vd\n",
    $VERSION, $CPAN::Mini::Inject::VERSION, $^V );
}

sub chkactions {
  for my $action ( qw(add update mirror inject) ) {
    return 1 if ( $options{actionname} eq $action );
  }
  return 0;
}

sub setsub {
  $options{actionname} = shift;
  $options{action}     = shift;
}

sub add {
  my $mcpi = shift;

  $mcpi->readlist;

    $mcpi->add(
      module   => $options{module},
      authorid => $options{authorid},
      version  => $options{version},
      file     => $options{file}
    );

  if ( $options{verbose} ) {
    my @added = $mcpi->added_modules;
    foreach my $added ( @added ){
      print "\nAdding File: $added->{file}\n";
      print "Author ID: $added->{authorid}\n";
      my $modules = $added->{modules};
      foreach my $mod ( sort keys %$modules ){
        print "Module: $mod\n";
        print "Version: $modules->{$mod}\n";
      }
      print "To repository: $mcpi->{config}{repository}\n\n";
    }
  }
  $mcpi->writelist;

}

sub update {
  my $mcpi = shift;

  mirror( $mcpi );
  inject( $mcpi );
}

sub mirror {
  my $mcpi = shift;

  # these come from the command line
  my %mirroropts =
    map { $_ => $options{$_} }
    grep { defined $options{$_} }
    qw(remote local verbose);

  $mcpi->update_mirror( %mirroropts );
}

sub inject {
  my $mcpi = shift;

  print "Injecting modules from $mcpi->{config}{repository}\n"
   if ( $options{verbose} );
  $mcpi->inject( $options{verbose} );
}

# MAIN
Getopt::Long::Configure( 'no_ignore_case' );
Getopt::Long::Configure( 'bundling' );

GetOptions(
  'h|help|?' =>
   sub { pod2usage( { -verbose => 1, -input => \*DATA } ); exit },
  'H|man' =>
   sub { pod2usage( { -verbose => 2, -input => \*DATA } ); exit },
  'V|version' => sub { print_version(); exit; },
  'v|verbose' => \$options{verbose},
  'l|local=s' => \$options{local},
  'r|remote=s'   => \$options{remote},
  'p|passive'    => \$ENV{FTP_PASSIVE},
  'add'          => sub { setsub( 'add', \&add ) },
  'update'       => sub { setsub( 'update', \&update ) },
  'mirror'       => sub { setsub( 'mirror', \&mirror ) },
  'inject'       => sub { setsub( 'inject', \&inject ) },
  'module=s'     => \$options{module},
  'authorid=s'   => \$options{authorid},
  'modversion=s' => \$options{version},
  'file=s'       => \$options{file},
  'all-in-meta'  => \$options{'all-in-meta'},
  'signing-key=s' => \$options{'signing_key'},
  'discover-packages' => \$options{'discover-packages'},
) or exit 1;

unless ( defined( $options{action} ) && chkactions() ) {
  pod2usage( { -verbose => 1, -input => \*DATA } );
  exit;
}

my $mcpi = CPAN::Mini::Inject->new->loadcfg( $options{cfg} )->parsecfg;

$CPAN::Checksums::SIGNING_KEY = $options{'signing_key'}
    if ($options{'signing_key'});

&{ $options{action} }( $mcpi );

__END__

=head1 NAME

mcpani -- A command line tool to manage a CPAN Mini Mirror.

=head1 SYNOPSIS

mcpani [options] < --add | --update | --mirror | --inject >

Commands:

    --add               Add a new package to the repository
          --module      Name of the module to add
          --authorid    Author ID of the module
          --modversion  Version number of the module
          --file        distribution module

    --update            Update local CPAN mirror and inject modules
    --mirror            Update local CPAN mirror from remote
    --inject            Add modules from repository to CPAN mirror

Options:

    -h, --help          This synopsis
    -H, --man           Detailed description

    -l, --local         local location for CPAN::Mini Mirror
    -r, --remote        CPAN mirror to mirror from
    -p, --passive       Enable passive ftp for mirroring.
    -v, --verbose       verbose output
    -V, --version       Version information.
        --signing-key   See CPAN::Checksums $SIGNING_KEY

=head1 DESCRIPTION

B<mcpani> uses L<CPAN::Mini> to build or update a local CPAN mirror from a
remote one, while also adding private or third-party distributions.

=head2 Configuration file

B<mcpani> will search the following four places in order:

=over 4

=item * file pointed to by the environment variable MCPANI_CONFIG

=item * $HOME/.mcpani/config

=item * /usr/local/etc/mcpani

=item * /etc/mcpani

=back

By default, B<mcpani> uses a simple configuration file in the following format:

 local: /www/CPAN
 remote: ftp://ftp.cpan.org/pub/CPAN ftp://ftp.kernel.org/pub/CPAN
 repository: /work/mymodules
 passive: yes
 dirmode: 0755

=head2 Configuration options

=over 4

=item C<local> (required)

location to store local CPAN::Mini mirror

=item C<remote> (required)

CPAN site(s) to mirror from. Multiple sites can be listed, with spaces
between them.

=item C<repository>

Location to store modules to add to the local CPAN::Mini mirror.

=item C<passive>

Enable passive FTP.

=item C<dirmode>

Set the permissions of created directories to the specified mode
(octal value). The default value is based on the umask (if supported).

=back

=head2 Command-line options

=over 4

=item C<--add>

=over 4

=item C<--authorid> the CPAN ID

=item C<--file> the distribution file

=item C<--module> the package name of the main module

=item C<-v>, C<--verbose>

=item C<--version> the version of the distribution

=back

=item C<-h>, C<-H>, C<--help>, C<--man>, C<-?>

Output a help message and exit.

=item C<--inject>

Inject the local distributions into the local repository.

=over 4

=item C<-v>, C<--verbose>

=back

=item C<--mirror>

Update the local MiniCPAN by downloading the latest modules from the
public CPAN (or the CPAN-like repo specified in the C<remote> config.
C<--mirror> uses

=over 4

=item C<-l>, C<--local>

=item C<-r>, C<--remote>

=item C<-v>, C<--verbose>

=back

=item C<--update>

This runs C<--mirror> then C<--inject>.

=item  C<-V>, C<--version>

Output the version of B<mcpani> and exit.

=back

=head1 AUTHOR

Shawn Sorichetti C<< <ssoriche@coloredblocks.net> >>

=head1 ISSUES

Report issues to the GitHub queue:

	https://github.com/briandfoy/cpan-mini-inject/issues

=head1 COPYRIGHT & LICENSE

Copyright 2004 Shawn Sorichetti, All Rights Reserved.

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

=cut
