more consting
[p5sagit/p5-mst-13.2.git] / lib / CPAN.pm
index d7991a3..ca18eff 100644 (file)
@@ -1,8 +1,8 @@
 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
 use strict;
 package CPAN;
-$CPAN::VERSION = '1.88_79';
-$CPAN::VERSION = eval $CPAN::VERSION;
+$CPAN::VERSION = '1.9101';
+$CPAN::VERSION = eval $CPAN::VERSION if $CPAN::VERSION =~ /_/;
 
 use CPAN::HandleConfig;
 use CPAN::Version;
@@ -207,7 +207,7 @@ sub shell {
     $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
     my $rl_avail = $Suppress_readline ? "suppressed" :
        ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
-           "available (try 'install Bundle::CPAN')";
+           "available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
 
     unless ($CPAN::Config->{'inhibit_startup_message'}){
         $CPAN::Frontend->myprint(
@@ -520,6 +520,7 @@ use strict;
                                     recompile
                                     reload
                                     report
+                                    reports
                                     scripts
                                     test
                                     upgrade
@@ -645,7 +646,7 @@ use strict;
 use overload '""' => "as_string";
 
 sub new {
-    my($class,$module,$file,$during,$error) = shift;
+    my($class,$module,$file,$during,$error) = @_;
     bless { module => $module,
             file => $file,
             during => $during,
@@ -654,10 +655,31 @@ sub new {
 
 sub as_string {
     my($self) = shift;
-    "Alert: While trying to $self->{during} YAML file\n".
-        "  $self->{file}\n".
-            "with '$self->{module}' the following error was encountered:\n".
-                "  $self->{error}\n";
+    if ($self->{during}) {
+        if ($self->{file}) {
+            if ($self->{module}) {
+                if ($self->{error}) {
+                    return "Alert: While trying to '$self->{during}' YAML file\n".
+                        " '$self->{file}'\n".
+                            "with '$self->{module}' the following error was encountered:\n".
+                                "  $self->{error}\n";
+                } else {
+                    return "Alert: While trying to '$self->{during}' YAML file\n".
+                        " '$self->{file}'\n".
+                            "with '$self->{module}' some unknown error was encountered\n";
+                }
+            } else {
+                return "Alert: While trying to '$self->{during}' YAML file\n".
+                    " '$self->{file}'\n".
+                        "some unknown error was encountered\n";
+            }
+        } else {
+            return "Alert: While trying to '$self->{during}' some YAML file\n".
+                    "some unknown error was encountered\n";
+        }
+    } else {
+        return "Alert: unknown error encountered\n";
+    }
 }
 
 package CPAN::Prompt; use overload '""' => "as_string";
@@ -1434,17 +1456,16 @@ sub tidyup {
   my($self) = @_;
   return unless $CPAN::META->{LOCK};
   return unless -d $self->{ID};
-  while ($self->{DU} > $self->{'MAX'} ) {
-    my($toremove) = shift @{$self->{FIFO}};
-    unless ($toremove =~ /\.yml$/) {
-        $CPAN::Frontend->myprint(sprintf(
-                                         "DEL(%.1f>%.1fMB): %s \n",
-                                         $self->{DU},
-                                         $self->{MAX},
-                                         $toremove,
-                                        )
-                                );
-    }
+  my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
+  for my $current (0..$#toremove) {
+    my $toremove = $toremove[$current];
+    $CPAN::Frontend->myprint(sprintf(
+                                     "DEL(%d/%d): %s \n",
+                                     $current+1,
+                                     scalar @toremove,
+                                     $toremove,
+                                    )
+                            );
     return if $CPAN::Signal;
     $self->_clean_cache($toremove);
     return if $CPAN::Signal;
@@ -1478,12 +1499,12 @@ sub entries {
        }
     }
     chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
-    sort { -M $b <=> -M $a} @entries;
+    sort { -M $a <=> -M $b} @entries;
 }
 
 #-> sub CPAN::CacheMgr::disk_usage ;
 sub disk_usage {
-    my($self,$dir) = @_;
+    my($self,$dir,$fast) = @_;
     return if exists $self->{SIZE}{$dir};
     return if $CPAN::Signal;
     my($Du) = 0;
@@ -1505,8 +1526,11 @@ sub disk_usage {
         $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
         return;
     }
-    find(
-         sub {
+    if ($fast) {
+        $Du = 0; # placeholder
+    } else {
+        find(
+             sub {
            $File::Find::prune++ if $CPAN::Signal;
            return if -l $_;
            if ($^O eq 'MacOS') {
@@ -1531,10 +1555,11 @@ sub disk_usage {
            }
          },
          $dir
-        );
+            );
+    }
     return if $CPAN::Signal;
     $self->{SIZE}{$dir} = $Du/1024/1024;
-    push @{$self->{FIFO}}, $dir;
+    unshift @{$self->{FIFO}}, $dir;
     $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
     $self->{DU} += $Du/1024/1024;
     $self->{DU};
@@ -1558,9 +1583,18 @@ sub _clean_cache {
     if ($dir !~ /\.yml$/ && -f "$dir.yml") {
         my $yaml_module = CPAN::_yaml_module;
         if ($CPAN::META->has_inst($yaml_module)) {
-            my($peek_yaml) = CPAN->_yaml_loadfile("$dir.yml");
-            if (my $id = $peek_yaml->[0]{distribution}{ID}) {
+            my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
+            if ($@) {
+                $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
+                unlink "$dir.yml" or
+                    $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
+                return;
+            } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
                 $CPAN::META->delete("CPAN::Distribution", $id);
+
+                # XXX we should restore the state NOW, otherise this
+                # distro does not exist until we read an index. BUG ALERT(?)
+
                 # $CPAN::Frontend->mywarn (" +++\n");
                 $id_deleted++;
             }
@@ -1608,15 +1642,20 @@ sub scan_cache {
                             sprintf("Scanning cache %s for sizes\n",
                                     $self->{ID}));
     my $e;
-    my @entries = grep { !/^\.\.?$/ } $self->entries($self->{ID});
+    my @entries = $self->entries($self->{ID});
     my $i = 0;
     my $painted = 0;
     for $e (@entries) {
-       # next if $e eq ".." || $e eq ".";
-       $self->disk_usage($e);
+        my $symbol = ".";
+        if ($self->{DU} > $self->{MAX}) {
+            $symbol = "-";
+            $self->disk_usage($e,1);
+        } else {
+            $self->disk_usage($e);
+        }
         $i++;
         while (($painted/76) < ($i/@entries)) {
-            $CPAN::Frontend->myprint(".");
+            $CPAN::Frontend->myprint($symbol);
             $painted++;
         }
        return if $CPAN::Signal;
@@ -2799,6 +2838,7 @@ sub format_result {
         if ($CPAN::META->has_inst("File::Temp")) {
             $installation_report_fh
                 = File::Temp->new(
+                                  dir      => File::Spec->tmpdir,
                                   template => 'cpan_install_XXXX',
                                   suffix   => '.txt',
                                   unlink   => 0,
@@ -2901,9 +2941,9 @@ sub mywarn {
 #-> sub CPAN::Shell::mydie ;
 sub mydie {
     my($self,$what) = @_;
-    $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
+    $self->mywarn($what);
 
-    # If it is the shell, we want that the following die to be silent,
+    # If it is the shell, we want the following die to be silent,
     # but if it is not the shell, we would need a 'die $what'. We need
     # to take care that only shell commands use mydie. Is this
     # possible?
@@ -2954,8 +2994,11 @@ sub unrecoverable_error {
 #-> sub CPAN::Shell::mysleep ;
 sub mysleep {
     my($self, $sleep) = @_;
-    use Time::HiRes qw(sleep);
-    sleep $sleep;
+    if (CPAN->has_inst("Time::HiRes")) {
+        Time::HiRes::sleep($sleep);
+    } else {
+        sleep($sleep < 1 ? 1 : int($sleep + 0.5));
+    }
 }
 
 #-> sub CPAN::Shell::setup_output ;
@@ -3047,7 +3090,7 @@ sub rematein {
             push @qcopy, $obj;
        } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
            $obj = $CPAN::META->instance('CPAN::Author',uc($s));
-            if ($meth =~ /^(dump|ls)$/) {
+            if ($meth =~ /^(dump|ls|reports)$/) {
                 $obj->$meth();
             } else {
                 $CPAN::Frontend->mywarn(
@@ -3151,11 +3194,13 @@ to find objects with matching identifiers.
                 require overload;
                 $serialized = overload::StrVal($obj);
             }
+            CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
             $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
         } elsif ($obj->$meth()){
             CPAN::Queue->delete($s);
+            CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG;
         } else {
-            CPAN->debug("failed");
+            CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG;
         }
 
         $obj->undelay;
@@ -3199,6 +3244,7 @@ sub recent {
                         notest
                         perldoc
                         readme
+                        reports
                         test
                        )) {
         *$command = sub { shift->rematein($command, @_); };
@@ -3632,20 +3678,6 @@ sub localize {
                     if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
                 $Ua->proxy('http', $var)
                     if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
-
-
-# >>>>> On Wed, 13 Dec 2000 09:21:34 -0500, "Robison, Jonathon (J.M.)" <jrobiso2@visteon.com> said:
-# 
-#  > I note that although CPAN.pm can use proxies, it doesn't seem equipped to
-#  > use ones that require basic autorization.
-#  
-#  > Example of when I use it manually in my own stuff:
-#  
-#  > $ua->proxy(['http','ftp'], http://my.proxy.server:83');
-#  > $req->proxy_authorization_basic("username","password");
-#  > $res = $ua->request($req);
-# 
-
                 $Ua->no_proxy($var)
                     if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
             }
@@ -4575,9 +4607,13 @@ sub reanimate_build_dir {
         sort { $b->[1] <=> $a->[1] }
             map { [ $_, -M File::Spec->catfile($d,$_) ] }
                 grep {/\.yml$/} readdir $dh;
-  DISTRO: for $dirent (@candidates) {
+  DISTRO: for $i (0..$#candidates) {
+        my $dirent = $candidates[$i];
         my $y = eval {CPAN->_yaml_loadfile(File::Spec->catfile($d,$dirent))};
-        die $@ if $@;
+        if ($@) {
+            warn "Error while parsing file '$dirent'; error: '$@'";
+            next DISTRO;
+        }
         my $c = $y->[0];
         if ($c && CPAN->_perl_fingerprint($c->{perl})) {
             my $key = $c->{distribution}{ID};
@@ -4595,11 +4631,16 @@ sub reanimate_build_dir {
             my $do
                 = $CPAN::META->{readwrite}{'CPAN::Distribution'}{$key}
                     = $c->{distribution};
-            delete $do->{badtestcnt};
+            for my $skipper (qw(badtestcnt notest force_update)) {
+                delete $do->{$skipper};
+            }
             # $DB::single = 1;
             if ($do->{make_test}
                 && $do->{build_dir}
-                && !$do->{make_test}->failed
+                && !(UNIVERSAL::can($do->{make_test},"failed") ?
+                     $do->{make_test}->failed :
+                     $do->{make_test} =~ /^YES/
+                    )
                 && (
                     !$do->{install}
                     ||
@@ -4617,8 +4658,9 @@ sub reanimate_build_dir {
         }
     }
     $CPAN::Frontend->myprint(sprintf(
-                                     "DONE\nFound %s old builds, restored the state of %s\n",
+                                     "DONE\nFound %s old build%s, restored the state of %s\n",
                                      @candidates ? sprintf("%d",scalar @candidates) : "no",
+                                     @candidates==1 ? "" : "s",
                                      $restored || "none",
                                     ));
 }
@@ -5428,6 +5470,12 @@ sub dir_listing {
     @result;
 }
 
+#-> sub CPAN::Author::reports
+sub reports {
+    $CPAN::Frontend->mywarn("reports on authors not implemented.
+Please file a bugreport if you need this.\n");
+}
+
 package CPAN::Distribution;
 use strict;
 
@@ -5438,14 +5486,24 @@ sub cpan_comment {
     $ro->{CPAN_COMMENT}
 }
 
-# CPAN::Distribution::undelay
+#-> CPAN::Distribution::undelay
 sub undelay {
     my $self = shift;
     delete $self->{later};
 }
 
+#-> CPAN::Distribution::is_dot_dist
+sub is_dot_dist {
+    my($self) = @_;
+    return (
+            substr($self->id,-1,1) eq "."
+            ||
+            $self->author->id eq "LOCAL"
+           );
+}
+
 # add the A/AN/ stuff
-# CPAN::Distribution::normalize
+#-> CPAN::Distribution::normalize
 sub normalize {
     my($self,$s) = @_;
     $s = $self->id unless defined $s;
@@ -5690,12 +5748,14 @@ sub get {
             # note: not intended to be persistent but at least visible
             # during this session
         } else {
-            if (exists $self->{build_dir} && -d $self->{build_dir}) {
+            if (exists $self->{build_dir} && -d $self->{build_dir}
+                && ($self->{modulebuild}||$self->{writemakefile})
+               ) {
                 # this deserves print, not warn:
                 $CPAN::Frontend->myprint("  Has already been unwrapped into directory ".
                                          "$self->{build_dir}\n"
                                         );
-                return;
+                return 1;
             }
 
             # although we talk about 'force' we shall not test on
@@ -5713,10 +5773,25 @@ sub get {
     }
     my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
 
-    #
-    # Get the file on local disk
-    #
+    $self->get_file_onto_local_disk;
+    return if $CPAN::Signal;
+    $self->check_integrity;
+    return if $CPAN::Signal;
+    my($packagedir,$local_file) = $self->run_preps_on_packagedir;
+    $packagedir ||= $self->{build_dir};
+
+    if ($CPAN::Signal){
+        $self->safe_chdir($sub_wd);
+        return;
+    }
+    return $self->run_MM_or_MB($local_file,$packagedir);
+}
+
+#-> CPAN::Distribution::get_file_onto_local_disk
+sub get_file_onto_local_disk {
+    my($self) = @_;
 
+    return if $self->is_dot_dist;
     my($local_file);
     my($local_wanted) =
         File::Spec->catfile(
@@ -5740,22 +5815,27 @@ sub get {
 
     $self->debug("local_wanted[$local_wanted]local_file[$local_file]") if $CPAN::DEBUG;
     $self->{localfile} = $local_file;
-    return if $CPAN::Signal;
+}
 
-    #
-    # Check integrity
-    #
+
+#-> CPAN::Distribution::check_integrity
+sub check_integrity {
+    my($self) = @_;
+
+    return if $self->is_dot_dist;
     if ($CPAN::META->has_inst("Digest::SHA")) {
        $self->debug("Digest::SHA is installed, verifying");
        $self->verifyCHECKSUM;
     } else {
        $self->debug("Digest::SHA is NOT installed");
     }
-    return if $CPAN::Signal;
+}
+
+#-> CPAN::Distribution::run_preps_on_packagedir
+sub run_preps_on_packagedir {
+    my($self) = @_;
+    return if $self->is_dot_dist;
 
-    #
-    # Create a clean room and go there
-    #
     $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
     my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
     $self->safe_chdir($builddir);
@@ -5773,7 +5853,6 @@ and fix the problem, then retry.
 EOF
     }
     if ($CPAN::Signal){
-        $self->safe_chdir($sub_wd);
         return;
     }
     $self->safe_chdir("tmp-$$");
@@ -5781,6 +5860,7 @@ EOF
     #
     # Unpack the goods
     #
+    my $local_file = $self->{localfile};
     my $ct = eval{CPAN::Tarzip->new($local_file)};
     unless ($ct) {
         $self->{unwrapped} = CPAN::Distrostatus->new("NO");
@@ -5887,11 +5967,6 @@ EOF
             }
         }
     }
-    if ($CPAN::Signal){
-        $self->safe_chdir($sub_wd);
-        return;
-    }
-
     $self->{build_dir} = $packagedir;
     $self->safe_chdir($builddir);
     File::Path::rmtree("tmp-$$");
@@ -5899,9 +5974,13 @@ EOF
     $self->safe_chdir($packagedir);
     $self->_signature_business();
     $self->safe_chdir($builddir);
-    return if $CPAN::Signal;
 
+    return($packagedir,$local_file);
+}
 
+#-> sub CPAN::Distribution::run_MM_or_MB
+sub run_MM_or_MB {
+    my($self,$local_file,$packagedir) = @_;
     my($mpl) = File::Spec->catfile($packagedir,"Makefile.PL");
     my($mpl_exists) = -f $mpl;
     unless ($mpl_exists) {
@@ -5942,7 +6021,6 @@ EOF
        ) {
         $self->store_persistent_state;
     }
-
     return $self;
 }
 
@@ -6130,7 +6208,7 @@ We\'ll try to build it with that Makefile then.
             my $fh = FileHandle->new;
             my $script_file = File::Spec->catfile($packagedir,$local_file);
             $fh->open($script_file)
-                or Carp::croak("Could not open $script_file: $!");
+                or Carp::croak("Could not open script '$script_file': $!");
             local $/ = "\n";
             # name parsen und prereq
             my($state) = "poddir";
@@ -6226,12 +6304,14 @@ sub _signature_business {
                                            );
 
                     my $wrap =
-                        sprintf(qq{I'd recommend removing %s. Its signature
-is invalid. Maybe you have configured your 'urllist' with
-a bad URL. Please check this array with 'o conf urllist', and
-retry. For more information, try opening a subshell with
+                        sprintf(qq{I'd recommend removing %s. Some error occured    }.
+                                qq{while checking its signature, so it could        }.
+                                qq{be invalid. Maybe you have configured            }.
+                                qq{your 'urllist' with a bad URL. Please check this }.
+                                qq{array with 'o conf urllist' and retry. Or        }.
+                                qq{examine the distribution in a subshell. Try
   look %s
-and there run
+and run
   cpansign -v
 },
                                 $self->{localfile},
@@ -6740,7 +6820,7 @@ sub force {
 #-> sub CPAN::Distribution::notest ;
 sub notest {
   my($self, $method) = @_;
-  # warn "XDEBUG: set notest for $self $method";
+  # $CPAN::Frontend->mywarn("XDEBUG: set notest for $self $method");
   $self->{"notest"}++; # name should probably have been force_install
 }
 
@@ -6748,7 +6828,7 @@ sub notest {
 sub unnotest {
   my($self) = @_;
   # warn "XDEBUG: deleting notest";
-  delete $self->{'notest'};
+  delete $self->{notest};
 }
 
 #-> sub CPAN::Distribution::unforce ;
@@ -6889,7 +6969,9 @@ is part of the perl-%s distribution. To install that, you need to run
                     # Trying an already failed 'make' (unless somebody else blocks)
                 } else {
                     # introduced for turning recursion detection into a distrostatus
-                    $CPAN::Frontend->mywarn("Could not make: ".substr($self->{make},3)."\n");
+                    my $error = length $self->{make}>3
+                        ? substr($self->{make},3) : "Unknown error";
+                    $CPAN::Frontend->mywarn("Could not make: $error\n");
                     $self->store_persistent_state;
                     return;
                 }
@@ -6898,17 +6980,9 @@ is part of the perl-%s distribution. To install that, you need to run
             }
         }
 
-        if (exists $self->{later} and length($self->{later})) {
+        if ($self->{later}) { # see also undelay
             if ($self->unsat_prereq) {
                 push @e, $self->{later};
-# RT ticket 18438 raises doubts if the deletion of {later} is valid.
-# YAML-0.53 triggered the later hodge-podge here, but my margin notes
-# are not sufficient to be sure if we really must/may do the delete
-# here. SO I accept the suggested patch for now. If we trigger a bug
-# again, I must go into deep contemplation about the {later} flag.
-
-#            } else {
-#                delete $self->{later};
             }
         }
 
@@ -7648,7 +7722,8 @@ sub unsat_prereq {
             # if we push it again, we have a potential infinite loop
 
             # The following "next" was a very problematic construct.
-            # It helped a lot but broke some day and must be replaced.
+            # It helped a lot but broke some day and had to be
+            # replaced.
 
             # We must be able to deal with modules that come again and
             # again as a prereq and have themselves prereqs and the
@@ -7660,7 +7735,7 @@ sub unsat_prereq {
             # The bug that brought this up is described in Todo under
             # "5.8.9 cannot install Compress::Zlib"
 
-            # next; # this is the next that must go away
+            # next; # this is the next that had to go away
 
             # The following "next NEED" are fine and the error message
             # explains well what is going on. For example when the DBI
@@ -7680,26 +7755,39 @@ sub unsat_prereq {
                                     "install",
                                     "make_clean",
                                    ) {
-                if (
-                    $do->{$nosayer}
-                    &&(UNIVERSAL::can($do->{$nosayer},"failed") ?
-                       $do->{$nosayer}->failed :
-                       $do->{$nosayer} =~ /^NO/)
-                   ) {
-                    if ($nosayer eq "make_test"
-                        &&
-                        $do->{make_test}{COMMANDID} != $CPAN::CurrentCommandId
-                       ) {
-                        next NOSAYER;
+                if ($do->{$nosayer}) {
+                    if (UNIVERSAL::can($do->{$nosayer},"failed") ?
+                        $do->{$nosayer}->failed :
+                        $do->{$nosayer} =~ /^NO/) {
+                        if ($nosayer eq "make_test"
+                            &&
+                            $do->{make_test}{COMMANDID} != $CPAN::CurrentCommandId
+                           ) {
+                            next NOSAYER;
+                        }
+                        $CPAN::Frontend->mywarn("Warning: Prerequisite ".
+                                                "'$need_module => $need_version' ".
+                                                "for '$self->{ID}' failed when ".
+                                                "processing '$do->{ID}' with ".
+                                                "'$nosayer => $do->{$nosayer}'. Continuing, ".
+                                                "but chances to succeed are limited.\n"
+                                               );
+                        next NEED;
+                    } else { # the other guy succeeded
+                        if ($nosayer eq "install") {
+                            # we had this with
+                            # DMAKI/DateTime-Calendar-Chinese-0.05.tar.gz
+                            # 2007-03
+                            $CPAN::Frontend->mywarn("Warning: Prerequisite ".
+                                                    "'$need_module => $need_version' ".
+                                                    "for '$self->{ID}' already installed ".
+                                                    "but installation looks suspicious. ".
+                                                    "Skipping another installation attempt, ".
+                                                    "to prevent looping endlessly.\n"
+                                                   );
+                            next NEED;
+                        }
                     }
-                    $CPAN::Frontend->mywarn("Warning: Prerequisite ".
-                                            "'$need_module => $need_version' ".
-                                            "for '$self->{ID}' failed when ".
-                                            "processing '$do->{ID}' with ".
-                                            "'$nosayer => $do->{$nosayer}'. Continuing, ".
-                                            "but chances to succeed are limited.\n"
-                                           );
-                    next NEED;
                 }
             }
         }
@@ -7906,7 +7994,9 @@ sub test {
 
   EXCUSE: {
        my @e;
-        unless (exists $self->{make} or exists $self->{later}) {
+        if ($self->{make} or $self->{later}) {
+            # go ahead
+        } else {
             push @e,
                 "Make had some problems, won't test";
         }
@@ -7917,7 +8007,6 @@ sub test {
              $self->{make}->failed :
              $self->{make} =~ /^NO/
             ) and push @e, "Can't test without successful make";
-
         $self->{badtestcnt} ||= 0;
         if ($self->{badtestcnt} > 0) {
             require Data::Dumper;
@@ -7925,21 +8014,25 @@ sub test {
             push @e, "Won't repeat unsuccessful test during this command";
         }
 
-        exists $self->{later} and length($self->{later}) and
-            push @e, $self->{later};
+        push @e, $self->{later} if $self->{later};
 
         if (exists $self->{build_dir}) {
-            if ($CPAN::META->{is_tested}{$self->{build_dir}}
-                &&
-                exists $self->{make_test}
-                &&
-                !(
-                  UNIVERSAL::can($self->{make_test},"failed") ?
-                  $self->{make_test}->failed :
-                  $self->{make_test} =~ /^NO/
-                 )
-               ) {
-                push @e, "Has already been tested successfully";
+            if (exists $self->{make_test}) {
+                if (
+                    UNIVERSAL::can($self->{make_test},"failed") ?
+                    $self->{make_test}->failed :
+                    $self->{make_test} =~ /^NO/
+                   ) {
+                    if (
+                        UNIVERSAL::can($self->{make_test},"commandid")
+                        &&
+                        $self->{make_test}->commandid == $CPAN::CurrentCommandId
+                       ) {
+                        push @e, "Has already been tested within this command";
+                    }
+                } else {
+                    push @e, "Has already been tested successfully";
+                }
             }
         } elsif (!@e) {
             push @e, "Has no own directory";
@@ -8019,11 +8112,7 @@ sub test {
     }
     my $ready_to_report = $want_report;
     if ($ready_to_report
-        && (
-            substr($self->id,-1,1) eq "."
-            ||
-            $self->author->id eq "LOCAL"
-           )
+        && $self->is_dot_dist
        ) {
         $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
                                 "for local directories\n");
@@ -8233,7 +8322,7 @@ sub install {
     if (my $goto = $self->prefs->{goto}) {
         return $self->goto($goto);
     }
-    $DB::single=1;
+    # $DB::single=1;
     unless ($self->{badtestcnt}) {
         $self->test;
     }
@@ -8245,7 +8334,9 @@ sub install {
     $CPAN::Frontend->myprint("Running $make install\n");
   EXCUSE: {
        my @e;
-       unless (exists $self->{make} or exists $self->{later}) {
+       if ($self->{make} or $self->{later}) {
+            # go ahead
+        } else {
             push @e,
                 "Make had some problems, won't install";
         }
@@ -8282,15 +8373,16 @@ sub install {
                 $self->{install}->text eq "YES" :
                 $self->{install} =~ /^YES/
                ) {
-                push @e, "Already done";
+                $CPAN::Frontend->myprint("  Already done\n");
+                $CPAN::META->is_installed($self->{build_dir});
+                return 1;
             } else {
                 # comment in Todo on 2006-02-11; maybe retry?
                 push @e, "Already tried without success";
             }
         }
 
-        exists $self->{later} and length($self->{later}) and
-            push @e, $self->{later};
+        push @e, $self->{later} if $self->{later};
 
        $CPAN::Frontend->myprint(join "", map {"  $_\n"} @e) and return if @e;
         unless (chdir $self->{build_dir}) {
@@ -8500,6 +8592,7 @@ Could not fork '$html_converter $saved_file': $!});
             my($fh,$filename);
             if ($CPAN::META->has_inst("File::Temp")) {
                 $fh = File::Temp->new(
+                                      dir      => File::Spec->tmpdir,
                                       template => 'cpan_htmlconvert_XXXX',
                                       suffix => '.txt',
                                       unlink => 0,
@@ -8559,6 +8652,7 @@ sub _getsave_url {
     my($fh,$filename);
     if ($CPAN::META->has_inst("File::Temp")) {
         $fh = File::Temp->new(
+                              dir      => File::Spec->tmpdir,
                               template => "cpan_getsave_url_XXXX",
                               suffix => ".html",
                               unlink => 0,
@@ -8624,6 +8718,91 @@ sub _build_command {
     return "./Build";
 }
 
+#-> sub CPAN::Distribution::reports
+sub reports {
+    my($self) = @_;
+    my $pathname = $self->id;
+    $CPAN::Frontend->myprint("Distribution: $pathname\n");
+
+    unless ($CPAN::META->has_inst("CPAN::DistnameInfo")) {
+        $CPAN::Frontend->mydie("CPAN::DistnameInfo not installed; cannot continue");
+    }
+    unless ($CPAN::META->has_usable("LWP")) {
+        $CPAN::Frontend->mydie("LWP not installed; cannot continue");
+    }
+    unless ($CPAN::META->has_inst("File::Temp")) {
+        $CPAN::Frontend->mydie("File::Temp not installed; cannot continue");
+    }
+
+    my $d = CPAN::DistnameInfo->new($pathname);
+
+    my $dist      = $d->dist;      # "CPAN-DistnameInfo"
+    my $version   = $d->version;   # "0.02"
+    my $maturity  = $d->maturity;  # "released"
+    my $filename  = $d->filename;  # "CPAN-DistnameInfo-0.02.tar.gz"
+    my $cpanid    = $d->cpanid;    # "GBARR"
+    my $distvname = $d->distvname; # "CPAN-DistnameInfo-0.02"
+
+    my $url = sprintf "http://cpantesters.perl.org/show/%s.yaml", $dist;
+
+    CPAN::LWP::UserAgent->config;
+    my $Ua;
+    eval { $Ua = CPAN::LWP::UserAgent->new; };
+    if ($@) {
+        $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
+    }
+    $CPAN::Frontend->myprint("Fetching '$url'...");
+    my $resp = $Ua->get($url);
+    unless ($resp->is_success) {
+        $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
+    }
+    $CPAN::Frontend->myprint("DONE\n\n");
+    my $yaml = $resp->content;
+    # was fuer ein Umweg!
+    my $fh = File::Temp->new(
+                             dir      => File::Spec->tmpdir,
+                             template => 'cpan_reports_XXXX',
+                             suffix => '.yaml',
+                             unlink => 0,
+                            );
+    my $tfilename = $fh->filename;
+    print $fh $yaml;
+    close $fh or $CPAN::Frontend->mydie("Could not close '$tfilename': $!");
+    my $unserialized = CPAN->_yaml_loadfile($tfilename)->[0];
+    unlink $tfilename or $CPAN::Frontend->mydie("Could not unlink '$tfilename': $!");
+    my %other_versions;
+    my $this_version_seen;
+    for my $rep (@$unserialized) {
+        my $rversion = $rep->{version};
+        if ($rversion eq $version){
+            unless ($this_version_seen++) {
+                $CPAN::Frontend->myprint ("$rep->{version}:\n");
+            }
+            $CPAN::Frontend->myprint
+                (sprintf("%1s%1s%-4s %s on %s %s (%s)\n",
+                         $rep->{archname} eq $Config::Config{archname}?"*":"",
+                         $rep->{action}eq"PASS"?"+":$rep->{action}eq"FAIL"?"-":"",
+                         $rep->{action},
+                         $rep->{perl},
+                         ucfirst $rep->{osname},
+                         $rep->{osvers},
+                         $rep->{archname},
+                        ));
+        } else {
+            $other_versions{$rep->{version}}++;
+        }
+    }
+    unless ($this_version_seen) {
+        $CPAN::Frontend->myprint("No reports found for version '$version'
+Reports for other versions:\n");
+        for my $v (sort keys %other_versions) {
+            $CPAN::Frontend->myprint(" $v\: $other_versions{$v}\n");
+        }
+    }
+    $url =~ s/\.yaml/.html/;
+    $CPAN::Frontend->myprint("See $url for details\n");
+}
+
 package CPAN::Bundle;
 use strict;
 
@@ -8632,6 +8811,7 @@ sub look {
     $CPAN::Frontend->myprint($self->as_string);
 }
 
+#-> CPAN::Bundle::undelay
 sub undelay {
     my $self = shift;
     delete $self->{later};
@@ -8901,26 +9081,27 @@ package CPAN::Module;
 use strict;
 
 # Accessors
-# sub CPAN::Module::userid
+#-> sub CPAN::Module::userid
 sub userid {
     my $self = shift;
     my $ro = $self->ro;
     return unless $ro;
     return $ro->{userid} || $ro->{CPAN_USERID};
 }
-# sub CPAN::Module::description
+#-> sub CPAN::Module::description
 sub description {
     my $self = shift;
     my $ro = $self->ro or return "";
     $ro->{description}
 }
 
+#-> sub CPAN::Module::distribution
 sub distribution {
     my($self) = @_;
     CPAN::Shell->expand("Distribution",$self->cpan_file);
 }
 
-# sub CPAN::Module::undelay
+#-> sub CPAN::Module::undelay
 sub undelay {
     my $self = shift;
     delete $self->{later};
@@ -9185,6 +9366,7 @@ sub as_string {
     join "", @m, "\n";
 }
 
+#-> sub CPAN::Module::manpage_headline
 sub manpage_headline {
   my($self,$local_file) = @_;
   my(@local_file) = $local_file;
@@ -9276,10 +9458,11 @@ sub fforce {
     $self->{force_update} = 2;
 }
 
+#-> sub CPAN::Module::notest ;
 sub notest {
     my($self) = @_;
-    # warn "XDEBUG: set notest for Module";
-    $self->{'notest'}++;
+    # $CPAN::Frontend->mywarn("XDEBUG: set notest for Module");
+    $self->{notest}++;
 }
 
 #-> sub CPAN::Module::rematein ;
@@ -9311,7 +9494,7 @@ sub rematein {
             $pack->force($meth);
         }
     }
-    $pack->notest($meth) if exists $self->{'notest'};
+    $pack->notest($meth) if exists $self->{notest} && $self->{notest};
 
     $pack->{reqtype} ||= "";
     CPAN->debug("dist-reqtype[$pack->{reqtype}]".
@@ -9337,17 +9520,18 @@ sub rematein {
             $pack->{reqtype} = $self->{reqtype};
         }
 
-    eval {
+    my $success = eval {
        $pack->$meth();
     };
     my $err = $@;
     $pack->unforce if $pack->can("unforce") && exists $self->{force_update};
-    $pack->unnotest if $pack->can("unnotest") && exists $self->{'notest'};
+    $pack->unnotest if $pack->can("unnotest") && exists $self->{notest};
     delete $self->{force_update};
-    delete $self->{'notest'};
+    delete $self->{notest};
     if ($err) {
        die $err;
     }
+    return $success;
 }
 
 #-> sub CPAN::Module::perldoc ;
@@ -9498,6 +9682,12 @@ sub parse_version {
     $have; # no stringify needed, \s* above matches always
 }
 
+#-> sub CPAN::Module::reports
+sub reports {
+    my($self) = @_;
+    $self->distribution->reports;
+}
+
 package CPAN;
 use strict;
 
@@ -10846,6 +11036,11 @@ undef otherwise.
 Downloads the README file associated with a distribution and runs it
 through the pager specified in C<$CPAN::Config->{pager}>.
 
+=item CPAN::Distribution::reports()
+
+Downloads report data for this distribution from cpantesters.perl.org
+and displays a subset of them.
+
 =item CPAN::Distribution::read_yaml()
 
 Returns the content of the META.yml of this distro as a hashref. Note:
@@ -11038,6 +11233,10 @@ Runs a C<perldoc> on this module.
 
 Runs a C<readme> on the distribution associated with this module.
 
+=item CPAN::Module::reports()
+
+Calls the reports() method on the associated distribution object.
+
 =item CPAN::Module::test()
 
 Runs a C<test> on the distribution associated with this module.