Silence warnings in Pod::Man
[p5sagit/p5-mst-13.2.git] / lib / CPAN.pm
index eeb6dbb..25b6e73 100644 (file)
@@ -1,7 +1,7 @@
 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
 use strict;
 package CPAN;
-$CPAN::VERSION = '1.88_54';
+$CPAN::VERSION = '1.88_57';
 $CPAN::VERSION = eval $CPAN::VERSION;
 
 use CPAN::HandleConfig;
@@ -58,13 +58,25 @@ $CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
 $CPAN::Defaultrecent ||= "http://search.cpan.org/recent";
 
 
-use vars qw($VERSION @EXPORT $AUTOLOAD
-            $DEBUG $META $HAS_USABLE $term
-            $GOTOSHELL
-            $Signal $Suppress_readline $Frontend
-            @Defaultsites $Have_warned $Defaultdocs $Defaultrecent
+use vars qw(
+            $AUTOLOAD
             $Be_Silent
+            $CONFIG_DIRTY
+            $DEBUG
+            $Defaultdocs
+            $Defaultrecent
+            $Frontend
+            $GOTOSHELL
+            $HAS_USABLE
+            $Have_warned
+            $META
+            $Signal
+            $Suppress_readline
+            $VERSION
             $autoload_recursion
+            $term
+            @Defaultsites
+            @EXPORT
            );
 
 @CPAN::ISA = qw(CPAN::Debug Exporter);
@@ -87,6 +99,7 @@ use vars qw($VERSION @EXPORT $AUTOLOAD
              readme
              recent
              recompile
+             report
              shell
              test
              upgrade
@@ -246,8 +259,11 @@ ReadLine support %s
            $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
            my $command = shift @line;
            eval { CPAN::Shell->$command(@line) };
-           warn $@ if $@;
-            if ($command =~ /^(make|test|install|force|notest|clean|upgrade)$/) {
+           if ($@){
+                require Carp;
+                Carp::cluck($@);
+            }
+            if ($command =~ /^(make|test|install|force|notest|clean|report|upgrade)$/) {
                 CPAN::Shell->failed($CPAN::CurrentCommandId,1);
             }
             soft_chdir_with_alternatives(\@cwd);
@@ -291,15 +307,12 @@ ReadLine support %s
               }
           }
       }
