This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade CPAN from version 2.05 to 2.09-TRIAL
[perl5.git] / cpan / CPAN / lib / App / Cpan.pm
index b548bcc..e8c9bb7 100644 (file)
@@ -4,9 +4,9 @@ use strict;
 use warnings;
 use vars qw($VERSION);
 
-use if $] < 5.008 => "IO::Scalar";
+use if $] < 5.008 => 'IO::Scalar';
 
-$VERSION = '1.62';
+$VERSION = '1.63';
 
 =head1 NAME
 
@@ -23,6 +23,9 @@ App::Cpan - easily interact with CPAN from the command line
        # use local::lib
        cpan -I module_name [ module_name ... ]
 
+       # one time mirror override for faster mirrors
+       cpan -p ...
+
        # with just the dot, install from the distribution in the
        # current directory
        cpan .
@@ -135,6 +138,11 @@ List the modules by the specified authors.
 
 Make the specified modules.
 
+=item -M mirror1,mirror2,...
+
+A comma-separated list of mirrors to use for just this run. The C<-P>
+option can find them for you automatically.
+
 =item -n
 
 Do a dry run, but don't actually install anything. (unimplemented)
@@ -145,11 +153,12 @@ Show the out-of-date modules.
 
 =item -p
 
-Ping the configured mirrors
+Ping the configured mirrors and print a report
 
 =item -P
 
-Find the best mirrors you could be using (but doesn't configure them just yet)
+Find the best mirrors you could be using and use them for the current
+session.
 
 =item -r
 
@@ -208,6 +217,51 @@ and tells you about problems you might have.
        # force install modules ( must use -i )
        cpan -fi CGI::Minimal URI
 
+       # install modules but without testing them
+       cpan -Ti CGI::Minimal URI
+
+=head2 Environment variables
+
+There are several components in CPAN.pm that use environment variables.
+The build tools, L<ExtUtils::MakeMaker> and L<Module::Build> use some,
+while others matter to the levels above them. Some of these are specified
+by the Perl Toolchain Gang:
+
+Lancaster Concensus: L<https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>
+
+Oslo Concensus: L<https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/oslo-consensus.md>
+
+=over 4
+
+=item NONINTERACTIVE_TESTING
+
+Assume no one is paying attention and skips prompts for distributions
+that do that correctly. C<cpan(1)> sets this to C<1> unless it already
+has a value (even if that value is false).
+
+=item PERL_MM_USE_DEFAULT
+
+Use the default answer for a prompted questions. C<cpan(1)> sets this
+to C<1> unless it already has a value (even if that value is false).
+
+=item CPAN_OPTS
+
+As with C<PERL5OPTS>, a string of additional C<cpan(1)> options to
+add to those you specify on the command line.
+
+=item CPANSCRIPT_LOGLEVEL
+
+The log level to use, with either the embedded, minimal logger or
+L<Log::Log4perl> if it is installed. Possible values are the same as
+the C<Log::Log4perl> levels: C<TRACE>, C<DEBUG>, C<INFO>, C<WARN>,
+C<ERROR>, and C<FATAL>. The default is C<INFO>.
+
+=item GIT_COMMAND
+
+The path to the C<git> binary to use for the Git features. The default
+is C</usr/local/bin/git>.
+
+=back
 
 =head2 Methods
 
@@ -216,7 +270,7 @@ and tells you about problems you might have.
 =cut
 
 use autouse Carp => qw(carp croak cluck);
-use CPAN ();
+use CPAN 1.80 (); # needs no test
 use Config;
 use autouse Cwd => qw(cwd);
 use autouse 'Data::Dumper' => qw(Dumper);
@@ -245,7 +299,7 @@ BEGIN { # most of this should be in methods
 use vars qw( @META_OPTIONS $Default %CPAN_METHODS @CPAN_OPTIONS  @option_order
        %Method_table %Method_table_index );
 
-@META_OPTIONS = qw( h v V I g G C A D O l L a r p P j: J w T);
+@META_OPTIONS = qw( h v V I g G M: C A D O l L a r p P j: J w T);
 
 $Default = 'default';
 
@@ -257,6 +311,7 @@ $Default = 'default';
        'm'      => 'make',
        't'      => 'test',
        'u'      => 'upgrade',
+       'T'      => 'notest',
        );
 @CPAN_OPTIONS = grep { $_ ne $Default } sort keys %CPAN_METHODS;
 
@@ -283,8 +338,9 @@ sub GOOD_EXIT () { 0 }
        J =>  [ \&_dump_config,       NO_ARGS, GOOD_EXIT, 'Dump configuration to stdout' ],
        F =>  [ \&_lock_lobotomy,     NO_ARGS, GOOD_EXIT, 'Turn off CPAN.pm lock files'  ],
        I =>  [ \&_load_local_lib,    NO_ARGS, GOOD_EXIT, 'Loading local::lib'           ],
+       M =>  [ \&_use_these_mirrors,    ARGS, GOOD_EXIT, 'Setting per session mirrors'  ],
+       P =>  [ \&_find_good_mirrors, NO_ARGS, GOOD_EXIT, 'Finding good mirrors'         ],
     w =>  [ \&_turn_on_warnings,  NO_ARGS, GOOD_EXIT, 'Turning on warnings'          ],
-    T =>  [ \&_turn_off_testing,  NO_ARGS, GOOD_EXIT, 'Turning off testing'          ],
 
        # options that do their one thing
        g =>  [ \&_download,          NO_ARGS, GOOD_EXIT, 'Download the latest distro'        ],
@@ -299,7 +355,6 @@ sub GOOD_EXIT () { 0 }
        L =>  [ \&_show_author_mods,     ARGS, GOOD_EXIT, 'Showing author mods'          ],
        a =>  [ \&_create_autobundle, NO_ARGS, GOOD_EXIT, 'Creating autobundle'          ],
        p =>  [ \&_ping_mirrors,      NO_ARGS, GOOD_EXIT, 'Pinging mirrors'              ],
-       P =>  [ \&_find_good_mirrors, NO_ARGS, GOOD_EXIT, 'Finding good mirrors'         ],
 
        r =>  [ \&_recompile,         NO_ARGS, GOOD_EXIT, 'Recompiling'                  ],
        u =>  [ \&_upgrade,           NO_ARGS, GOOD_EXIT, 'Running `make test`'          ],
@@ -309,6 +364,7 @@ sub GOOD_EXIT () { 0 }
        i =>  [ \&_default,              ARGS, GOOD_EXIT, 'Running `make install`'       ],
    'm' => [ \&_default,              ARGS, GOOD_EXIT, 'Running `make`'               ],
        t =>  [ \&_default,              ARGS, GOOD_EXIT, 'Running `make test`'          ],
+       T =>  [ \&_default,              ARGS, GOOD_EXIT, 'Installing with notest'       ],
        );
 
 %Method_table_index = (
@@ -364,7 +420,9 @@ sub _process_setup_options
                        );
                }
 