-      if ($CPAN::DEBUG && $CPAN::DEBUG & $CPAN::DEBUG{CPAN}) {
-          # debugging 'incommandcolor': should always be off at the end of a command
-          # (incommandcolor is used to detect recursive dependencies)
-          for my $class (qw(Module Distribution)) {
-              for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
-                  next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
-                  CPAN->debug("BUG: $class '$dm' was in command state, resetting");
-                  delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
-              }
+      for my $class (qw(Module Distribution)) {
+          # again unsafe meta access?
+          for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
+              next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
+              CPAN->debug("BUG: $class '$dm' was in command state, resetting");
+              delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
           }
       }
       if ($GOTOSHELL) {
@@ -343,8 +356,8 @@ sub _yaml_loadfile {
     my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
     if ($CPAN::META->has_inst($yaml_module)) {
         my $code = UNIVERSAL::can($yaml_module, "LoadFile");
-        my $yaml;
-        eval { $yaml = $code->($local_file); };
+        my @yaml;
+        eval { @yaml = $code->($local_file); };
         if ($@) {
             $CPAN::Frontend->mydie("Alert: While trying to parse YAML file\n".
                                    "  $local_file\n".
@@ -352,11 +365,11 @@ sub _yaml_loadfile {
                                    "  $@\n"
                                   );
         }
-        return $yaml;
+        return \@yaml;
     } else {
         $CPAN::Frontend->mywarn("'$yaml_module' not installed, cannot parse '$local_file'\n");
     }
-    return +{};
+    return +[];
 }
 
 package CPAN::CacheMgr;
@@ -395,6 +408,7 @@ use strict;
                                     recent
                                     recompile
                                     reload
+                                    report
                                     scripts
                                     test
                                     upgrade
@@ -859,7 +873,7 @@ sub has_usable {
                            ],
                'File::HomeDir' => [
                                    sub {require File::HomeDir;
-                                        unless (File::HomeDir->VERSION >= 0.52){
+                                        unless (File::HomeDir::->VERSION >= 0.52){
                                             for ("Will not use File::HomeDir, need 0.52\n") {
                                                 $CPAN::Frontend->mywarn($_);
                                                 die $_;
@@ -1004,6 +1018,9 @@ sub cleanup {
   unlink $META->{LOCK};
   # require Carp;
   # Carp::cluck("DEBUGGING");
+  if ( $CPAN::CONFIG_DIRTY ) {
+      $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
+  }
   $CPAN::Frontend->myprint("Lockfile removed.\n");
 }
 
@@ -1033,11 +1050,13 @@ sub savehist {
     close $fh;
 }
 
+#-> sub CPAN::is_tested
 sub is_tested {
     my($self,$what) = @_;
     $self->{is_tested}{$what} = 1;
 }
 
+#-> sub CPAN::is_installed
 # unsets the is_tested flag: as soon as the thing is installed, it is
 # not needed in set_perl5lib anymore
 sub is_installed {
@@ -1045,16 +1064,34 @@ sub is_installed {
     delete $self->{is_tested}{$what};
 }
 
+#-> sub CPAN::set_perl5lib
 sub set_perl5lib {
-    my($self) = @_;
+    my($self,$for) = @_;
+    unless ($for) {
+        (undef,undef,undef,$for) = caller(1);
+        $for =~ s/.*://;
+    }
     $self->{is_tested} ||= {};
     return unless %{$self->{is_tested}};
     my $env = $ENV{PERL5LIB};
     $env = $ENV{PERLLIB} unless defined $env;
     my @env;
     push @env, $env if defined $env and length $env;
-    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
-    $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+    #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
+    #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} sort keys %{$self->{is_tested}};
+    if (@dirs < 15) {
+        $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB for $for\n");
+    } else {
+        my @d = map {s/^\Q$CPAN::Config->{'build_dir'}/%BUILDDIR%/; $_ }
+            sort keys %{$self->{is_tested}};
+        $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib subdirs of ".
+                                 "@d to PERL5LIB; ".
+                                 "%BUILDDIR%=$CPAN::Config->{'build_dir'} ".
+                                 "for $for\n"
+                                );
+    }
+
     $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
 }
 
@@ -1437,7 +1474,6 @@ sub i {
 # 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
 sub o {
     my($self,$o_type,@o_what) = @_;
-    $DB::single = 1;
     $o_type ||= "";
     CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
     if ($o_type eq 'conf') {
@@ -1615,7 +1651,12 @@ sub reload_this {
     unless ($file && -f $file) {
         # this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
         $file = $INC{$f};
-        @inc = substr($file,0,-length($f)); # bring in back to me!
+        unless (CPAN->has_inst("File::Basename")) {
+            @inc = File::Basename::dirname($file);
+        } else {
+            # do we ever need this?
+            @inc = substr($file,0,-length($f)-1); # bring in back to me!
+        }
     }
     CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
     unless (-f $file) {
@@ -1774,6 +1815,17 @@ sub scripts {
     }
 }
 
+#-> sub CPAN::Shell::report ;
+sub report {
+    my($self,@args) = @_;
+    unless ($CPAN::META->has_inst("CPAN::Reporter")) {
+        $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
+    }
+    local $CPAN::Config->{test_report} = 1;
+    $self->force("test",@args); # force is there so that the test be
+                                # re-run (as documented)
+}
+
 #-> sub CPAN::Shell::upgrade ;
 sub upgrade {
     my($self,@args) = @_;
@@ -1860,7 +1912,6 @@ sub _u_r_common {
        }
         my $color_on = "";
         my $color_off = "";
-        # $GLOBAL_AUTOLOAD_RECURSION = 12;
         if (
             $COLOR_REGISTERED
             &&
@@ -1919,6 +1970,7 @@ sub failed {
   DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
         my $failed = "";
       NAY: for my $nosayer (
+                            "unwrapped",
                             "writemakefile",
                             "signature_verify",
                             "make",
@@ -2060,7 +2112,7 @@ sub autobundle {
 sub expandany {
     my($self,$s) = @_;
     CPAN->debug("s[$s]") if $CPAN::DEBUG;
-    if ($s =~ m|/|) { # looks like a file
+    if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
         $s = CPAN::Distribution->normalize($s);
         return $CPAN::META->instance('CPAN::Distribution',$s);
         # Distributions spring into existence, not expand
@@ -2408,10 +2460,14 @@ sub rematein {
            $obj = $s;
        } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
        } elsif ($s =~ m|^/|) { # looks like a regexp
-            $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
-                                    "not supported.\nRejecting argument '$s'\n");
-            $CPAN::Frontend->mysleep(2);
-            next;
+            if (substr($s,-1,1) eq ".") {
+                $obj = CPAN::Shell->expandany($s);
+            } else {
+                $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
+                                        "not supported.\nRejecting argument '$s'\n");
+                $CPAN::Frontend->mysleep(2);
+                next;
+            }
        } elsif ($meth eq "ls") {
             $self->globls($s,\@pragma);
             next STHING;
@@ -3224,7 +3280,7 @@ sub hosthardest {
     my($aslocal_dir) = File::Basename::dirname($aslocal);
     File::Path::mkpath($aslocal_dir);
     my $ftpbin = $CPAN::Config->{ftp};
-    unless (length $ftpbin && MM->maybe_command($ftpbin)) {
+    unless ($ftpbin && length $ftpbin && MM->maybe_command($ftpbin)) {
         $CPAN::Frontend->myprint("No external ftp command available\n\n");
         return;
     }
@@ -3736,12 +3792,14 @@ sub rd_authindex {
     CPAN->debug(sprintf "modulus[%d]lines[%s]", $modulus, scalar @lines) if $CPAN::DEBUG;
     foreach (@lines) {
        my($userid,$fullname,$email) =
-           m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
-       next unless $userid && $fullname && $email;
-
-       # instantiate an author object
-       my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
-       $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
+           m/alias\s+(\S+)\s+\"([^\"\<]*)\s+\<(.*)\>\"/;
+        $fullname ||= $email;
+       if ($userid && $fullname && $email){
+            my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
+            $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
+        } else {
+            CPAN->debug(sprintf "line[%s]", $_) if $CPAN::DEBUG;
+        }
         $CPAN::Frontend->myprint(".") unless $i++ % $modulus;
        return if $CPAN::Signal;
     }
@@ -4097,10 +4155,17 @@ sub ro {
     exists $self->{RO} and return $self->{RO};
 }
 
+#-> sub CPAN::InfoObj::cpan_userid
 sub cpan_userid {
     my $self = shift;
-    my $ro = $self->ro or return "N/A"; # N/A for bundles found locally
-    return $ro->{CPAN_USERID} || "N/A";
+    my $ro = $self->ro;
+    if ($ro) {
+        return $ro->{CPAN_USERID} || "N/A";
+    } else {
+        $self->debug("ID[$self->{ID}]");
+        # N/A for bundles found locally
+        return "N/A";
+    }
 }
 
 sub id { shift->{ID}; }
@@ -4197,7 +4262,11 @@ sub as_string {
     push @m, $class, " id = $self->{ID}\n";
     my $ro;
     unless ($ro = $self->ro) {
-        $CPAN::Frontend->mydie("Unknown object $self->{ID}");
+        if (substr($self->{ID},-1,1) eq ".") { # directory
+            $ro = +{};
+        } else {
+            $CPAN::Frontend->mydie("Unknown object $self->{ID}");
+        }
     }
     for (sort keys %$ro) {
        # next if m/^(ID|RO)$/;
@@ -4221,15 +4290,36 @@ sub as_string {
         next unless defined $ro->{$_};
         push @m, sprintf "    %-12s %s%s\n", $_, $ro->{$_}, $extra;
     }
-    for (sort keys %$self) {
+  KEY: for (sort keys %$self) {
        next if m/^(ID|RO)$/;
+        unless (defined $self->{$_}) {
+            delete $self->{$_};
+            next KEY;
+        }
        if (ref($self->{$_}) eq "ARRAY") {
          push @m, sprintf "    %-12s %s\n", $_, "@{$self->{$_}}";
        } elsif (ref($self->{$_}) eq "HASH") {
+            my $value;
+            if (/^CONTAINSMODS$/) {
+                $value = join(" ",sort keys %{$self->{$_}});
+            } elsif (/^prereq_pm$/) {
+                my @value;
+                my $v = $self->{$_};
+                for my $x (sort keys %$v) {
+                    my @svalue;
+                    for my $y (sort keys %{$v->{$x}}) {
+                        push @svalue, "$y=>$v->{$x}{$y}";
+                    }
+                    push @value, "$x\:" . join ",", @svalue;
+                }
+                $value = join ";", @value;
+            } else {
+                $value = $self->{$_};
+            }
          push @m, sprintf(
                           "    %-12s %s\n",
                           $_,
-                          join(" ",sort keys %{$self->{$_}}),
+                          $value,
                           );
        } else {
          push @m, sprintf "    %-12s %s\n", $_, $self->{$_};
@@ -4471,7 +4561,24 @@ sub undelay {
 sub normalize {
     my($self,$s) = @_;
     $s = $self->id unless defined $s;
-    if (
+    if (substr($s,-1,1) eq ".") {
+        if ($s eq ".") {
+            $s = "$CPAN::iCwd/.";
+        } elsif (File::Spec->file_name_is_absolute($s)) {
+        } elsif (File::Spec->can("rel2abs")) {
+            $s = File::Spec->rel2abs($s);
+        } else {
+            $CPAN::Frontend->mydie("Your File::Spec is too old, please upgrade File::Spec");
+        }
+        CPAN->debug("s[$s]") if $CPAN::DEBUG;
+        unless ($CPAN::META->exists("CPAN::Distribution", $s)) {
+            for ($CPAN::META->instance("CPAN::Distribution", $s)) {
+                $_->{build_dir} = $s;
+                $_->{archived} = "local_directory";
+                $_->{unwrapped} = CPAN::Distrostatus->new("YES -- local_directory");
+            }
+        }
+    } elsif (
         $s =~ tr|/|| == 1
         or
         $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
@@ -4487,7 +4594,12 @@ sub normalize {
 #-> sub CPAN::Distribution::author ;
 sub author {
     my($self) = @_;
-    my($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
+    my($authorid);
+    if (substr($self->id,-1,1) eq ".") {
+        $authorid = "LOCAL";
+    } else {
+        ($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
+    }
     CPAN::Shell->expand("Author",$authorid);
 }
 
@@ -4514,7 +4626,16 @@ sub fast_yaml {
                                 $local_wanted)) {
         $CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n");
     }
-    my $yaml = CPAN->_yaml_loadfile($local_file);
+    my $yaml = CPAN->_yaml_loadfile($local_file)->[0];
+}
+
+#-> sub CPAN::Distribution::cpan_userid
+sub cpan_userid {
+    my $self = shift;
+    if ($self->{ID} =~ m{[A-Z]/[A-Z\-]{2}/([A-Z\-]+)/}) {
+        return $1;
+    }
+    return $self->SUPER::cpan_userid;
 }
 
 #-> sub CPAN::Distribution::pretty_id
@@ -4626,11 +4747,26 @@ sub called_for {
 #-> sub CPAN::Distribution::get ;
 sub get {
     my($self) = @_;
+    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+                           ? $ENV{PERL5LIB}
+                           : ($ENV{PERLLIB} || "");
+
+    $CPAN::META->set_perl5lib;
+    local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
   EXCUSE: {
        my @e;
-       exists $self->{'build_dir'} and push @e,
-           "Is already unwrapped into directory $self->{'build_dir'}";
-       $CPAN::Frontend->myprint(join "", map {"  $_\n"} @e) and return if @e;
+       exists $self->{build_dir} and push @e,
+           "Is already unwrapped into directory $self->{build_dir}";
+
+        exists $self->{unwrapped} and (
+                                       $self->{unwrapped}->can("failed") ?
+                                       $self->{unwrapped}->failed :
+                                       $self->{unwrapped} =~ /^NO/
+                                      )
+            and push @e, "Unwrapping had some problem, won't try again without force";
+
+       $CPAN::Frontend->mywarn(join "", map {"  $_\n"} @e) and return if @e;
     }
     my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
 
@@ -4658,7 +4794,8 @@ sub get {
         }
         $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
     }
-    $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
+
+    $self->debug("local_wanted[$local_wanted]local_file[$local_file]") if $CPAN::DEBUG;
     $self->{localfile} = $local_file;
     return if $CPAN::Signal;
 
@@ -4701,7 +4838,6 @@ EOF
     #
     # Unpack the goods
     #
-    $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
     my $ct = CPAN::Tarzip->new($local_file);
     if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i){
         $self->{was_uncompressed}++ unless $ct->gtest();
@@ -4710,8 +4846,6 @@ EOF
        $self->unzip_me($ct);
     } else {
         $self->{was_uncompressed}++ unless $ct->gtest();
-        $self->debug("calling pm2dir for local_file[$local_file]")
-         if $CPAN::DEBUG;
        $local_file = $self->handle_singlefile($local_file);
 #    } else {
 #      $self->{archived} = "NO";
@@ -4754,8 +4888,8 @@ EOF
                             )) if $CPAN::DEBUG;
     } else {
         my $userid = $self->cpan_userid;
-        unless ($userid) {
-            CPAN->debug("no userid? self[$self]");
+        CPAN->debug("userid[$userid]");
+        if (!$userid or $userid eq "N/A") {
             $userid = "anon";
         }
         my $pragmatic_dir = $userid . '000';
@@ -4780,50 +4914,7 @@ EOF
     File::Path::rmtree("tmp");
 
     $self->safe_chdir($packagedir);
-    if ($CPAN::Config->{check_sigs}) {
-        if ($CPAN::META->has_inst("Module::Signature")) {
-            if (-f "SIGNATURE") {
-                $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
-                my $rv = Module::Signature::verify();
-                if ($rv != Module::Signature::SIGNATURE_OK() and
-                    $rv != Module::Signature::SIGNATURE_MISSING()) {
-                    $CPAN::Frontend->myprint(
-                                             qq{\nSignature invalid for }.
-                                             qq{distribution file. }.
-                                             qq{Please investigate.\n\n}.
-                                             $self->as_string,
-                                             $CPAN::META->instance(
-                                                                   'CPAN::Author',
-                                                                   $self->cpan_userid,
-                                                                  )->as_string
-                                            );
-
-                    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
-  look %s
-and there run
-  cpansign -v
-},
-                                $self->{localfile},
-                                $self->pretty_id,
-                               );
-                    $self->{signature_verify} = CPAN::Distrostatus->new("NO");
-                    $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap));
-                    $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep");
-                } else {
-                    $self->{signature_verify} = CPAN::Distrostatus->new("YES");
-                    $self->debug("Module::Signature has verified") if $CPAN::DEBUG;
-                }
-            } else {
-                $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n});
-            }
-        } else {
-            $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
-        }
-    }
+    $self->_signature_business();
     $self->safe_chdir($builddir);
     return if $CPAN::Signal;
 
@@ -4843,116 +4934,201 @@ and there run
     my $prefer_installer = "eumm"; # eumm|mb
     if (-f File::Spec->catfile($packagedir,"Build.PL")) {
         if ($mpl_exists) { # they *can* choose
-            if ($CPAN::META->has_inst("Module::Build")) {
-                $prefer_installer = $CPAN::Config->{prefer_installer};
-            }
+            $prefer_installer = CPAN::HandleConfig->prefs_lookup($self,
+                                                                 q{prefer_installer});
         } else {
             $prefer_installer = "mb";
         }
     }
+    return unless $self->patch;
     if (lc($prefer_installer) eq "mb") {
         $self->{modulebuild} = 1;
     } elsif (! $mpl_exists) {
-        $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
-                             $mpl,
-                             CPAN::anycwd(),
-                            )) if $CPAN::DEBUG;
-        my($configure) = File::Spec->catfile($packagedir,"Configure");
-        if (-f $configure) {
-            # do we have anything to do?
-            $self->{'configure'} = $configure;
-        } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
-            $CPAN::Frontend->mywarn(qq{
+        $self->_edge_cases($mpl,$packagedir,$local_file);
+    }
+
+    return $self;
+}
+
+#-> CPAN::Distribution::patch
+sub try_download {
+    my($self,$patch) = @_;
+    my $norm = $self->normalize($patch);
+    my($local_wanted) =
+        File::Spec->catfile(
+                            $CPAN::Config->{keep_source_where},
+                            "authors",
+                            "id",
+                            split(/\//,$norm),
+                           );
+    $self->debug("Doing localize") if $CPAN::DEBUG;
+    return CPAN::FTP->localize("authors/id/$norm",
+                               $local_wanted);
+}
+
+#-> CPAN::Distribution::patch
+sub patch {
+    my($self) = @_;
+    if (my $patches = $self->prefs->{patches}) {
+        return unless @$patches;
+        $self->safe_chdir($self->{build_dir});
+        CPAN->debug("patches[$patches]");
+        my $patchbin = $CPAN::Config->{patch};
+        unless ($patchbin && length $patchbin) {
+            $CPAN::Frontend->mydie("No external patch command configured\n\n".
+                                   "Please run 'o conf init /patch/'\n\n");
+        }
+        unless (MM->maybe_command($patchbin)) {
+            $CPAN::Frontend->mydie("No external patch command available\n\n".
+                                   "Please run 'o conf init /patch/'\n\n");
+        }
+        $patchbin = CPAN::HandleConfig->safe_quote($patchbin);
+        my $args = "-b -g0 -p1 -N --fuzz=3";
+        my $countedpatches = @$patches == 1 ? "1 patch" : (scalar @$patches . " patches");
+        $CPAN::Frontend->myprint("Going to apply $countedpatches:\n");
+        for my $patch (@$patches) {
+            unless (-f $patch) {
+                if (my $trydl = $self->try_download($patch)) {
+                    $patch = $trydl;
+                } else {
+                    my $fail = "Could not find patch '$patch'";
+                    $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+                    $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+                    delete $self->{build_dir};
+                    return;
+                }
+            }
+            $CPAN::Frontend->myprint("  $patch\n");
+            my $readfh = CPAN::Tarzip->TIEHANDLE($patch);
+            my $writefh = FileHandle->new;
+            unless (open $writefh, "|$patchbin $args") {
+                my $fail = "Could not fork '$patchbin $args'";
+                $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+                $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+                delete $self->{build_dir};
+                return;
+            }
+            while (my $x = $readfh->READLINE) {
+                print $writefh $x;
+            }
+            unless (close $writefh) {
+                my $fail = "Could not apply patch '$patch'";
+                $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+                $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+                delete $self->{build_dir};
+                return;
+            }
+        }
+        $self->{patched}++;
+    }
+    return 1;
+}
+
+#-> sub CPAN::Distribution::_edge_cases
+# with "configure" or "Makefile" or single file scripts
+sub _edge_cases {
+    my($self,$mpl,$packagedir,$local_file) = @_;
+    $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
+                         $mpl,
+                         CPAN::anycwd(),
+                        )) if $CPAN::DEBUG;
+    my($configure) = File::Spec->catfile($packagedir,"Configure");
+    if (-f $configure) {
+        # do we have anything to do?
+        $self->{configure} = $configure;
+    } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
+        $CPAN::Frontend->mywarn(qq{
 Package comes with a Makefile and without a Makefile.PL.
 We\'ll try to build it with that Makefile then.
 });
-            $self->{writemakefile} = CPAN::Distrostatus->new("YES");
-            $CPAN::Frontend->mysleep(2);
-        } else {
-            my $cf = $self->called_for || "unknown";
-            if ($cf =~ m|/|) {
-                $cf =~ s|.*/||;
-                $cf =~ s|\W.*||;
-            }
-            $cf =~ s|[/\\:]||g; # risk of filesystem damage
-            $cf = "unknown" unless length($cf);
-            $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL.
+        $self->{writemakefile} = CPAN::Distrostatus->new("YES");
+        $CPAN::Frontend->mysleep(2);
+    } else {
+        my $cf = $self->called_for || "unknown";
+        if ($cf =~ m|/|) {
+            $cf =~ s|.*/||;
+            $cf =~ s|\W.*||;
+        }
+        $cf =~ s|[/\\:]||g;     # risk of filesystem damage
+        $cf = "unknown" unless length($cf);
+        $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL.
   (The test -f "$mpl" returned false.)
   Writing one on our own (setting NAME to $cf)\a\n});
-            $self->{had_no_makefile_pl}++;
-            $CPAN::Frontend->mysleep(3);
-
-            # Writing our own Makefile.PL
-
-           my $script = "";
-           if ($self->{archived} eq "maybe_pl"){
-               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: $!");
-               local $/ = "\n";
-               # name parsen und prereq
-               my($state) = "poddir";
-               my($name, $prereq) = ("", "");
-               while (<$fh>){
-                   if ($state eq "poddir" && /^=head\d\s+(\S+)/) {
-                       if ($1 eq 'NAME') {
-                           $state = "name";
-                       } elsif ($1 eq 'PREREQUISITES') {
-                           $state = "prereq";
-                       }
-                   } elsif ($state =~ m{^(name|prereq)$}) {
-                       if (/^=/) {
-                           $state = "poddir";
-                       } elsif (/^\s*$/) {
-                           # nop
-                       } elsif ($state eq "name") {
-                           if ($name eq "") {
-                               ($name) = /^(\S+)/;
-                               $state = "poddir";
-                           }
-                       } elsif ($state eq "prereq") {
-                           $prereq .= $_;
-                       }
-                   } elsif (/^=cut\b/) {
-                       last;
-                   }
-               }
-               $fh->close;
+        $self->{had_no_makefile_pl}++;
+        $CPAN::Frontend->mysleep(3);
 
-                for ($name) {
-                   s{.*<}{}; # strip X<...>
-                   s{>.*}{};
-                }
-               chomp $prereq;
-                $prereq = join " ", split /\s+/, $prereq;
-               my($PREREQ_PM) = join("\n", map {
-                   s{.*<}{}; # strip X<...>
-                   s{>.*}{};
-                    if (/[\s\'\"]/) { # prose?
-                    } else {
-                        s/[^\w:]$//; # period?
-                        " "x28 . "'$_' => 0,";
+        # Writing our own Makefile.PL
+
+        my $script = "";
+        if ($self->{archived} eq "maybe_pl") {
+            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: $!");
+            local $/ = "\n";
+            # name parsen und prereq
+            my($state) = "poddir";
+            my($name, $prereq) = ("", "");
+            while (<$fh>) {
+                if ($state eq "poddir" && /^=head\d\s+(\S+)/) {
+                    if ($1 eq 'NAME') {
+                        $state = "name";
+                    } elsif ($1 eq 'PREREQUISITES') {
+                        $state = "prereq";
+                    }
+                } elsif ($state =~ m{^(name|prereq)$}) {
+                    if (/^=/) {
+                        $state = "poddir";
+                    } elsif (/^\s*$/) {
+                        # nop
+                    } elsif ($state eq "name") {
+                        if ($name eq "") {
+                            ($name) = /^(\S+)/;
+                            $state = "poddir";
+                        }
+                    } elsif ($state eq "prereq") {
+                        $prereq .= $_;
                     }
-               } split /\s*,\s*/, $prereq);
+                } elsif (/^=cut\b/) {
+                    last;
+                }
+            }
+            $fh->close;
 
-               $script = "
+            for ($name) {
+                s{.*<}{};       # strip X<...>
+                s{>.*}{};
+            }
+            chomp $prereq;
+            $prereq = join " ", split /\s+/, $prereq;
+            my($PREREQ_PM) = join("\n", map {
+                s{.*<}{};       # strip X<...>
+                s{>.*}{};
+                if (/[\s\'\"]/) { # prose?
+                } else {
+                    s/[^\w:]$//; # period?
+                    " "x28 . "'$_' => 0,";
+                }
+            } split /\s*,\s*/, $prereq);
+
+            $script = "
               EXE_FILES => ['$name'],
               PREREQ_PM => {
 $PREREQ_PM
                            },
 ";
+            if ($name) {
+                my $to_file = File::Spec->catfile($packagedir, $name);
+                rename $script_file, $to_file
+                    or die "Can't rename $script_file to $to_file: $!";
+            }
+        }
 
-               my $to_file = File::Spec->catfile($packagedir, $name);
-               rename $script_file, $to_file
-                 or die "Can't rename $script_file to $to_file: $!";
-           }
-
-            my $fh = FileHandle->new;
-            $fh->open(">$mpl")
-                or Carp::croak("Could not open >$mpl: $!");
-            $fh->print(
-qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
+        my $fh = FileHandle->new;
+        $fh->open(">$mpl")
+            or Carp::croak("Could not open >$mpl: $!");
+        $fh->print(
+                   qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
 # because there was no Makefile.PL supplied.
 # Autogenerated on: }.scalar localtime().qq{
 
@@ -4961,21 +5137,67 @@ WriteMakefile(
               NAME => q[$cf],$script
              );
 });
-            $fh->close;
-        }
+        $fh->close;
     }
+}
 
-    return $self;
+#-> CPAN::Distribution::_signature_business
+sub _signature_business {
+    my($self) = @_;
+    if ($CPAN::Config->{check_sigs}) {
+        if ($CPAN::META->has_inst("Module::Signature")) {
+            if (-f "SIGNATURE") {
+                $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
+                my $rv = Module::Signature::verify();
+                if ($rv != Module::Signature::SIGNATURE_OK() and
+                    $rv != Module::Signature::SIGNATURE_MISSING()) {
+                    $CPAN::Frontend->myprint(
+                                             qq{\nSignature invalid for }.
+                                             qq{distribution file. }.
+                                             qq{Please investigate.\n\n}.
+                                             $self->as_string,
+                                             $CPAN::META->instance(
+                                                                   'CPAN::Author',
+                                                                   $self->cpan_userid,
+                                                                  )->as_string
+                                            );
+
+                    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
+  look %s
+and there run
+  cpansign -v
+},
+                                $self->{localfile},
+                                $self->pretty_id,
+                               );
+                    $self->{signature_verify} = CPAN::Distrostatus->new("NO");
+                    $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap));
+                    $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep");
+                } else {
+                    $self->{signature_verify} = CPAN::Distrostatus->new("YES");
+                    $self->debug("Module::Signature has verified") if $CPAN::DEBUG;
+                }
+            } else {
+                $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n});
+            }
+        } else {
+            $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
+        }
+    }
 }
 
-# CPAN::Distribution::untar_me ;
+#-> CPAN::Distribution::untar_me ;
 sub untar_me {
     my($self,$ct) = @_;
     $self->{archived} = "tar";
     if ($ct->untar()) {
-       $self->{unwrapped} = "YES";
+       $self->{unwrapped} = CPAN::Distrostatus->new("YES");
     } else {
-       $self->{unwrapped} = "NO";
+       $self->{unwrapped} = CPAN::Distrostatus->new("NO -- untar failed");
     }
 }
 
@@ -4984,9 +5206,9 @@ sub unzip_me {
     my($self,$ct) = @_;
     $self->{archived} = "zip";
     if ($ct->unzip()) {
-       $self->{unwrapped} = "YES";
+       $self->{unwrapped} = CPAN::Distrostatus->new("YES");
     } else {
-       $self->{unwrapped} = "NO";
+       $self->{unwrapped} = CPAN::Distrostatus->new("NO -- unzip failed");
     }
     return;
 }
@@ -5003,13 +5225,13 @@ sub handle_singlefile {
     my $to = File::Basename::basename($local_file);
     if ($to =~ s/\.(gz|Z)(?!\n)\Z//) {
         if (CPAN::Tarzip->new($local_file)->gunzip($to)) {
-            $self->{unwrapped} = "YES";
+            $self->{unwrapped} = CPAN::Distrostatus->new("YES");
         } else {
-            $self->{unwrapped} = "NO";
+            $self->{unwrapped} = CPAN::Distrostatus->new("NO -- uncompressing failed");
         }
     } else {
         File::Copy::cp($local_file,".");
-        $self->{unwrapped} = "YES";
+        $self->{unwrapped} = CPAN::Distrostatus->new("NO -- copying failed");
     }
     return $to;
 }
@@ -5231,7 +5453,7 @@ sub CHECKSUM_check_file {
     $sloppy ||= 0;
     $self->debug("chk_file[$chk_file]sloppy[$sloppy]") if $CPAN::DEBUG;
     if ($CPAN::Config->{check_sigs}) {
-        if ($CPAN::META->has_inst("Module::Signature") and Module::Signature->VERSION >= 0.26) {
+        if ($CPAN::META->has_inst("Module::Signature")) {
             $self->debug("Module::Signature is installed, verifying");
             $self->SIG_check_file($chk_file);
         } else {
@@ -5369,10 +5591,26 @@ sub eq_CHECKSUM {
 sub force {
   my($self, $method) = @_;
   for my $att (qw(
-  CHECKSUM_STATUS archived build_dir localfile make install unwrapped
-  writemakefile modulebuild make_test signature_verify
+                  CHECKSUM_STATUS
+                  archived
+                  build_dir
+                  install
+                  localfile
+                  make
+                  make_test
+                  modulebuild
+                  prefs
+                  prefs_file
+                  prereq_pm
+                  prereq_pm_detected
+                  reqtype
+                  signature_verify
+                  unwrapped
+                  writemakefile
+                  yaml_content
  )) {
     delete $self->{$att};
+    CPAN->debug(sprintf "att[%s]", $att) if $CPAN::DEBUG;
   }
   if ($method && $method =~ /make|test|install/) {
     $self->{"force_update"}++; # name should probably have been force_install
@@ -5467,17 +5705,31 @@ is part of the perl-%s distribution. To install that, you need to run
     }
     $CPAN::Frontend->myprint(sprintf "Running %s for %s\n", $make, $self->id);
     $self->get;
+    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+                           ? $ENV{PERL5LIB}
+                           : ($ENV{PERLLIB} || "");
+
+    $CPAN::META->set_perl5lib;
+    local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
     if ($CPAN::Signal){
       delete $self->{force_update};
       return;
     }
   EXCUSE: {
         my @e;
-        !$self->{archived} || $self->{archived} eq "NO" and push @e,
-        "Is neither a tar nor a zip archive.";
+        if (!$self->{archived} || $self->{archived} eq "NO") {
+            push @e, "Is neither a tar nor a zip archive.";
+        }
 
-        !$self->{unwrapped} || $self->{unwrapped} eq "NO" and push @e,
-        "Had problems unarchiving. Please build manually";
+        if (!$self->{unwrapped}
+            || (
+                $self->{unwrapped}->can("failed") ?
+                $self->{unwrapped}->failed :
+                $self->{unwrapped} =~ /^NO/
+               )) {
+            push @e, "Had problems unarchiving. Please build manually";
+        }
 
         unless ($self->{force_update}) {
             exists $self->{signature_verify} and (
@@ -5558,7 +5810,12 @@ is part of the perl-%s distribution. To install that, you need to run
                           $makepl_arg ? " $makepl_arg" : "",
                          );
     }
-    local %ENV = %ENV;
+    my %env;
+    while (my($k,$v) = each %ENV) {
+        next unless defined $v;
+        $env{$k} = $v;
+    }
+    local %ENV = %env;
     if (my $env = $self->prefs->{pl}{env}) {
         for my $e (keys %$env) {
             $ENV{$e} = $env->{$e};
@@ -5620,7 +5877,7 @@ is part of the perl-%s distribution. To install that, you need to run
             }
        } else {
             if (my $expect = $self->prefs->{pl}{expect}) {
-                $ret = $self->run_via_expect($system,$expect);
+                $ret = $self->_run_via_expect($system,$expect);
             } else {
                 $ret = system($system);
             }
@@ -5692,17 +5949,26 @@ is part of the perl-%s distribution. To install that, you need to run
     }
 }
 
-# CPAN::Distribution::run_via_expect
-sub run_via_expect {
+# CPAN::Distribution::_run_via_expect
+sub _run_via_expect {
     my($self,$system,$expect) = @_;
     CPAN->debug("system[$system]expect[$expect]") if $CPAN::DEBUG;
     if ($CPAN::META->has_inst("Expect")) {
         my $expo = Expect->new;
         $expo->spawn($system);
       EXPECT: for (my $i = 0; $i < $#$expect; $i+=2) {
-            my $regex = eval "qr{$expect->[$i]}";
+            my $next = $expect->[$i];
+            my($timeout,$re);
+            if (ref $next) {
+                $timeout = $next->{timeout};
+                $re = $next->{expect};
+            } else {
+                $timeout = 15;
+                $re = $next;
+            }
+            my $regex = eval "qr{$re}";
             my $send = $expect->[$i+1];
-            $expo->expect(10,
+            $expo->expect($timeout,
                           [ eof => sub {
                                 my $but = $expo->clear_accum;
                                 $CPAN::Frontend->mywarn("EOF (maybe harmless) system[$system]
@@ -5727,8 +5993,8 @@ expected[$regex]\nbut[$but]\n\n");
 
 # CPAN::Distribution::_find_prefs
 sub _find_prefs {
-    my($self,$distro) = @_;
-    my $distroid = $distro->pretty_id;
+    my($self) = @_;
+    my $distroid = $self->pretty_id;
     CPAN->debug("distroid[$distroid]") if $CPAN::DEBUG;
     my $prefs_dir = $CPAN::Config->{prefs_dir};
     eval { File::Path::mkpath($prefs_dir); };
@@ -5743,44 +6009,59 @@ sub _find_prefs {
             next if $_ eq "." || $_ eq "..";
             next unless /\.yml$/;
             my $abs = File::Spec->catfile($prefs_dir, $_);
-            CPAN->debug("abs[$abs]") if $CPAN::DEBUG;
             if (-f $abs) {
-                my $yaml = CPAN->_yaml_loadfile($abs);
-                my $ok = 1;
-                my $match = $yaml->{match} or
-                    $CPAN::Frontend->mydie("Nonconforming YAML file '$abs': ".
-                                           "missing attribut 'match'. Please ".
-                                           "remove, cannot continue.");
-                for my $sub_attribute (keys %$match) {
-                    my $qr = eval "qr{$yaml->{match}{$sub_attribute}}";
-                    if ($sub_attribute eq "module") {
-                        my $okm = 0;
-                        my @modules = $distro->containsmods;
-                        for my $module (@modules) {
-                            $okm ||= $module =~ /$qr/;
-                            last if $okm;
+                CPAN->debug(sprintf "abs[%s]", $abs) if $CPAN::DEBUG;
+                my @yaml = @{CPAN->_yaml_loadfile($abs)};
+                # $DB::single=1;
+              ELEMENT: for my $y (0..$#yaml) {
+                    my $yaml = $yaml[$y];
+                    my $match = $yaml->{match};
+                    unless ($match) {
+                        CPAN->debug("no 'match' in abs[$abs], skipping");
+                        next ELEMENT;
+                    }
+                    my $ok = 1;
+                    for my $sub_attribute (keys %$match) {
+                        my $qr = eval "qr{$yaml->{match}{$sub_attribute}}";
+                        if ($sub_attribute eq "module") {
+                            my $okm = 0;
+                            CPAN->debug(sprintf "abs[%s]yaml[%d]", $abs, scalar @yaml) if $CPAN::DEBUG;
+                            my @modules = $self->containsmods;
+                            CPAN->debug(sprintf "abs[%s]yaml[%d]modules[%s]", $abs, scalar @yaml, join(",",@modules)) if $CPAN::DEBUG;
+                          MODULE: for my $module (@modules) {
+                                $okm ||= $module =~ /$qr/;
+                                last MODULE if $okm;
+                            }
+                            $ok &&= $okm;
+                        } elsif ($sub_attribute eq "distribution") {
+                            my $okd = $distroid =~ /$qr/;
+                            $ok &&= $okd;
+                        } elsif ($sub_attribute eq "perl") {
+                            my $okp = $^X =~ /$qr/;
+                            $ok &&= $okp;
+                        } else {
+                            $CPAN::Frontend->mydie("Nonconforming YAML file '$abs': ".
+                                                   "unknown sub_attribut '$sub_attribute'. ".
+                                                   "Please ".
+                                                   "remove, cannot continue.");
                         }
-                        $ok &&= $okm;
-                    } elsif ($sub_attribute eq "distribution") {
-                        my $okd = $distroid =~ /$qr/;
-                        $ok &&= $okd;
-                    } else {
-                        $CPAN::Frontend->mydie("Nonconforming YAML file '$abs': ".
-                                               "unknown sub_attribut '$sub_attribute'. ".
-                                               "Please ".
-                                               "remove, cannot continue.");
                     }
-                }
-                if ($ok) {
-                    return {
-                            prefs => $yaml,
-                            prefs_file => $abs,
-                           };
+                    CPAN->debug(sprintf "abs[%s]yaml[%d]ok[%d]", $abs, scalar @yaml, $ok) if $CPAN::DEBUG;
+                    if ($ok) {
+                        return {
+                                prefs => $yaml,
+                                prefs_file => $abs,
+                                prefs_file_section => $y,
+                               };
+                    }
+
                 }
             }
         }
     } else {
-        $CPAN::Frontend->mywarn("'$yaml_module' not installed, cannot read prefs '$prefs_dir'\n");
+        unless ($self->{have_complained_about_missing_yaml}++) {
+            $CPAN::Frontend->mywarn("'$yaml_module' not installed, cannot read prefs '$prefs_dir'\n");
+        }
     }
     return;
 }
@@ -5793,19 +6074,23 @@ sub prefs {
     }
     if ($CPAN::Config->{prefs_dir}) {
         CPAN->debug("prefs_dir[$CPAN::Config->{prefs_dir}]") if $CPAN::DEBUG;
-        my $prefs = $self->_find_prefs($self);
+        my $prefs = $self->_find_prefs();
         if ($prefs) {
-            for my $x (qw(prefs prefs_file)) {
+            for my $x (qw(prefs prefs_file prefs_file_section)) {
                 $self->{$x} = $prefs->{$x};
             }
-            my $basename = File::Basename::basename($self->{prefs_file});
+            my $bs = sprintf(
+                             "%s[%s]",
+                             File::Basename::basename($self->{prefs_file}),
+                             $self->{prefs_file_section},
+                            );
             my $filler1 = "_" x 22;
-            my $filler2 = int(66 - length($basename))/2;
+            my $filler2 = int(66 - length($bs))/2;
             $filler2 = 0 if $filler2 < 0;
             $filler2 = " " x $filler2;
             $CPAN::Frontend->myprint("
 $filler1 D i s t r o P r e f s $filler1
-$filler2 $basename $filler2
+$filler2 $bs $filler2
 ");
             $CPAN::Frontend->mysleep(1);
             return $self->{prefs};
@@ -5842,8 +6127,8 @@ sub _make_command {
         return
             CPAN::HandleConfig
                 ->safe_quote(
-                             $self->prefs->{cpanconfig}{make}
-                             || $CPAN::Config->{make}
+                             CPAN::HandleConfig->prefs_lookup($self,
+                                                              q{make})
                              || $Config::Config{make}
                              || 'make'
                             );
@@ -5852,7 +6137,7 @@ sub _make_command {
         Carp::confess("CPAN::_make_command() used as function. Don't Do That.");
         return
           safe_quote(undef,
-                     $self->prefs->{cpanconfig}{make}
+                     CPAN::HandleConfig->prefs_lookup($self,q{make})
                      || $CPAN::Config->{make}
                      || $Config::Config{make}
                      || 'make');
@@ -5865,15 +6150,30 @@ sub follow_prereqs {
     my(@prereq_tuples) = grep {$_->[0] ne "perl"} @_;
     return unless @prereq_tuples;
     my @prereq = map { $_->[0] } @prereq_tuples;
-    my $id = $self->id;
+    my $pretty_id = $self->pretty_id;
     my %map = (
                b => "build_requires",
                r => "requires",
                c => "commandline",
               );
+    my($filler1,$filler2,$filler3,$filler4);
+    my $unsat = "Unsatisfied dependencies detected during";
+    my $w = length($unsat) > length($pretty_id) ? length($unsat) : length($pretty_id);
+    {
+        my $r = int(($w - length($unsat))/2);
+        my $l = $w - length($unsat) - $r;
+        $filler1 = "-"x4 . " "x$l;
+        $filler2 = " "x$r . "-"x4 . "\n";
+    }
+    {
+        my $r = int(($w - length($pretty_id))/2);
+        my $l = $w - length($pretty_id) - $r;
+        $filler3 = "-"x4 . " "x$l;
+        $filler4 = " "x$r . "-"x4 . "\n";
+    }
     $CPAN::Frontend->
-        myprint("---- Unsatisfied dependencies detected during\n".
-                "---- $id\n".
+        myprint("$filler1 $unsat $filler2".
+                "$filler3 $pretty_id $filler4".
                 join("", map {"    $_->[0] \[$map{$_->[1]}]\n"} @prereq_tuples),
                );
     my $follow = 0;
@@ -5890,6 +6190,7 @@ of modules we are processing right now?", "yes");
             myprint("  Ignoring dependencies on modules @prereq\n");
     }
     if ($follow) {
+        my $id = $self->id;
         # color them as dirty
         for my $p (@prereq) {
             # warn "calling color_cmd_tmps(0,1)";
@@ -5998,9 +6299,9 @@ sub read_yaml {
     my $yaml = File::Spec->catfile($build_dir,"META.yml");
     $self->debug("yaml[$yaml]") if $CPAN::DEBUG;
     return unless -f $yaml;
-    eval { $self->{yaml_content} = CPAN->_yaml_loadfile($yaml); };
+    eval { $self->{yaml_content} = CPAN->_yaml_loadfile($yaml)->[0]; };
     if ($@) {
-        return; # if we die, then we cannot read our own META.yml
+        return; # if we die, then we cannot read YAML's own META.yml
     }
     if (not exists $self->{yaml_content}{dynamic_config}
         or $self->{yaml_content}{dynamic_config}
@@ -6090,19 +6391,28 @@ sub prereq_pm {
                     $req  = Module::Build->current->requires();
                     $breq = Module::Build->current->build_requires();
                 };
+                # this failed for example for HTML::Mason and for
+                # Error.pm because they are subclassing Module::Build
+                # in their Build.PL in such a way that Module::Build
+                # cannot read the _build directory. We DO need a dump
+                # command for that.
                 if ($@) {
-                    # HTML::Mason prompted for this with bleadperl@28900 or so
                     $CPAN::Frontend
                         ->mywarn(
                                  sprintf("Warning: while trying to determine ".
                                          "prerequisites for %s with the help of ".
                                          "Module::Build the following error ".
-                                         "occurred: '%s'\n\nCannot care for prerequisites\n",
+                                         "occurred: '%s'\n\nFalling back to META.yml ".
+                                         "for prerequisites\n",
                                          $self->id,
                                          $@
                                         ));
-                    $self->{prereq_pm_detected}++;
-                    return $self->{prereq_pm} = {requires=>{},build_requires=>{}};
+                    my $build_dir = $self->{build_dir};
+                    my $yaml = File::Spec->catfile($build_dir,"META.yml");
+                    if ($yaml = CPAN->_yaml_loadfile($yaml)->[0]) {
+                        $req =  $yaml->{requires} || {};
+                        $breq =  $yaml->{build_requires} || {};
+                    }
                 }
             }
         }
@@ -6138,6 +6448,14 @@ sub test {
     }
 
     my $make = $self->{modulebuild} ? "Build" : "make";
+
+    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+                           ? $ENV{PERL5LIB}
+                           : ($ENV{PERLLIB} || "");
+
+    $CPAN::META->set_perl5lib;
+    local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
     $CPAN::Frontend->myprint("Running $make test\n");
     if (my @prereq = $self->unsat_prereq){
         unless ($prereq[0][0] eq "perl") {
@@ -6218,17 +6536,64 @@ sub test {
         $system = join " ", $self->_make_command(), "test";
     }
     my($tests_ok);
-    local %ENV = %ENV;
+    my %env;
+    while (my($k,$v) = each %ENV) {
+        next unless defined $v;
+        $env{$k} = $v;
+    }
+    local %ENV = %env;
     if (my $env = $self->prefs->{test}{env}) {
         for my $e (keys %$env) {
             $ENV{$e} = $env->{$e};
         }
     }
     my $expect = $self->prefs->{test}{expect};
-    if ($expect && @$expect) {
-        $tests_ok = $self->run_via_expect($system,$expect) == 0;
-    } elsif ( $CPAN::Config->{test_report} && 
-              $CPAN::META->has_inst("CPAN::Reporter") ) {
+    my $can_expect = $CPAN::META->has_inst("Expect");
+    my $want_expect = 0;
+    if ( $expect && @$expect ) {
+        if ($can_expect) {
+            $want_expect = 1;
+        } else {
+            $CPAN::Frontend->mywarn("Expect not installed, falling back to ".
+                                    "testing without\n");
+        }
+    }
+    my $test_report = CPAN::HandleConfig->prefs_lookup($self,
+                                                       q{test_report});
+    my $can_report = $CPAN::META->has_inst("CPAN::Reporter");
+    my $want_report = $test_report && $can_report;
+    my $ready_to_report = $want_report;
+    if ($ready_to_report
+        && (
+            substr($self->id,-1,1) eq "."
+            ||
+            $self->author->id eq "LOCAL"
+           )
+       ) {
+        $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
+                                "for for local directories\n");
+        $ready_to_report = 0;
+    }
+    if ($ready_to_report
+        &&
+        $self->prefs->{patches}
+        &&
+        @{$self->prefs->{patches}}
+        &&
+        $self->{patched}
+       ) {
+        $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
+                                "when the source has been patched\n");
+        $ready_to_report = 0;
+    }
+    if ($want_expect) {
+        if ($ready_to_report) {
+            $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is currently ".
+                                    "not supported when distroprefs specify ".
+                                    "an interactive test\n");
+        }
+        $tests_ok = $self->_run_via_expect($system,$expect) == 0;
+    } elsif ( $ready_to_report ) {
         $tests_ok = CPAN::Reporter::test($self, $system);
     } else {
         $tests_ok = system($system) == 0;
@@ -6254,7 +6619,7 @@ sub test {
                 my $verb = $cnt == 1 ? "one dependency not OK ($which)" :
                     "$cnt dependencies missing ($which)";
                 $CPAN::Frontend->mywarn("Tests succeeded but $verb\n");
-                $self->{make_test} = CPAN::Distrostatus->new("NO -- $verb");
+                $self->{make_test} = CPAN::Distrostatus->new("NO $verb");
                 return;
             }
         }
@@ -6427,9 +6792,9 @@ sub install {
                          );
     } else {
         my($make_install_make_command) =
-            $self->prefs->{cpanconfig}{make_install_make_command}
-                || $CPAN::Config->{make_install_make_command}
-                    || $self->_make_command();
+            CPAN::HandleConfig->prefs_lookup($self,
+                                             q{make_install_make_command})
+                  || $self->_make_command();
         $system = sprintf("%s install %s",
                           $make_install_make_command,
                           $CPAN::Config->{make_install_arg},
@@ -6437,8 +6802,8 @@ sub install {
     }
 
     my($stderr) = $^O eq "MSWin32" ? "" : " 2>&1 ";
-    my $brip = $self->prefs->{cpanconfig}{build_requires_install_policy};
-    $brip ||= $CPAN::Config->{build_requires_install_policy};
+    my $brip = CPAN::HandleConfig->prefs_lookup($self,
+                                                q{build_requires_install_policy});
     $brip ||="ask/yes";
     my $id = $self->id;
     my $reqtype = $self->{reqtype} ||= "c"; # in doubt it was a command
@@ -6480,15 +6845,15 @@ sub install {
         $self->{install} = CPAN::Distrostatus->new("NO");
         $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
         my $mimc =
-            $self->prefs->{cpanconfig}{make_install_make_command} ||
-                $CPAN::Config->{make_install_make_command};
+            CPAN::HandleConfig->prefs_lookup($self,
+                                             q{make_install_make_command});
         if (
             $makeout =~ /permission/s
             && $> > 0
             && (
                 ! $mimc
-                || $mimc eq ($self->prefs->{cpanconfig}{make}
-                             || $CPAN::Config->{make})
+                || $mimc eq (CPAN::HandleConfig->prefs_lookup($self,
+                                                              q{make}))
                )
            ) {
             $CPAN::Frontend->myprint(
@@ -6918,9 +7283,10 @@ sub rematein {
        if ($type eq 'CPAN::Distribution') {
            $CPAN::Frontend->mywarn(qq{
 The Bundle }.$self->id.qq{ contains
-explicitly a file $s.
+explicitly a file '$s'.
+Going to $meth that.
 });
-           $CPAN::Frontend->mysleep(3);
+           $CPAN::Frontend->mysleep(5);
        }
        # possibly noisy action:
         $self->debug("type[$type] s[$s]") if $CPAN::DEBUG;
@@ -7321,7 +7687,7 @@ sub manpage_headline {
 # Note: also inherited by CPAN::Bundle
 sub cpan_file {
     my $self = shift;
-    CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
+    # CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
     unless ($self->ro) {
        CPAN::Index->reload;
     }
@@ -7862,6 +8228,13 @@ perl breaks binary compatibility. If one of the modules that CPAN uses
 is in turn depending on binary compatibility (so you cannot run CPAN
 commands), then you should try the CPAN::Nox module for recovery.
 
+=head2 report Bundle|Distribution|Module
+
+The C<report> command temporarily turns on the C<test_report> config
+variable, then runs the C<force test> command with the given
+arguments. The C<force> pragma is used to re-run the tests and repeat
+every step that might have failed before.
+
 =head2 upgrade [Module|/Regex/]...
 
 The C<upgrade> command first runs an C<r> command with the given
@@ -7894,9 +8267,9 @@ Modules know their associated Distribution objects. They always refer
 to the most recent official release. Developers may mark their releases
 as unstable development versions (by inserting an underbar into the
 module version number which will also be reflected in the distribution
-name when you run 'make dist'), so the really hottest and newest 
-distribution is not always the default.  If a module Foo circulates 
-on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient 
+name when you run 'make dist'), so the really hottest and newest
+distribution is not always the default.  If a module Foo circulates
+on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
 way to install version 1.23 by saying
 
     install Foo
@@ -7913,6 +8286,29 @@ so you would have to say
 The first example will be driven by an object of the class
 CPAN::Module, the second by an object of class CPAN::Distribution.
 
+=head2 Integrating local directories
+
+Distribution objects are normally distributions from the CPAN, but
+there is a slightly degenerate case for Distribution objects, too,
+normally only needed by developers. If a distribution object ends with
+a dot or is a dot by itself, then it represents a local directory and
+all actions such as C<make>, C<test>, and C<install> are applied
+directly to that directory. This gives the command C<cpan .> an
+interesting touch: while the normal mantra of installing a CPAN module
+without CPAN.pm is one of
+
+    perl Makefile.PL                 perl Build.PL
+           ( go and get prerequisites )
+    make                             ./Build
+    make test                        ./Build test
+    make install                     ./Build install
+
+the command C<cpan .> does all of this at once. It figures out which
+of the two mantras is appropriate, fetches and installs all
+prerequisites, cares for them recursively and finally finishes the
+installation of the module in the current directory, be it a CPAN
+module or not.
+
 =head1 PROGRAMMER'S INTERFACE
 
 If you do not enter the shell, the available shell commands are both
@@ -8219,7 +8615,8 @@ through the pager specified in C<$CPAN::Config->{pager}>.
 
 Returns the content of the META.yml of this distro as a hashref. Note:
 works only after an attempt has been made to C<make> the distribution.
-Returns undef otherwise.
+Returns undef otherwise. Also returns undef if the content of META.yml
+is dynamic.
 
 =item CPAN::Distribution::test()
 
@@ -8657,6 +9054,7 @@ defined:
   no_proxy           don't proxy to these hosts/domains (comma separated list)
   pager              location of external program more (or any pager)
   password           your password if you CPAN server wants one
+  patch              path to external prg
   prefer_installer   legal values are MB and EUMM: if a module comes
                      with both a Makefile.PL and a Build.PL, use the
                      former (EUMM) or the latter (MB); if the module
@@ -8789,17 +9187,18 @@ modules like Plagger.
 
 CPAN.pm can use YAML files to either pass additional arguments to one
 of the four commands, set environment variables or instantiate an
-Expect object that reads from the console, waits for some regular
-expression and enters some answer. Needless to say that for the latter
-option Expect.pm needs to be installed.
+Expect object that reads from the console and enters answers on your
+behalf (latter option requires Expect.pm installed). A further option
+is to apply patches from the local disk or from CPAN.
 
 CPAN.pm comes with a couple of such YAML files. The structure is
-currently not documented. Please see the distroprefs directory of the
-CPAN distribution for examples and follow the README in there.
+currently not documented because in flux. Please see the distroprefs
+directory of the CPAN distribution for examples and follow the README
+in there.
 
 Please note that setting the environment variable PERL_MM_USE_DEFAULT
 to a true value can also get you a long way if you want to always pick
-the default answers. But this only works if the author of apackage
+the default answers. But this only works if the author of a package
 used the prompt function provided by ExtUtils::MakeMaker and if the
 defaults are OK for you.