-       foreach my $o ( qw(F I w T) )
+       $class->_turn_off_testing if $options->{T};
+
+       foreach my $o ( qw(F I w P M) )
                {
                next unless exists $options->{$o};
                $Method_table{$o}[ $Method_table_index{code} ]->( $options->{$o} );
@@ -385,13 +443,25 @@ sub _process_setup_options
 
        my $option_count = grep { $options->{$_} } @option_order;
        no warnings 'uninitialized';
-       $option_count -= $options->{'f'}; # don't count force
+
+       # don't count options that imply installation
+       foreach my $opt ( qw(f T) ) { # don't count force or notest
+               $option_count -= $options->{$opt};
+               }
 
        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # if there are no options, set -i (this line fixes RT ticket 16915)
        $options->{i}++ unless $option_count;
        }
 
+sub _setup_environment {
+# should we override or set defaults? If this were a true interactive
+# session, we'd be in the CPAN shell.
+
+# https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md
+       $ENV{NONINTERACTIVE_TESTING} = 1 unless defined $ENV{NONINTERACTIVE_TESTING};
+       $ENV{PERL_MM_USE_DEFAULT}    = 1 unless defined $ENV{PERL_MM_USE_DEFAULT};
+       }
 
 =item run()
 
@@ -424,13 +494,15 @@ sub run
 
        $class->_process_setup_options( $options );
 
+       $class->_setup_environment( $options );
+
        OPTION: foreach my $option ( @option_order )
                {
                next unless $options->{$option};
 
                my( $sub, $takes_args, $description ) =
                        map { $Method_table{$option}[ $Method_table_index{$_} ] }
-                       qw( code takes_args );
+                       qw( code takes_args description );
 
                unless( ref $sub eq ref sub {} )
                        {
@@ -464,6 +536,7 @@ sub _init_logger
 
     unless( $log4perl_loaded )
         {
+        print "Loading internal null logger. Install Log::Log4perl for logging messages\n";
         $logger = Local::Null::Logger->new;
         return $logger;
         }
@@ -494,7 +567,7 @@ sub _default
        # we'll deal with 'f' (force) later, so skip it
        foreach my $option ( @CPAN_OPTIONS )
                {
-               next if $option eq 'f';
+               next if ( $option eq 'f' or $option eq 'T' );
                next unless $options->{$option};
                $switch = $option;
                last;
@@ -512,24 +585,30 @@ sub _default
        my $method = $CPAN_METHODS{$switch};
        die "CPAN.pm cannot $method!\n" unless CPAN::Shell->can( $method );
 
-       # call the CPAN::Shell method, with force if specified
+       # call the CPAN::Shell method, with force or notest if specified
        my $action = do {
-               if( $options->{f} ) { sub { CPAN::Shell->force( $method, @_ ) } }
-               else                { sub { CPAN::Shell->$method( @_ )        } }
+                  if( $options->{f} ) { sub { CPAN::Shell->force( $method, @_ )  } }
+               elsif( $options->{T} ) { sub { CPAN::Shell->notest( $method, @_ ) } }
+               else                   { sub { CPAN::Shell->$method( @_ )         } }
                };
 
        # How do I handle exit codes for multiple arguments?
-       my $errors = 0;
+       my @errors = ();
 
        foreach my $arg ( @$args )
                {
                _clear_cpanpm_output();
                $action->( $arg );
 
-               $errors += defined _cpanpm_output_indicates_failure();
+               my $error = _cpanpm_output_indicates_failure();
+               push @errors, $error if $error;
                }
 
-       $errors ? I_DONT_KNOW_WHAT_HAPPENED : HEY_IT_WORKED;
+       return do {
+               if( @errors ) { $errors[0] }
+               else { HEY_IT_WORKED }
+               };
+
        }
 
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -571,21 +650,32 @@ sub _clear_cpanpm_output { $scalar = '' }
 
 sub _get_cpanpm_output   { $scalar }
 
+# These are lines I don't care about in CPAN.pm output. If I can
+# filter out the informational noise, I have a better chance to
+# catch the error signal
 my @skip_lines = (
        qr/^\QWarning \(usually harmless\)/,
        qr/\bwill not store persistent state\b/,
        qr(//hint//),
        qr/^\s+reports\s+/,
+       qr/^Try the command/,
+       qr/^\s+$/,
+       qr/^to find objects/,
+       qr/^\s*Database was generated on/,
+       qr/^Going to read/,
+       qr|^\s+i\s+/|,    # the i /Foo::Whatever/ line when it doesn't know
        );
 
 sub _get_cpanpm_last_line
        {
        my $fh;
-       if ($] < 5.008) {
-               $fh = IO::Scalar->new(\ $scalar);
-        } else {
-               eval q{open $fh, "<", \\ $scalar;};
-        }
+
+       if( $] < 5.008 ) {
+               $fh = IO::Scalar->new( \ $scalar );
+               }
+       else {
+               eval q{ open $fh, '<', \\ $scalar; };
+               }
 
        my @lines = <$fh>;
 
@@ -611,13 +701,16 @@ sub _get_cpanpm_last_line
 
 BEGIN {
 my $epic_fail_words = join '|',
-       qw( Error stop(?:ping)? problems force not unsupported fail(?:ed)? );
+       qw( Error stop(?:ping)? problems force not unsupported
+               fail(?:ed)? Cannot\s+install );
 
 sub _cpanpm_output_indicates_failure
        {
        my $last_line = _get_cpanpm_last_line();
 
        my $result = $last_line =~ /\b(?:$epic_fail_words)\b/i;
+       return A_MODULE_FAILED_TO_INSTALL if $last_line =~ /\b(?:Cannot\s+install)\b/i;
+
        $result || ();
        }
 }
@@ -817,7 +910,6 @@ sub _is_pingable_scheme {
 sub _find_good_mirrors {
        require CPAN::Mirrors;
 
-       my $mirrors = CPAN::Mirrors->new;
        my $file = do {
                my $file = 'MIRRORED.BY';
                my $local_path = File::Spec->catfile(
@@ -830,11 +922,10 @@ sub _find_good_mirrors {
                        $local_path;
                        }
                };
-
-       $mirrors->parse_mirrored_by( $file );
+       my $mirrors = CPAN::Mirrors->new( $file );
 
        my @mirrors = $mirrors->best_mirrors(
-               how_many   => 3,
+               how_many   => 5,
                verbose    => 1,
                );
 
@@ -843,6 +934,9 @@ sub _find_good_mirrors {
                _print_ping_report( $mirror->http );
                }
 
+       $CPAN::Config->{urllist} = [
+               map { $_->http } @mirrors
+               ];
        }
 
 sub _print_inc_dir_report
@@ -859,9 +953,10 @@ sub _print_ping_report
        my( $mirror ) = @_;
 
        my $rtt = eval { _get_ping_report( $mirror ) };
+       my $result = $rtt ? sprintf "+ (%4d ms)", $rtt * 1000 : '!';
 
        $logger->info(
-               sprintf "\t%s (%4d ms) %s", $rtt  ? '+' : '!',  $rtt * 1000, $mirror
+               sprintf "\t%s %s", $result, $mirror
                );
        }
 
@@ -908,6 +1003,19 @@ sub _load_local_lib # -I
        return HEY_IT_WORKED;
        }
 
+sub _use_these_mirrors # -M
+       {
+       $logger->debug( "Setting per session mirrors" );
+       unless( $_[0] ) {
+               $logger->die( "The -M switch requires a comma-separated list of mirrors" );
+               }
+
+       $CPAN::Config->{urllist} = [ split /,/, $_[0] ];
+
+       $logger->debug( "Mirrors are @{$CPAN::Config->{urllist}}" );
+
+       }
+
 sub _create_autobundle
        {
        $logger->info(
@@ -1157,9 +1265,9 @@ sub _show_Details
                print "$arg\n", "-" x 73, "\n\t";
                print join "\n\t",
                        $module->description ? $module->description : "(no description)",
-                       $module->cpan_file,
-                       $module->inst_file,
-                       'Installed: ' . $module->inst_version,
+                       $module->cpan_file ? $module->cpan_file : "(no cpanfile)",
+                       $module->inst_file ? $module->inst_file :"(no installation file)" ,
+                       'Installed: ' . ($module->inst_version ? $module->inst_version : "not installed"),
                        'CPAN:      ' . $module->cpan_version . '  ' .
                                ($module->uptodate ? "" : "Not ") . "up to date",
                        $author->fullname . " (" . $module->userid . ")",
@@ -1306,7 +1414,7 @@ sub _eval_version
 sub _path_to_module
        {
        my( $inc, $path ) = @_;
-       return if length $path< length $inc;
+       return if length $path < length $inc;
 
        my $module_path = substr( $path, length $inc );
        $module_path =~ s/\.pm\z//;
@@ -1348,14 +1456,10 @@ correctly if Log4perl is not installed.
 * When I capture CPAN.pm output, I need to check for errors and
 report them to the user.
 
-* Support local::lib
-
 * Warnings switch
 
 * Check then exit
 
-* ping mirrors support
-
 * no test option
 
 =head1 BUGS
@@ -1364,14 +1468,16 @@ report them to the user.
 
 =head1 SEE ALSO
 
-Most behaviour, including environment variables and configuration,
-comes directly from CPAN.pm.
+L<CPAN>, L<App::cpanminus>
 
 =head1 SOURCE AVAILABILITY
 
-This code is in Github:
+This code is in Github in the CPAN.pm repository:
+
+       https://github.com/andk/cpanpm
 
-       git://github.com/briandfoy/cpan_script.git
+The source used to be tracked separately in another GitHub repo,
+but the canonical source is now in the above repo.
 
 =head1 CREDITS
 
@@ -1391,7 +1497,7 @@ brian d foy, C<< <bdfoy@cpan.org> >>
 
 =head1 COPYRIGHT
 
-Copyright (c) 2001-2013, brian d foy, All Rights Reserved.
+Copyright (c) 2001-2014, brian d foy, All Rights Reserved.
 
 You may redistribute this under the same terms as Perl itself.