Upgrade to CPAN-1.88_72
Steve Peters [Tue, 13 Feb 2007 15:23:00 +0000 (15:23 +0000)]
p4raw-id: //depot/perl@30256

lib/CPAN.pm
lib/CPAN/FirstTime.pm
lib/CPAN/HandleConfig.pm
lib/CPAN/Queue.pm
lib/CPAN/Tarzip.pm

index 434fc16..2221a5f 100644 (file)
@@ -1,7 +1,7 @@
 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
 use strict;
 package CPAN;
-$CPAN::VERSION = '1.88_69';
+$CPAN::VERSION = '1.88_73';
 $CPAN::VERSION = eval $CPAN::VERSION;
 
 use CPAN::HandleConfig;
@@ -64,13 +64,13 @@ use vars qw(
             $AUTOLOAD
             $Be_Silent
             $CONFIG_DIRTY
-            $DEBUG
             $Defaultdocs
             $Defaultrecent
             $Frontend
             $GOTOSHELL
             $HAS_USABLE
             $Have_warned
+            $MAX_RECURSION
             $META
             $RUN_DEGRADED
             $Signal
@@ -83,6 +83,8 @@ use vars qw(
             @EXPORT
            );
 
+$MAX_RECURSION = 32;
+
 @CPAN::ISA = qw(CPAN::Debug Exporter);
 
 # note that these functions live in CPAN::Shell and get executed via
@@ -98,6 +100,7 @@ use vars qw(
              get
              install
              install_tested
+             is_tested
              make
              mkmyconfig
              notest
@@ -179,14 +182,7 @@ sub shell {
                 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
                 last;
             }
-            my($fh) = FileHandle->new;
-            open $fh, "<$histfile" or last;
-            local $/ = "\n";
-            while (<$fh>) {
-                chomp;
-                $term->AddHistory($_);
-            }
-            close $fh;
+            $META->readhist($term,$histfile);
         }}
         for ($CPAN::Config->{term_ornaments}) { # alias
             local $Term::ReadLine::termcap_nowarn = 1;
@@ -374,14 +370,28 @@ sub _yaml_loadfile {
     return +[] unless -s $local_file;
     my $yaml_module = _yaml_module;
     if ($CPAN::META->has_inst($yaml_module)) {
-        my $code = UNIVERSAL::can($yaml_module, "LoadFile");
-        my @yaml;
-        eval { @yaml = $code->($local_file); };
-        if ($@) {
-            # this shall not be done by the frontend
-            die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
+        my $code;
+        if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
+            my @yaml;
+            eval { @yaml = $code->($local_file); };
+            if ($@) {
+                # this shall not be done by the frontend
+                die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
+            }
+            return \@yaml;
+        } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
+            local *FH;
+            open FH, $local_file or die "Could not open '$local_file': $!";
+            local $/;
+            my $ystream = <FH>;
+            my @yaml;
+            eval { @yaml = $code->($ystream); };
+            if ($@) {
+                # this shall not be done by the frontend
+                die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
+            }
+            return \@yaml;
         }
-        return \@yaml;
     } else {
         # this shall not be done by the frontend
         die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
@@ -394,12 +404,16 @@ sub _yaml_dumpfile {
     my($self,$local_file,@what) = @_;
     my $yaml_module = _yaml_module;
     if ($CPAN::META->has_inst($yaml_module)) {
+        my $code;
         if (UNIVERSAL::isa($local_file, "FileHandle")) {
-            my $code = UNIVERSAL::can($yaml_module, "Dump");
+            $code = UNIVERSAL::can($yaml_module, "Dump");
             eval { print $local_file $code->(@what) };
-        } else {
-            my $code = UNIVERSAL::can($yaml_module, "DumpFile");
+        } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
             eval { $code->($local_file,@what); };
+        } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
+            local *FH;
+            open FH, ">$local_file" or die "Could not open '$local_file': $!";
+            print FH $code->(@what);
         }
         if ($@) {
             die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
@@ -466,11 +480,13 @@ use strict;
                                     clean
                                     cvs_import
                                     dump
+                                    failed
                                     force
                                     fforce
                                     hosts
                                     install
                                     install_tested
+                                    is_tested
                                     look
                                     ls
                                     make
@@ -520,6 +536,10 @@ package CPAN::Exception::RecursiveDependency;
 use strict;
 use overload '""' => "as_string";
 
+# a module sees its distribution (no version)
+# a distribution sees its prereqs (which are module names) (usually with versions)
+# a bundle sees its module names and/or its distributions (no version)
+
 sub new {
     my($class) = shift;
     my($deps) = shift;
@@ -709,10 +729,11 @@ sub _perl_fingerprint {
     if (defined $dll) {
         $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
     }
+    my $mtime_perl = (-f $^X ? (stat(_))[9] : '-1');
     my $this_fingerprint = {
                             '$^X' => $^X,
                             sitearchexp => $Config::Config{sitearchexp},
-                            'mtime_$^X' => (stat $^X)[9],
+                            'mtime_$^X' => $mtime_perl,
                             'mtime_dll' => $mtime_dll,
                            };
     if ($other_fingerprint) {
@@ -1064,6 +1085,16 @@ sub has_usable {
                                         }
                                     },
                                   ],
+               'Archive::Tar' => [
+                                  sub {require Archive::Tar;
+                                       unless (Archive::Tar::->VERSION >= 1.00) {
+                                            for ("Will not use Archive::Tar, need 1.00\n") {
+                                                $CPAN::Frontend->mywarn($_);
+                                                die $_;
+                                            }
+                                       }
+                                  },
+                                 ],
               };
     if ($usable->{$mod}) {
         for my $c (0..$#{$usable->{$mod}}) {
@@ -1128,7 +1159,7 @@ sub has_inst {
        $CPAN::Frontend->mysleep(3);
     } elsif ($mod eq "Digest::SHA"){
         if ($Have_warned->{"Digest::SHA"}++) {
-            $CPAN::Frontend->myprint(qq{CPAN: checksum security checks disabled}.
+            $CPAN::Frontend->myprint(qq{CPAN: checksum security checks disabled }.
                                      qq{because Digest::SHA not installed.\n});
         } else {
             $CPAN::Frontend->mywarn(qq{
@@ -1210,6 +1241,19 @@ sub cleanup {
   $CPAN::Frontend->myprint("Lockfile removed.\n");
 }
 
+#-> sub CPAN::readhist
+sub readhist {
+    my($self,$term,$histfile) = @_;
+    my($fh) = FileHandle->new;
+    open $fh, "<$histfile" or last;
+    local $/ = "\n";
+    while (<$fh>) {
+        chomp;
+        $term->AddHistory($_);
+    }
+    close $fh;
+}
+
 #-> sub CPAN::savehist
 sub savehist {
     my($self) = @_;
@@ -1327,8 +1371,11 @@ sub tidyup {
     my($toremove) = shift @{$self->{FIFO}};
     unless ($toremove =~ /\.yml$/) {
         $CPAN::Frontend->myprint(sprintf(
-                                         "DEL: $toremove (%.1f>%.1f MB)\n",
-                                         $self->{DU}, $self->{'MAX'})
+                                         "DEL(%.1f>%.1fMB): %s \n",
+                                         $self->{DU},
+                                         $self->{MAX},
+                                         $toremove,
+                                        )
                                 );
     }
     return if $CPAN::Signal;
@@ -1436,7 +1483,22 @@ sub _clean_cache {
     $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
        if $CPAN::DEBUG;
     File::Path::rmtree($dir);
-    unlink "$dir.yml"; # may fail
+    my $id_deleted = 0;
+    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}) {
+                $CPAN::META->delete("CPAN::Distribution", $id);
+                # $CPAN::Frontend->mywarn (" +++\n");
+                $id_deleted++;
+            }
+        }
+        unlink "$dir.yml"; # may fail
+        unless ($id_deleted) {
+            CPAN->debug("no distro found associated with '$dir'");
+        }
+    }
     $self->{DU} -= $self->{SIZE}{$dir};
     delete $self->{SIZE}{$dir};
 }
@@ -1470,6 +1532,7 @@ sub scan_cache {
     return if $self->{SCAN} eq 'never';
     $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
        unless $self->{SCAN} eq 'atstart';
+    return unless $CPAN::META->{LOCK};
     $CPAN::Frontend->myprint(
                             sprintf("Scanning cache %s for sizes\n",
                                     $self->{ID}));
@@ -1724,7 +1787,7 @@ sub o {
                 CPAN::HandleConfig->prettyprint($k);
            }
            $CPAN::Frontend->myprint("\n");
-       } else {
+        } else {
             if (CPAN::HandleConfig->edit(@o_what)) {
             } else {
                 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
@@ -1841,7 +1904,7 @@ sub hosts {
         $S{end} ||= $last->{end};
         my $dltime = $last->{end} - $start;
         my $dlsize = $last->{filesize} || 0;
-        my $url = $last->{thesiteurl}->text;
+        my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
         my $s = $S{ok}{$url} ||= {};
         $s->{n}++;
         $s->{dlsize} ||= 0;
@@ -1904,6 +1967,7 @@ sub reload {
                     "CPAN/Kwalify.pm",
                     "CPAN/Queue.pm",
                     "CPAN/Reporter.pm",
+                    "CPAN/SQLite.pm",
                     "CPAN/Tarzip.pm",
                     "CPAN/Version.pm",
                    );
@@ -2127,7 +2191,7 @@ sub report {
                                 # re-run (as documented)
 }
 
-# experimental (compare with _is_tested)
+# compare with is_tested
 #-> sub CPAN::Shell::install_tested
 sub install_tested {
     my($self,@some) = @_;
@@ -2141,8 +2205,8 @@ sub install_tested {
             $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
             next;
         }
-        my $yaml_content = CPAN::_yaml_loadfile($yaml);
-        my $id = $yaml_content->[0]{ID};
+        my $yaml_content = CPAN->_yaml_loadfile($yaml);
+        my $id = $yaml_content->[0]{distribution}{ID};
         unless ($id){
             $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
             next;
@@ -2442,11 +2506,11 @@ sub status {
     }
 }
 
-# experimental (must run after failed or similar [I think])
-# intended as a preparation ot install_tested
+# compare with install_tested
 #-> sub CPAN::Shell::is_tested
-sub _is_tested {
+sub is_tested {
     my($self) = @_;
+    CPAN::Index->reload;
     for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
         my $time;
         if ($CPAN::META->{is_tested}{$b}) {
@@ -2727,7 +2791,7 @@ sub print_ornamented {
         my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
         if ($@) {
             print "Term::ANSIColor rejects color[$ornament]: $@\n
-Please choose a different color (Hint: try 'o conf init color.*')\n";
+Please choose a different color (Hint: try 'o conf init /color/')\n";
         }
         print $color_on,
             $swhat,
@@ -2819,6 +2883,7 @@ sub unrecoverable_error {
 #-> sub CPAN::Shell::mysleep ;
 sub mysleep {
     my($self, $sleep) = @_;
+    use Time::HiRes qw(sleep);
     sleep $sleep;
 }
 
@@ -2861,6 +2926,8 @@ sub rematein {
     # enter the queue but not its copy. How do they get a sensible
     # test_count?
 
+    my $needs_recursion_protection = "make|test|install";
+
     # construct the queue
     my($s,@s,@qcopy);
   STHING: foreach $s (@some) {
@@ -2887,7 +2954,10 @@ sub rematein {
        }
        if (0) {
         } elsif (ref $obj) {
-            $obj->color_cmd_tmps(0,1);
+            if ($meth =~ /^($needs_recursion_protection)$/) {
+                # silly for look or dump
+                $obj->color_cmd_tmps(0,1);
+            }
             CPAN::Queue->new(qmod => $obj->id, reqtype => "c");
             push @qcopy, $obj;
        } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
@@ -2927,6 +2997,15 @@ to find objects with matching identifiers.
         my $s = $q->as_string;
         my $reqtype = $q->reqtype || "";
         $obj = CPAN::Shell->expandany($s);
+        unless ($obj) {
+            # don't know how this can happen, maybe we should panic,
+            # but maybe we get a solution from the first user who hits
+            # this unfortunate exception?
+            $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
+                                    "to an object. Skipping.");
+            $CPAN::Frontend->mysleep(5);
+            next;
+        }
         $obj->{reqtype} ||= "";
         {
             # force debugging because CPAN::SQLite somehow delivers us
@@ -3002,8 +3081,10 @@ to find objects with matching identifiers.
         }
        CPAN::Queue->delete_first($s);
     }
-    for my $obj (@qcopy) {
-        $obj->color_cmd_tmps(0,0);
+    if ($meth =~ /^($needs_recursion_protection)$/) {
+        for my $obj (@qcopy) {
+            $obj->color_cmd_tmps(0,0);
+        }
     }
 }
 
@@ -3233,6 +3314,7 @@ sub _new_stats {
 sub _add_to_statistics {
     my($self,$stats) = @_;
     my $yaml_module = CPAN::_yaml_module;
+    $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG;
     if ($CPAN::META->has_inst($yaml_module)) {
         $stats->{thesiteurl} = $ThesiteURL;
         if (CPAN->has_inst("Time::HiRes")) {
@@ -3254,7 +3336,7 @@ sub _add_to_statistics {
         # arbitrary hardcoded constants until somebody demands to have
         # them settable
         while (
-               @{$fullstats->{history}} > 9999
+               @{$fullstats->{history}} > 999
                || $time - $fullstats->{history}[0]{start} > 30*86400  # one month
               ) {
             shift @{$fullstats->{history}}
@@ -3563,7 +3645,9 @@ sub localize {
     if ($ret) {
         $stats->{filesize} = -s $ret;
     }
+    $self->debug("before _add_to_statistics") if $CPAN::DEBUG;
     $self->_add_to_statistics($stats);
+    $self->debug("after _add_to_statistics") if $CPAN::DEBUG;
     if ($ret) {
         unlink "$aslocal.bak$$";
         return $ret;
@@ -4202,7 +4286,7 @@ sub cpl {
     $pos ||= 0;
     CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
     $line =~ s/^\s*//;
-    if ($line =~ s/^(force\s*)//) {
+    if ($line =~ s/^((?:notest|f?force)\s*)//) {
        $pos -= length($1);
     }
     my @return;
@@ -5372,7 +5456,11 @@ sub pretty_id {
     substr($id,5);
 }
 
-# mark as dirty/clean
+# mark as dirty/clean for the sake of recursion detection. $color=1
+# means "in use", $color=0 means "not in use anymore". $color=2 means
+# we have determined prereqs now and thus insist on passing this
+# through (at least) once again.
+
 #-> sub CPAN::Distribution::color_cmd_tmps ;
 sub color_cmd_tmps {
     my($self) = shift;
@@ -5382,8 +5470,9 @@ sub color_cmd_tmps {
     # a distribution needs to recurse into its prereq_pms
 
     return if exists $self->{incommandcolor}
+        && $color==1
         && $self->{incommandcolor}==$color;
-    if ($depth>=100){
+    if ($depth>=$CPAN::MAX_RECURSION){
         $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
     }
     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
@@ -5407,7 +5496,7 @@ sub color_cmd_tmps {
         # as we are at the end of a command, we'll give up this
         # reminder of a broken test. Other commands may test this guy
         # again. Maybe 'badtestcnt' should be renamed to
-        # 'makte_test_failed_within_command'?
+        # 'make_test_failed_within_command'?
         delete $self->{badtestcnt};
     }
     $self->{incommandcolor} = $color;
@@ -5745,8 +5834,10 @@ EOF
     my $prefer_installer = "eumm"; # eumm|mb
     if (-f File::Spec->catfile($packagedir,"Build.PL")) {
         if ($mpl_exists) { # they *can* choose
-            $prefer_installer = CPAN::HandleConfig->prefs_lookup($self,
-                                                                 q{prefer_installer});
+            if ($CPAN::META->has_inst("Module::Build")) {
+                $prefer_installer = CPAN::HandleConfig->prefs_lookup($self,
+                                                                     q{prefer_installer});
+            }
         } else {
             $prefer_installer = "mb";
         }
@@ -7190,6 +7281,13 @@ sub _find_prefs {
 # CPAN::Distribution::prefs
 sub prefs {
     my($self) = @_;
+    if (exists $self->{negative_prefs_cache}
+        &&
+        $self->{negative_prefs_cache} != $CPAN::CurrentCommandId
+       ) {
+        delete $self->{negative_prefs_cache};
+        delete $self->{prefs};
+    }
     if (exists $self->{prefs}) {
         return $self->{prefs}; # XXX comment out during debugging
     }
@@ -7219,7 +7317,8 @@ $filler2 $bs $filler2
             return $self->{prefs};
         }
     }
-    return +{};
+    $self->{negative_prefs_cache} = $CPAN::CurrentCommandId;
+    return $self->{prefs} = +{};
 }
 
 # CPAN::Distribution::make_x_arg
@@ -7280,6 +7379,7 @@ sub follow_prereqs {
                c => "commandline",
               );
     my($filler1,$filler2,$filler3,$filler4);
+    # $DB::single=1;
     my $unsat = "Unsatisfied dependencies detected during";
     my $w = length($unsat) > length($pretty_id) ? length($unsat) : length($pretty_id);
     {
@@ -7319,7 +7419,7 @@ of modules we are processing right now?", "yes");
             # warn "calling color_cmd_tmps(0,1)";
             my $any = CPAN::Shell->expandany($p);
             if ($any) {
-                $any->color_cmd_tmps(0,1);
+                $any->color_cmd_tmps(0,2);
             } else {
                 $CPAN::Frontend->mywarn("Warning (maybe a bug): Cannot expand prereq '$p'\n");
                 $CPAN::Frontend->mysleep(2);
@@ -7341,19 +7441,21 @@ sub unsat_prereq {
     my $prereq_pm = $self->prereq_pm or return;
     my(@need);
     my %merged = (%{$prereq_pm->{requires}||{}},%{$prereq_pm->{build_requires}||{}});
+    my @merged = %merged;
+    CPAN->debug("all merged_prereqs[@merged]") if $CPAN::DEBUG;
   NEED: while (my($need_module, $need_version) = each %merged) {
-        my($available_version,$available_file);
+        my($available_version,$available_file,$nmo);
         if ($need_module eq "perl") {
             $available_version = $];
             $available_file = $^X;
         } else {
-            my $nmo = $CPAN::META->instance("CPAN::Module",$need_module);
+            $nmo = $CPAN::META->instance("CPAN::Module",$need_module);
             next if $nmo->uptodate;
             $available_file = $nmo->available_file;
 
             # if they have not specified a version, we accept any installed one
             if (not defined $need_version or
-                $need_version eq "0" or
+                $need_version == 0 or
                 $need_version eq "undef") {
                 next if defined $available_file;
             }
@@ -7410,13 +7512,71 @@ sub unsat_prereq {
         }
         if ($self->{sponsored_mods}{$need_module}++){
             # We have already sponsored it and for some reason it's still
-            # not available. So we do nothing. Or what should we do?
+            # not available. So we do ... what??
+
             # if we push it again, we have a potential infinite loop
-            next;
+
+            # The following "next" was a very problematic construct.
+            # It helped a lot but broke some day and must be replaced.
+
+            # We must be able to deal with modules that come again and
+            # again as a prereq and have themselves prereqs and the
+            # queue becomes long but finally we would find the correct
+            # order. The RecursiveDependency check should trigger a
+            # die when it's becoming too weird. Unfortunately removing
+            # this next breaks many other things.
+
+            # 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
+
+            # The following "next NEED" are fine and the error message
+            # explains well what is going on. For example when the DBI
+            # fails and consequently DBD::SQLite fails and now we are
+            # processing CPAN::SQLite. Then we must have a "next" for
+            # DBD::SQLite. How can we get it and how can we identify
+            # all other cases we must identify?
+
+            my $do = $nmo->distribution;
+            next NEED unless $do; # not on CPAN
+          NOSAYER: for my $nosayer (
+                                    "unwrapped",
+                                    "writemakefile",
+                                    "signature_verify",
+                                    "make",
+                                    "make_test",
+                                    "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;
+                    }
+                    $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;
+                }
+            }
         }
         my $needed_as = exists $prereq_pm->{requires}{$need_module} ? "r" : "b";
         push @need, [$need_module,$needed_as];
     }
+    my @unfolded = map { "[".join(",",@$_)."]" } @need;
+    CPAN->debug("returning from unsat_prereq[@unfolded]") if $CPAN::DEBUG;
     @need;
 }
 
@@ -7437,6 +7597,7 @@ sub read_yaml {
                                               # cannot read YAML's own
                                               # META.yml
     }
+    # not "authoritative"
     if (not exists $self->{yaml_content}{dynamic_config}
         or $self->{yaml_content}{dynamic_config}
        ) {
@@ -7451,7 +7612,7 @@ sub read_yaml {
 sub prereq_pm {
     my($self) = @_;
     $self->{prereq_pm_detected} ||= 0;
-    CPAN->debug("prereq_pm_detected[$self->{prereq_pm_detected}]") if $CPAN::DEBUG;
+    CPAN->debug("ID[$self->{ID}]prereq_pm_detected[$self->{prereq_pm_detected}]") if $CPAN::DEBUG;
     return $self->{prereq_pm} if $self->{prereq_pm_detected};
     return unless $self->{writemakefile}  # no need to have succeeded
                                           # but we must have run it
@@ -7516,13 +7677,17 @@ sub prereq_pm {
 
                 #  Regexp modified by A.Speer to remember actual version of file
                 #  PREREQ_PM hash key wants, then add to
-                while ( $p =~ m/(?:\s)([\w\:]+)=>q\[(.*?)\],?/g ){
+                while ( $p =~ m/(?:\s)([\w\:]+)=>(q\[.*?\]|undef),?/g ){
                     # In case a prereq is mentioned twice, complain.
                     if ( defined $req->{$1} ) {
                         warn "Warning: PREREQ_PM mentions $1 more than once, ".
                             "last mention wins";
                     }
-                    $req->{$1} = $2;
+                    my($m,$n) = ($1,$2);
+                    if ($n =~ /^q\[(.*?)\]$/) {
+                        $n = $1;
+                    }
+                    $req->{$m} = $n;
                 }
                 last;
             }
@@ -7597,11 +7762,17 @@ sub test {
     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") {
-            return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
-        }
-    }
+
+#    if (my @prereq = $self->unsat_prereq){
+#        if ( $CPAN::DEBUG ) {
+#            require Data::Dumper;
+#            CPAN->debug(sprintf "unsat_prereq[%s]", Data::Dumper::Dumper(\@prereq));
+#        }
+#        unless ($prereq[0][0] eq "perl") {
+#            return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
+#        }
+#    }
+
   EXCUSE: {
        my @e;
         unless (exists $self->{make} or exists $self->{later}) {
@@ -7617,8 +7788,11 @@ sub test {
             ) and push @e, "Can't test without successful make";
 
         $self->{badtestcnt} ||= 0;
-        $self->{badtestcnt} > 0 and
+        if ($self->{badtestcnt} > 0) {
+            require Data::Dumper;
+            CPAN->debug(sprintf "NOREPEAT[%s]", Data::Dumper::Dumper($self)) if $CPAN::DEBUG;
             push @e, "Won't repeat unsuccessful test during this command";
+        }
 
         exists $self->{later} and length($self->{later}) and
             push @e, $self->{later};
@@ -7672,6 +7846,11 @@ sub test {
     } else {
         $system = join " ", $self->_make_command(), "test";
     }
+    my $make_test_arg = $self->make_x_arg("test");
+    $system = sprintf("%s%s",
+                      $system,
+                      $make_test_arg ? " $make_test_arg" : "",
+                     );
     my($tests_ok);
     my %env;
     while (my($k,$v) = each %ENV) {
@@ -7750,7 +7929,7 @@ sub test {
 
             # local $CPAN::DEBUG = 16; # Distribution
             for my $m (keys %{$self->{sponsored_mods}}) {
-                my $m_obj = CPAN::Shell->expand("Module",$m);
+                my $m_obj = CPAN::Shell->expand("Module",$m) or next;
                 # XXX we need available_version which reflects
                 # $ENV{PERL5LIB} so that already tested but not yet
                 # installed modules are counted.
@@ -7917,7 +8096,10 @@ sub install {
     if (my $goto = $self->prefs->{goto}) {
         return $self->goto($goto);
     }
-    $self->test;
+    $DB::single=1;
+    unless ($self->{badtestcnt}) {
+        $self->test;
+    }
     if ($CPAN::Signal){
       delete $self->{force_update};
       return;
@@ -8333,8 +8515,9 @@ sub color_cmd_tmps {
     # to recurse into its prereq_pms, a bundle needs to recurse into its modules
 
     return if exists $self->{incommandcolor}
+        && $color==1
         && $self->{incommandcolor}==$color;
-    if ($depth>=100){
+    if ($depth>=$CPAN::MAX_RECURSION){
         $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
     }
     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
@@ -8522,62 +8705,6 @@ Going to $meth that.
        my $obj = $CPAN::META->instance($type,$s);
         $obj->{reqtype} = $self->{reqtype};
        $obj->$meth();
-        if ($obj->isa('CPAN::Bundle')
-            &&
-            exists $obj->{install_failed}
-            &&
-            ref($obj->{install_failed}) eq "HASH"
-           ) {
-          for (keys %{$obj->{install_failed}}) {
-            $self->{install_failed}{$_} = undef; # propagate faiure up
-                                                 # to me in a
-                                                 # recursive call
-            $fail{$s} = 1; # the bundle itself may have succeeded but
-                           # not all children
-          }
-        } else {
-          my $success;
-          $success = $obj->can("uptodate") ? $obj->uptodate : 0;
-          $success ||= $obj->{install} && $obj->{install} eq "YES";
-          if ($success) {
-            delete $self->{install_failed}{$s};
-          } else {
-            $fail{$s} = 1;
-          }
-        }
-    }
-
-    # recap with less noise
-    if ( $meth eq "install" ) {
-       if (%fail) {
-           require Text::Wrap;
-           my $raw = sprintf(qq{Bundle summary:
-The following items in bundle %s had installation problems:},
-                             $self->id
-                            );
-           $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
-           $CPAN::Frontend->myprint("\n");
-           my $paragraph = "";
-            my %reported;
-           for $s ($self->contains) {
-              if ($fail{$s}){
-               $paragraph .= "$s ";
-                $self->{install_failed}{$s} = undef;
-                $reported{$s} = undef;
-              }
-           }
-            my $report_propagated;
-            for $s (sort keys %{$self->{install_failed}}) {
-              next if exists $reported{$s};
-              $paragraph .= "and the following items had problems
-during recursive bundle calls: " unless $report_propagated++;
-              $paragraph .= "$s ";
-            }
-           $CPAN::Frontend->myprint(Text::Wrap::fill("  ","  ",$paragraph));
-           $CPAN::Frontend->myprint("\n");
-       } else {
-           $self->{install} = 'YES';
-       }
     }
 }
 
@@ -8675,9 +8802,41 @@ sub color_cmd_tmps {
     # a module needs to recurse to its cpan_file
 
     return if exists $self->{incommandcolor}
+        && $color==1
         && $self->{incommandcolor}==$color;
-    return if $depth>=1 && $self->uptodate;
-    if ($depth>=100){
+    return if $color==0 && !$self->{incommandcolor};
+    if ($color>=1) {
+        if ( $self->uptodate ) {
+            $self->{incommandcolor} = $color;
+            return;
+        } elsif (my $have_version = $self->available_version) {
+            # maybe what we have is good enough
+            if (@$ancestors) {
+                my $who_asked_for_me = $ancestors->[-1];
+                my $obj = CPAN::Shell->expandany($who_asked_for_me);
+                if (0) {
+                } elsif ($obj->isa("CPAN::Bundle")) {
+                    # bundles cannot specify a minimum version
+                    return;
+                } elsif ($obj->isa("CPAN::Distribution")) {
+                    if (my $prereq_pm = $obj->prereq_pm) {
+                        for my $k (keys %$prereq_pm) {
+                            if (my $want_version = $prereq_pm->{$k}{$self->id}) {
+                                if (CPAN::Version->vcmp($have_version,$want_version) >= 0) {
+                                    $self->{incommandcolor} = $color;
+                                    return;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    } else {
+        $self->{incommandcolor} = $color; # set me before recursion,
+                                          # so we can break it
+    }
+    if ($depth>=$CPAN::MAX_RECURSION){
         $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
     }
     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
@@ -8735,17 +8894,22 @@ sub as_glimpse {
 sub dslip_status {
     my($self) = @_;
     my($stat);
+    # development status
     @{$stat->{D}}{qw,i c a b R M S,}     = qw,idea
                                               pre-alpha alpha beta released
                                               mature standard,;
+    # support level
     @{$stat->{S}}{qw,m d u n a,}         = qw,mailing-list
                                               developer comp.lang.perl.*
                                               none abandoned,;
+    # language
     @{$stat->{L}}{qw,p c + o h,}         = qw,perl C C++ other hybrid,;
+    # interface
     @{$stat->{I}}{qw,f r O p h n,}       = qw,functions
                                               references+ties
                                               object-oriented pragma
                                               hybrid none,;
+    # public licence
     @{$stat->{P}}{qw,p g l b a o d r n,} = qw,Standard-Perl
                                               GPL LGPL
                                               BSD Artistic
@@ -9213,11 +9377,13 @@ CPAN - query, download and build perl modules from CPAN sites
 
 Interactive mode:
 
-  perl -MCPAN -e shell;
+  perl -MCPAN -e shell
 
-Batch mode:
+--or--
 
-  use CPAN;
+  cpan
+
+Basic commands:
 
   # Modules:
 
@@ -9246,14 +9412,13 @@ Batch mode:
 
 =head1 DESCRIPTION
 
-The CPAN module is designed to automate the make and install of perl
-modules and extensions. It includes some primitive searching
-capabilities and knows how to use Net::FTP or LWP (or some external
-download clients) to fetch the raw data from the net.
+The CPAN module automates or at least simplifies the make and install
+of perl modules and extensions. It includes some primitive searching
+capabilities and knows how to use Net::FTP or LWP or some external
+download clients to fetch the distributions from the net.
 
-Distributions are fetched from one or more of the mirrored CPAN
-(Comprehensive Perl Archive Network) sites and unpacked in a dedicated
-directory.
+These are fetched from one or more of the mirrored CPAN (Comprehensive
+Perl Archive Network) sites and unpacked in a dedicated directory.
 
 The CPAN module also supports the concept of named and versioned
 I<bundles> of modules. Bundles simplify the handling of sets of
@@ -9274,11 +9439,15 @@ The interactive mode is entered by running
 
     perl -MCPAN -e shell
 
-which puts you into a readline interface. If Term::ReadKey and either
-Term::ReadLine::Perl or Term::ReadLine::Gnu are installed it supports
-both history and command completion.
+or
+
+    cpan
+
+which puts you into a readline interface. If C<Term::ReadKey> and
+either C<Term::ReadLine::Perl> or C<Term::ReadLine::Gnu> are installed
+it supports both history and command completion.
 
-Once you are on the command line, type 'h' to get a one page help
+Once you are on the command line, type C<h> to get a one page help
 screen and the rest should be self-explanatory.
 
 The function call C<shell> takes two optional arguments, one is the
@@ -9308,7 +9477,7 @@ displayed with the rather verbose method C<as_string>, but if we find
 more than one, we display each object with the terse method
 C<as_glimpse>.
 
-=item get, make, test, install, clean  modules or distributions
+=item C<get>, C<make>, C<test>, C<install>, C<clean> modules or distributions
 
 These commands take any number of arguments and investigate what is
 necessary to perform the action. If the argument is a distribution
@@ -9341,7 +9510,7 @@ has been run successfully before. Same for install runs.
 The C<force> pragma may precede another command (currently: C<get>,
 C<make>, C<test>, or C<install>) and executes the command from scratch
 and tries to continue in case of some errors. See the section below on
-The C<force> and the C<fforce> pragma.
+the C<force> and the C<fforce> pragma.
 
 The C<notest> pragma may be used to skip the test part in the build
 process.
@@ -9356,7 +9525,7 @@ A C<clean> command results in a
 
 being executed within the distribution file's working directory.
 
-=item readme, perldoc, look module or distribution
+=item C<readme>, C<perldoc>, C<look> module or distribution
 
 C<readme> displays the README file of the associated distribution.
 C<Look> gets and untars (if not yet done) the distribution file,
@@ -9364,9 +9533,9 @@ changes to the appropriate directory and opens a subshell process in
 that directory. C<perldoc> displays the pod documentation of the
 module in html or plain text format.
 
-=item ls author
+=item C<ls> author
 
-=item ls globbing_expression
+=item C<ls> globbing_expression
 
 The first form lists all distribution files in and below an author's
 CPAN directory as they are stored in the CHECKUMS files distributed on
@@ -9386,7 +9555,7 @@ Note that globbing only lists directories explicitly asked for, for
 example FOO/* will not list FOO/bar/Acme-Sthg-n.nn.tar.gz. This may be
 regarded as a bug and may be changed in future versions.
 
-=item failed
+=item C<failed>
 
 The C<failed> command reports all distributions that failed on one of
 C<make>, C<test> or C<install> for some reason in the currently
@@ -9585,1016 +9754,1335 @@ module or not.
 The typical usage case is for private modules or working copies of
 projects from remote repositories on the local disk.
 
-=head1 PROGRAMMER'S INTERFACE
-
-If you do not enter the shell, the available shell commands are both
-available as methods (C<CPAN::Shell-E<gt>install(...)>) and as
-functions in the calling package (C<install(...)>).  Before calling low-level
-commands it makes sense to initialize components of CPAN you need, e.g.:
-
-  CPAN::HandleConfig->load;
-  CPAN::Shell::setup_output;
-  CPAN::Index->reload;
-
-High-level commands do such initializations automatically.
-
-There's currently only one class that has a stable interface -
-CPAN::Shell. All commands that are available in the CPAN shell are
-methods of the class CPAN::Shell. Each of the commands that produce
-listings of modules (C<r>, C<autobundle>, C<u>) also return a list of
-the IDs of all modules within the list.
-
-=over 2
-
-=item expand($type,@things)
-
-The IDs of all objects available within a program are strings that can
-be expanded to the corresponding real objects with the
-C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
-list of CPAN::Module objects according to the C<@things> arguments
-given. In scalar context it only returns the first element of the
-list.
-
-=item expandany(@things)
-
-Like expand, but returns objects of the appropriate type, i.e.
-CPAN::Bundle objects for bundles, CPAN::Module objects for modules and
-CPAN::Distribution objects for distributions. Note: it does not expand
-to CPAN::Author objects.
-
-=item Programming Examples
-
-This enables the programmer to do operations that combine
-functionalities that are available in the shell.
-
-    # install everything that is outdated on my disk:
-    perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'
-
-    # install my favorite programs if necessary:
-    for $mod (qw(Net::FTP Digest::SHA Data::Dumper)){
-        CPAN::Shell->install($mod);
-    }
-
-    # list all modules on my disk that have no VERSION number
-    for $mod (CPAN::Shell->expand("Module","/./")){
-       next unless $mod->inst_file;
-        # MakeMaker convention for undefined $VERSION:
-       next unless $mod->inst_version eq "undef";
-       print "No VERSION in ", $mod->id, "\n";
-    }
+=head1 CONFIGURATION
 
-    # find out which distribution on CPAN contains a module:
-    print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file
+When the CPAN module is used for the first time, a configuration
+dialog tries to determine a couple of site specific options. The
+result of the dialog is stored in a hash reference C< $CPAN::Config >
+in a file CPAN/Config.pm.
 
-Or if you want to write a cronjob to watch The CPAN, you could list
-all modules that need updating. First a quick and dirty way:
+The default values defined in the CPAN/Config.pm file can be
+overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
+best placed in $HOME/.cpan/CPAN/MyConfig.pm, because $HOME/.cpan is
+added to the search path of the CPAN module before the use() or
+require() statements. The mkmyconfig command writes this file for you.
 
-    perl -e 'use CPAN; CPAN::Shell->r;'
+The C<o conf> command has various bells and whistles:
 
-If you don't want to get any output in the case that all modules are
-up to date, you can parse the output of above command for the regular
-expression //modules are up to date// and decide to mail the output
-only if it doesn't match. Ick?
+=over
 
-If you prefer to do it more in a programmer style in one single
-process, maybe something like this suits you better:
+=item completion support
 
-  # list all modules on my disk that have newer versions on CPAN
-  for $mod (CPAN::Shell->expand("Module","/./")){
-    next unless $mod->inst_file;
-    next if $mod->uptodate;
-    printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
-        $mod->id, $mod->inst_version, $mod->cpan_version;
-  }
+If you have a ReadLine module installed, you can hit TAB at any point
+of the commandline and C<o conf> will offer you completion for the
+built-in subcommands and/or config variable names.
 
-If that gives you too much output every day, you maybe only want to
-watch for three modules. You can write
+=item displaying some help: o conf help
 
-  for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")){
+Displays a short help
 
-as the first line instead. Or you can combine some of the above
-tricks:
+=item displaying current values: o conf [KEY]
 
-  # watch only for a new mod_perl module
-  $mod = CPAN::Shell->expand("Module","mod_perl");
-  exit if $mod->uptodate;
-  # new mod_perl arrived, let me know all update recommendations
-  CPAN::Shell->r;
+Displays the current value(s) for this config variable. Without KEY
+displays all subcommands and config variables.
 
-=back
+Example:
 
-=head2 Methods in the other Classes
+  o conf shell
 
-=over 4
+=item changing of scalar values: o conf KEY VALUE
 
-=item CPAN::Author::as_glimpse()
+Sets the config variable KEY to VALUE. The empty string can be
+specified as usual in shells, with C<''> or C<"">
 
-Returns a one-line description of the author
+Example:
 
-=item CPAN::Author::as_string()
+  o conf wget /usr/bin/wget
 
-Returns a multi-line description of the author
+=item changing of list values: o conf KEY SHIFT|UNSHIFT|PUSH|POP|SPLICE|LIST
 
-=item CPAN::Author::email()
+If a config variable name ends with C<list>, it is a list. C<o conf
+KEY shift> removes the first element of the list, C<o conf KEY pop>
+removes the last element of the list. C<o conf KEYS unshift LIST>
+prepends a list of values to the list, C<o conf KEYS push LIST>
+appends a list of valued to the list.
 
-Returns the author's email address
+Likewise, C<o conf KEY splice LIST> passes the LIST to the according
+splice command.
 
-=item CPAN::Author::fullname()
+Finally, any other list of arguments is taken as a new list value for
+the KEY variable discarding the previous value.
 
-Returns the author's name
+Examples:
 
-=item CPAN::Author::name()
+  o conf urllist unshift http://cpan.dev.local/CPAN
+  o conf urllist splice 3 1
+  o conf urllist http://cpan1.local http://cpan2.local ftp://ftp.perl.org
 
-An alias for fullname
+=item reverting to saved: o conf defaults
 
-=item CPAN::Bundle::as_glimpse()
+Reverts all config variables to the state in the saved config file.
 
-Returns a one-line description of the bundle
+=item saving the config: o conf commit
 
-=item CPAN::Bundle::as_string()
+Saves all config variables to the current config file (CPAN/Config.pm
+or CPAN/MyConfig.pm that was loaded at start).
 
-Returns a multi-line description of the bundle
+=back
 
-=item CPAN::Bundle::clean()
+The configuration dialog can be started any time later again by
+issuing the command C< o conf init > in the CPAN shell. A subset of
+the configuration dialog can be run by issuing C<o conf init WORD>
+where WORD is any valid config variable or a regular expression.
 
-Recursively runs the C<clean> method on all items contained in the bundle.
+=head2 Config Variables
 
-=item CPAN::Bundle::contains()
+Currently the following keys in the hash reference $CPAN::Config are
+defined:
 
-Returns a list of objects' IDs contained in a bundle. The associated
-objects may be bundles, modules or distributions.
+  applypatch         path to external prg
+  auto_commit        commit all changes to config variables to disk
+  build_cache        size of cache for directories to build modules
+  build_dir          locally accessible directory to build modules
+  build_dir_reuse    boolean if distros in build_dir are persistent
+  build_requires_install_policy
+                     to install or not to install when a module is
+                     only needed for building. yes|no|ask/yes|ask/no
+  bzip2              path to external prg
+  cache_metadata     use serializer to cache metadata
+  commands_quote     prefered character to use for quoting external
+                     commands when running them. Defaults to double
+                     quote on Windows, single tick everywhere else;
+                     can be set to space to disable quoting
+  check_sigs         if signatures should be verified
+  colorize_debug     Term::ANSIColor attributes for debugging output
+  colorize_output    boolean if Term::ANSIColor should colorize output
+  colorize_print     Term::ANSIColor attributes for normal output
+  colorize_warn      Term::ANSIColor attributes for warnings
+  commandnumber_in_prompt
+                     boolean if you want to see current command number
+  cpan_home          local directory reserved for this package
+  curl               path to external prg
+  dontload_hash      DEPRECATED
+  dontload_list      arrayref: modules in the list will not be
+                     loaded by the CPAN::has_inst() routine
+  ftp                path to external prg
+  ftp_passive        if set, the envariable FTP_PASSIVE is set for downloads
+  ftp_proxy          proxy host for ftp requests
+  getcwd             see below
+  gpg                path to external prg
+  gzip              location of external program gzip
+  histfile           file to maintain history between sessions
+  histsize           maximum number of lines to keep in histfile
+  http_proxy         proxy host for http requests
+  inactivity_timeout breaks interactive Makefile.PLs or Build.PLs
+                     after this many seconds inactivity. Set to 0 to
+                     never break.
+  index_expire       after this many days refetch index files
+  inhibit_startup_message
+                     if true, does not print the startup message
+  keep_source_where  directory in which to keep the source (if we do)
+  lynx               path to external prg
+  make               location of external make program
+  make_arg          arguments that should always be passed to 'make'
+  make_install_make_command
+                     the make command for running 'make install', for
+                     example 'sudo make'
+  make_install_arg   same as make_arg for 'make install'
+  makepl_arg        arguments passed to 'perl Makefile.PL'
+  mbuild_arg        arguments passed to './Build'
+  mbuild_install_arg arguments passed to './Build install'
+  mbuild_install_build_command
+                     command to use instead of './Build' when we are
+                     in the install stage, for example 'sudo ./Build'
+  mbuildpl_arg       arguments passed to 'perl Build.PL'
+  ncftp              path to external prg
+  ncftpget           path to external prg
+  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
+                     comes with only one of the two, that one will be
+                     used in any case
+  prerequisites_policy
+                     what to do if you are missing module prerequisites
+                     ('follow' automatically, 'ask' me, or 'ignore')
+  prefs_dir          local directory to store per-distro build options
+  proxy_user         username for accessing an authenticating proxy
+  proxy_pass         password for accessing an authenticating proxy
+  randomize_urllist  add some randomness to the sequence of the urllist
+  scan_cache        controls scanning of cache ('atstart' or 'never')
+  shell              your favorite shell
+  show_upload_date   boolean if commands should try to determine upload date
+  tar                location of external program tar
+  term_is_latin      if true internal UTF-8 is translated to ISO-8859-1
+                     (and nonsense for characters outside latin range)
+  term_ornaments     boolean to turn ReadLine ornamenting on/off
+  test_report        email test reports (if CPAN::Reporter is installed)
+  unzip              location of external program unzip
+  urllist           arrayref to nearby CPAN sites (or equivalent locations)
+  use_sqlite         use CPAN::SQLite for metadata storage (fast and lean)
+  username           your username if you CPAN server wants one
+  wait_list          arrayref to a wait server to try (See CPAN::WAIT)
+  wget               path to external prg
+  yaml_module        which module to use to read/write YAML files
 
-=item CPAN::Bundle::force($method,@args)
+You can set and query each of these options interactively in the cpan
+shell with the C<o conf> or the C<o conf init> command as specified below.
 
-Forces CPAN to perform a task that it normally would have refused to
-do. Force takes as arguments a method name to be called and any number
-of additional arguments that should be passed to the called method.
-The internals of the object get the needed changes so that CPAN.pm
-does not refuse to take the action. The C<force> is passed recursively
-to all contained objects. See also the section above on the C<force>
-and the C<fforce> pragma.
+=over 2
 
-=item CPAN::Bundle::get()
+=item C<o conf E<lt>scalar optionE<gt>>
 
-Recursively runs the C<get> method on all items contained in the bundle
+prints the current value of the I<scalar option>
 
-=item CPAN::Bundle::inst_file()
+=item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>
 
-Returns the highest installed version of the bundle in either @INC or
-C<$CPAN::Config->{cpan_home}>. Note that this is different from
-CPAN::Module::inst_file.
+Sets the value of the I<scalar option> to I<value>
 
-=item CPAN::Bundle::inst_version()
+=item C<o conf E<lt>list optionE<gt>>
 
-Like CPAN::Bundle::inst_file, but returns the $VERSION
+prints the current value of the I<list option> in MakeMaker's
+neatvalue format.
 
-=item CPAN::Bundle::uptodate()
+=item C<o conf E<lt>list optionE<gt> [shift|pop]>
 
-Returns 1 if the bundle itself and all its members are uptodate.
+shifts or pops the array in the I<list option> variable
 
-=item CPAN::Bundle::install()
+=item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>
 
-Recursively runs the C<install> method on all items contained in the bundle
+works like the corresponding perl commands.
 
-=item CPAN::Bundle::make()
+=item interactive editing: o conf init [MATCH|LIST]
 
-Recursively runs the C<make> method on all items contained in the bundle
+Runs an interactive configuration dialog for matching variables.
+Without argument runs the dialog over all supported config variables.
+To specify a MATCH the argument must be enclosed by slashes.
 
-=item CPAN::Bundle::readme()
+Examples:
 
-Recursively runs the C<readme> method on all items contained in the bundle
+  o conf init ftp_passive ftp_proxy
+  o conf init /color/
 
-=item CPAN::Bundle::test()
+Note: this method of setting config variables often provides more
+explanation about the functioning of a variable than the manpage.
 
-Recursively runs the C<test> method on all items contained in the bundle
+=back
 
-=item CPAN::Distribution::as_glimpse()
+=head2 CPAN::anycwd($path): Note on config variable getcwd
 
-Returns a one-line description of the distribution
+CPAN.pm changes the current working directory often and needs to
+determine its own current working directory. Per default it uses
+Cwd::cwd but if this doesn't work on your system for some reason,
+alternatives can be configured according to the following table:
 
-=item CPAN::Distribution::as_string()
+=over 4
 
-Returns a multi-line description of the distribution
+=item cwd
 
-=item CPAN::Distribution::author
+Calls Cwd::cwd
 
-Returns the CPAN::Author object of the maintainer who uploaded this
-distribution
+=item getcwd
 
-=item CPAN::Distribution::clean()
+Calls Cwd::getcwd
 
-Changes to the directory where the distribution has been unpacked and
-runs C<make clean> there.
+=item fastcwd
 
-=item CPAN::Distribution::containsmods()
+Calls Cwd::fastcwd
 
-Returns a list of IDs of modules contained in a distribution file.
-Only works for distributions listed in the 02packages.details.txt.gz
-file. This typically means that only the most recent version of a
-distribution is covered.
+=item backtickcwd
 
-=item CPAN::Distribution::cvs_import()
+Calls the external command cwd.
 
-Changes to the directory where the distribution has been unpacked and
-runs something like
+=back
 
-    cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version
+=head2 Note on the format of the urllist parameter
 
-there.
+urllist parameters are URLs according to RFC 1738. We do a little
+guessing if your URL is not compliant, but if you have problems with
+C<file> URLs, please try the correct format. Either:
 
-=item CPAN::Distribution::dir()
+    file://localhost/whatever/ftp/pub/CPAN/
 
-Returns the directory into which this distribution has been unpacked.
+or
 
-=item CPAN::Distribution::force($method,@args)
+    file:///home/ftp/pub/CPAN/
 
-Forces CPAN to perform a task that it normally would have refused to
-do. Force takes as arguments a method name to be called and any number
-of additional arguments that should be passed to the called method.
-The internals of the object get the needed changes so that CPAN.pm
-does not refuse to take the action. See also the section above on the
-C<force> and the C<fforce> pragma.
+=head2 The urllist parameter has CD-ROM support
 
-=item CPAN::Distribution::get()
+The C<urllist> parameter of the configuration table contains a list of
+URLs that are to be used for downloading. If the list contains any
+C<file> URLs, CPAN always tries to get files from there first. This
+feature is disabled for index files. So the recommendation for the
+owner of a CD-ROM with CPAN contents is: include your local, possibly
+outdated CD-ROM as a C<file> URL at the end of urllist, e.g.
 
-Downloads the distribution from CPAN and unpacks it. Does nothing if
-the distribution has already been downloaded and unpacked within the
-current session.
+  o conf urllist push file://localhost/CDROM/CPAN
 
-=item CPAN::Distribution::install()
+CPAN.pm will then fetch the index files from one of the CPAN sites
+that come at the beginning of urllist. It will later check for each
+module if there is a local copy of the most recent version.
 
-Changes to the directory where the distribution has been unpacked and
-runs the external command C<make install> there. If C<make> has not
-yet been run, it will be run first. A C<make test> will be issued in
-any case and if this fails, the install will be canceled. The
-cancellation can be avoided by letting C<force> run the C<install> for
-you.
+Another peculiarity of urllist is that the site that we could
+successfully fetch the last file from automatically gets a preference
+token and is tried as the first site for the next request. So if you
+add a new site at runtime it may happen that the previously preferred
+site will be tried another time. This means that if you want to disallow
+a site for the next transfer, it must be explicitly removed from
+urllist.
 
-This install method has only the power to install the distribution if
-there are no dependencies in the way. To install an object and all of
-its dependencies, use CPAN::Shell->install.
+=head2 Maintaining the urllist parameter
 
-Note that install() gives no meaningful return value. See uptodate().
+If you have YAML.pm (or some other YAML module configured in
+C<yaml_module>) installed, CPAN.pm collects a few statistical data
+about recent downloads. You can view the statistics with the C<hosts>
+command or inspect them directly by looking into the C<FTPstats.yml>
+file in your C<cpan_home> directory.
 
-=item CPAN::Distribution::isa_perl()
+To get some interesting statistics it is recommended to set the
+C<randomize_urllist> parameter that introduces some amount of
+randomness into the URL selection.
 
-Returns 1 if this distribution file seems to be a perl distribution.
-Normally this is derived from the file name only, but the index from
-CPAN can contain a hint to achieve a return value of true for other
-filenames too.
+=head2 The C<requires> and C<build_requires> dependency declarations
 
-=item CPAN::Distribution::look()
+Since CPAN.pm version 1.88_51 modules declared as C<build_requires> by
+a distribution are treated differently depending on the config
+variable C<build_requires_install_policy>. By setting
+C<build_requires_install_policy> to C<no> such a module is not being
+installed. It is only built and tested and then kept in the list of
+tested but uninstalled modules. As such it is available during the
+build of the dependent module by integrating the path to the
+C<blib/arch> and C<blib/lib> directories in the environment variable
+PERL5LIB. If C<build_requires_install_policy> is set ti C<yes>, then
+both modules declared as C<requires> and those declared as
+C<build_requires> are treated alike. By setting to C<ask/yes> or
+C<ask/no>, CPAN.pm asks the user and sets the default accordingly.
 
-Changes to the directory where the distribution has been unpacked and
-opens a subshell there. Exiting the subshell returns.
+=head2 Configuration for individual distributions (I<Distroprefs>)
 
-=item CPAN::Distribution::make()
+(B<Note:> This feature has been introduced in CPAN.pm 1.8854 and is
+still considered beta quality)
 
-First runs the C<get> method to make sure the distribution is
-downloaded and unpacked. Changes to the directory where the
-distribution has been unpacked and runs the external commands C<perl
-Makefile.PL> or C<perl Build.PL> and C<make> there.
+Distributions on the CPAN usually behave according to what we call the
+CPAN mantra. Or since the event of Module::Build we should talk about
+two mantras:
 
-=item CPAN::Distribution::perldoc()
+    perl Makefile.PL     perl Build.PL
+    make                 ./Build
+    make test            ./Build test
+    make install         ./Build install
 
-Downloads the pod documentation of the file associated with a
-distribution (in html format) and runs it through the external
-command lynx specified in C<$CPAN::Config->{lynx}>. If lynx
-isn't available, it converts it to plain text with external
-command html2text and runs it through the pager specified
-in C<$CPAN::Config->{pager}>
+But some modules cannot be built with this mantra. They try to get
+some extra data from the user via the environment, extra arguments or
+interactively thus disturbing the installation of large bundles like
+Phalanx100 or modules with many dependencies like Plagger.
 
-=item CPAN::Distribution::prefs()
+The distroprefs system of C<CPAN.pm> addresses this problem by
+allowing the user to specify extra informations and recipes in YAML
+files to either
 
-Returns the hash reference from the first matching YAML file that the
-user has deposited in the C<prefs_dir/> directory. The first
-succeeding match wins. The files in the C<prefs_dir/> are processed
-alphabetically and the canonical distroname (e.g.
-AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
-stored in the $root->{match}{distribution} attribute value.
-Additionally all module names contained in a distribution are matched
-agains the regular expressions in the $root->{match}{module} attribute
-value. The two match values are ANDed together. Each of the two
-attributes are optional.
-
-=item CPAN::Distribution::prereq_pm()
-
-Returns the hash reference that has been announced by a distribution
-as the merge of the C<requires> element and the C<build_requires>
-element of the META.yml or the C<PREREQ_PM> hash in the
-C<Makefile.PL>. Note: works only after an attempt has been made to
-C<make> the distribution. Returns undef otherwise.
+=over
 
-=item CPAN::Distribution::readme()
+=item
 
-Downloads the README file associated with a distribution and runs it
-through the pager specified in C<$CPAN::Config->{pager}>.
+pass additional arguments to one of the four commands,
 
-=item CPAN::Distribution::read_yaml()
+=item
 
-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. Also returns undef if the content of META.yml
-is dynamic.
+set environment variables
 
-=item CPAN::Distribution::test()
+=item
 
-Changes to the directory where the distribution has been unpacked and
-runs C<make test> there.
+instantiate an Expect object that reads from the console, waits for
+some regular expressions and enters some answers
 
-=item CPAN::Distribution::uptodate()
+=item
 
-Returns 1 if all the modules contained in the distribution are
-uptodate. Relies on containsmods.
+temporarily override assorted C<CPAN.pm> configuration variables
 
-=item CPAN::Index::force_reload()
+=item
 
-Forces a reload of all indices.
+disable the installation of an object altogether
 
-=item CPAN::Index::reload()
+=back
 
-Reloads all indices if they have not been read for more than
-C<$CPAN::Config->{index_expire}> days.
+See the YAML and Data::Dumper files that come with the C<CPAN.pm>
+distribution in the C<distroprefs/> directory for examples.
 
-=item CPAN::InfoObj::dump()
+=head2 Filenames
 
-CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
-inherit this method. It prints the data structure associated with an
-object. Useful for debugging. Note: the data structure is considered
-internal and thus subject to change without notice.
+The YAML files themselves must have the C<.yml> extension, all other
+files are ignored (for two exceptions see I<Fallback Data::Dumper and
+Storable> below). The containing directory can be specified in
+C<CPAN.pm> in the C<prefs_dir> config variable. Try C<o conf init
+prefs_dir> in the CPAN shell to set and activate the distroprefs
+system.
 
-=item CPAN::Module::as_glimpse()
+Every YAML file may contain arbitrary documents according to the YAML
+specification and every single document is treated as an entity that
+can specify the treatment of a single distribution.
 
-Returns a one-line description of the module in four columns: The
-first column contains the word C<Module>, the second column consists
-of one character: an equals sign if this module is already installed
-and uptodate, a less-than sign if this module is installed but can be
-upgraded, and a space if the module is not installed. The third column
-is the name of the module and the fourth column gives maintainer or
-distribution information.
+The names of the files can be picked freely, C<CPAN.pm> always reads
+all files (in alphabetical order) and takes the key C<match> (see
+below in I<Language Specs>) as a hashref containing match criteria
+that determine if the current distribution matches the YAML document
+or not.
 
-=item CPAN::Module::as_string()
+=head2 Fallback Data::Dumper and Storable
 
-Returns a multi-line description of the module
+If neither your configured C<yaml_module> nor YAML.pm is installed
+CPAN.pm falls back to using Data::Dumper and Storable and looks for
+files with the extensions C<.dd> or C<.st> in the C<prefs_dir>
+directory. These files are expected to contain one or more hashrefs.
+For Data::Dumper generated files, this is expected to be done with by
+defining C<$VAR1>, C<$VAR2>, etc. The YAML shell would produce these
+with the command
 
-=item CPAN::Module::clean()
+    ysh < somefile.yml > somefile.dd
 
-Runs a clean on the distribution associated with this module.
+For Storable files the rule is that they must be constructed such that
+C<Storable::retrieve(file)> returns an array reference and the array
+elements represent one distropref object each. The conversion from
+YAML would look like so:
 
-=item CPAN::Module::cpan_file()
+    perl -MYAML=LoadFile -MStorable=nstore -e '
+        @y=LoadFile(shift);
+        nstore(\@y, shift)' somefile.yml somefile.st
 
-Returns the filename on CPAN that is associated with the module.
+In bootstrapping situations it is usually sufficient to translate only
+a few YAML files to Data::Dumper for the crucial modules like
+C<YAML::Syck>, C<YAML.pm> and C<Expect.pm>. If you prefer Storable
+over Data::Dumper, remember to pull out a Storable version that writes
+an older format than all the other Storable versions that will need to
+read them.
 
-=item CPAN::Module::cpan_version()
+=head2 Blueprint
 
-Returns the latest version of this module available on CPAN.
+The following example contains all supported keywords and structures
+with the exception of C<eexpect> which can be used instead of
+C<expect>.
 
-=item CPAN::Module::cvs_import()
+  ---
+  comment: "Demo"
+  match:
+    module: "Dancing::Queen"
+    distribution: "^CHACHACHA/Dancing-"
+    perl: "/usr/local/cariba-perl/bin/perl"
+  disabled: 1
+  cpanconfig:
+    make: gmake
+  pl:
+    args:
+      - "--somearg=specialcase"
 
-Runs a cvs_import on the distribution associated with this module.
+    env: {}
 
-=item CPAN::Module::description()
+    expect:
+      - "Which is your favorite fruit"
+      - "apple\n"
 
-Returns a 44 character description of this module. Only available for
-modules listed in The Module List (CPAN/modules/00modlist.long.html
-or 00modlist.long.txt.gz)
+  make:
+    args:
+      - all
+      - extra-all
 
-=item CPAN::Module::distribution()
+    env: {}
 
-Returns the CPAN::Distribution object that contains the current
-version of this module.
+    expect: []
 
-=item CPAN::Module::dslip_status()
+    commendline: "echo SKIPPING make"
 
-Returns a hash reference. The keys of the hash are the letters C<D>,
-C<S>, C<L>, C<I>, and <P>, for development status, support level,
-language, interface and public licence respectively. The data for the
-DSLIP status are collected by pause.perl.org when authors register
-their namespaces. The values of the 5 hash elements are one-character
-words whose meaning is described in the table below. There are also 5
-hash elements C<DV>, C<SV>, C<LV>, C<IV>, and <PV> that carry a more
-verbose value of the 5 status variables.
+  test:
+    args: []
 
-Where the 'DSLIP' characters have the following meanings:
+    env: {}
 
-  D - Development Stage  (Note: *NO IMPLIED TIMESCALES*):
-    i   - Idea, listed to gain consensus or as a placeholder
-    c   - under construction but pre-alpha (not yet released)
-    a/b - Alpha/Beta testing
-    R   - Released
-    M   - Mature (no rigorous definition)
-    S   - Standard, supplied with Perl 5
+    expect: []
 
-  S - Support Level:
-    m   - Mailing-list
-    d   - Developer
-    u   - Usenet newsgroup comp.lang.perl.modules
-    n   - None known, try comp.lang.perl.modules
-    a   - abandoned; volunteers welcome to take over maintainance
+  install:
+    args: []
 
-  L - Language Used:
-    p   - Perl-only, no compiler needed, should be platform independent
-    c   - C and perl, a C compiler will be needed
-    h   - Hybrid, written in perl with optional C code, no compiler needed
-    +   - C++ and perl, a C++ compiler will be needed
-    o   - perl and another language other than C or C++
+    env:
+      WANT_TO_INSTALL: YES
 
-  I - Interface Style
-    f   - plain Functions, no references used
-    h   - hybrid, object and function interfaces available
-    n   - no interface at all (huh?)
-    r   - some use of unblessed References or ties
-    O   - Object oriented using blessed references and/or inheritance
+    expect:
+      - "Do you really want to install"
+      - "y\n"
 
-  P - Public License
-    p   - Standard-Perl: user may choose between GPL and Artistic
-    g   - GPL: GNU General Public License
-    l   - LGPL: "GNU Lesser General Public License" (previously known as
-          "GNU Library General Public License")
-    b   - BSD: The BSD License
-    a   - Artistic license alone
-    o   - open source: appoved by www.opensource.org
-    d   - allows distribution without restrictions
-    r   - restricted distribtion
-    n   - no license at all
+  patches:
+    - "ABCDE/Fedcba-3.14-ABCDE-01.patch"
 
-=item CPAN::Module::force($method,@args)
 
-Forces CPAN to perform a task that it normally would have refused to
-do. Force takes as arguments a method name to be called and any number
-of additional arguments that should be passed to the called method.
-The internals of the object get the needed changes so that CPAN.pm
-does not refuse to take the action. See also the section above on the
-C<force> and the C<fforce> pragma.
+=head2 Language Specs
 
-=item CPAN::Module::get()
+Every YAML document represents a single hash reference. The valid keys
+in this hash are as follows:
 
-Runs a get on the distribution associated with this module.
+=over
 
-=item CPAN::Module::inst_file()
+=item comment [scalar]
 
-Returns the filename of the module found in @INC. The first file found
-is reported just like perl itself stops searching @INC when it finds a
-module.
+A comment
 
-=item CPAN::Module::available_file()
+=item cpanconfig [hash]
 
-Returns the filename of the module found in PERL5LIB or @INC. The
-first file found is reported. The advantage of this method over
-C<inst_file> is that modules that have been tested but not yet
-installed are included because PERL5LIB keeps track of tested modules.
+Temporarily override assorted C<CPAN.pm> configuration variables.
 
-=item CPAN::Module::inst_version()
+Supported are: C<build_requires_install_policy>, C<check_sigs>,
+C<make>, C<make_install_make_command>, C<prefer_installer>,
+C<test_report>. Please report as a bug when you need another one
+supported.
 
-Returns the version number of the installed module in readable format.
+=item disabled [boolean]
 
-=item CPAN::Module::available_version()
+Specifies that this distribution shall not be processed at all.
 
-Returns the version number of the available module in readable format.
+=item goto [string]
 
-=item CPAN::Module::install()
+The canonical name of a delegate distribution that shall be installed
+instead. Useful when a new version, although it tests OK itself,
+breaks something else or a developer release or a fork is already
+uploaded that is better than the last released version.
 
-Runs an C<install> on the distribution associated with this module.
+=item install [hash]
 
-=item CPAN::Module::look()
+Processing instructions for the C<make install> or C<./Build install>
+phase of the CPAN mantra. See below under I<Processiong Instructions>.
 
-Changes to the directory where the distribution associated with this
-module has been unpacked and opens a subshell there. Exiting the
-subshell returns.
+=item make [hash]
 
-=item CPAN::Module::make()
+Processing instructions for the C<make> or C<./Build> phase of the
+CPAN mantra. See below under I<Processiong Instructions>.
 
-Runs a C<make> on the distribution associated with this module.
+=item match [hash]
 
-=item CPAN::Module::manpage_headline()
+A hashref with one or more of the keys C<distribution>, C<modules>, or
+C<perl> that specify if a document is targeted at a specific CPAN
+distribution.
 
-If module is installed, peeks into the module's manpage, reads the
-headline and returns it. Moreover, if the module has been downloaded
-within this session, does the equivalent on the downloaded module even
-if it is not installed.
+The corresponding values are interpreted as regular expressions. The
+C<distribution> related one will be matched against the canonical
+distribution name, e.g. "AUTHOR/Foo-Bar-3.14.tar.gz".
 
-=item CPAN::Module::perldoc()
+The C<module> related one will be matched against I<all> modules
+contained in the distribution until one module matches.
 
-Runs a C<perldoc> on this module.
+The C<perl> related one will be matched against C<$^X>.
 
-=item CPAN::Module::readme()
+If more than one restriction of C<module>, C<distribution>, and
+C<perl> is specified, the results of the separately computed match
+values must all match. If this is the case then the hashref
+represented by the YAML document is returned as the preference
+structure for the current distribution.
 
-Runs a C<readme> on the distribution associated with this module.
+=item patches [array]
 
-=item CPAN::Module::test()
+An array of patches on CPAN or on the local disk to be applied in
+order via the external patch program. If the value for the C<-p>
+parameter is C<0> or C<1> is determined by reading the patch
+beforehand.
 
-Runs a C<test> on the distribution associated with this module.
+Note: if the C<applypatch> program is installed and C<CPAN::Config>
+knows about it B<and> a patch is written by the C<makepatch> program,
+then C<CPAN.pm> lets C<applypatch> apply the patch. Both C<makepatch>
+and C<applypatch> are available from CPAN in the C<JV/makepatch-*>
+distribution.
 
-=item CPAN::Module::uptodate()
+=item pl [hash]
 
-Returns 1 if the module is installed and up-to-date.
+Processing instructions for the C<perl Makefile.PL> or C<perl
+Build.PL> phase of the CPAN mantra. See below under I<Processiong
+Instructions>.
 
-=item CPAN::Module::userid()
+=item test [hash]
 
-Returns the author's ID of the module.
+Processing instructions for the C<make test> or C<./Build test> phase
+of the CPAN mantra. See below under I<Processiong Instructions>.
 
 =back
 
-=head2 Cache Manager
-
-Currently the cache manager only keeps track of the build directory
-($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
-deletes complete directories below C<build_dir> as soon as the size of
-all directories there gets bigger than $CPAN::Config->{build_cache}
-(in MB). The contents of this cache may be used for later
-re-installations that you intend to do manually, but will never be
-trusted by CPAN itself. This is due to the fact that the user might
-use these directories for building modules on different architectures.
-
-There is another directory ($CPAN::Config->{keep_source_where}) where
-the original distribution files are kept. This directory is not
-covered by the cache manager and must be controlled by the user. If
-you choose to have the same directory as build_dir and as
-keep_source_where directory, then your sources will be deleted with
-the same fifo mechanism.
+=head2 Processing Instructions
 
-=head2 Bundles
+=over
 
-A bundle is just a perl module in the namespace Bundle:: that does not
-define any functions or methods. It usually only contains documentation.
+=item args [array]
 
-It starts like a perl module with a package declaration and a $VERSION
-variable. After that the pod section looks like any other pod with the
-only difference being that I<one special pod section> exists starting with
-(verbatim):
+Arguments to be added to the command line
 
-       =head1 CONTENTS
+=item commandline
 
-In this pod section each line obeys the format
+A full commandline that will be executed as it stands by a system
+call. During the execution the environment variable PERL will is set
+to $^X. If C<commandline> is specified, the content of C<args> is not
+used.
 
-        Module_Name [Version_String] [- optional text]
+=item eexpect [hash]
 
-The only required part is the first field, the name of a module
-(e.g. Foo::Bar, ie. I<not> the name of the distribution file). The rest
-of the line is optional. The comment part is delimited by a dash just
-as in the man page header.
+Extended C<expect>. This is a hash reference with three allowed keys,
+C<mode>, C<timeout>, and C<talk>.
 
-The distribution of a bundle should follow the same convention as
-other distributions.
+C<mode> may have the values C<deterministic> for the case where all
+questions come in the order written down and C<anyorder> for the case
+where the questions may come in any order. The default mode is
+C<deterministic>.
 
-Bundles are treated specially in the CPAN package. If you say 'install
-Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
-the modules in the CONTENTS section of the pod. You can install your
-own Bundles locally by placing a conformant Bundle file somewhere into
-your @INC path. The autobundle() command which is available in the
-shell interface does that for you by including all currently installed
-modules in a snapshot bundle file.
+C<timeout> denotes a timeout in seconds. Floating point timeouts are
+OK. In the case of a C<mode=deterministic> the timeout denotes the
+timeout per question, in the case of C<mode=anyorder> it denotes the
+timeout per byte received from the stream or questions.
 
-=head1 PREREQUISITES
+C<talk> is a reference to an array that contains alternating questions
+and answers. Questions are regular expressions and answers are literal
+strings. The Expect module will then watch the stream coming from the
+execution of the external program (C<perl Makefile.PL>, C<perl
+Build.PL>, C<make>, etc.).
 
-If you have a local mirror of CPAN and can access all files with
-"file:" URLs, then you only need a perl better than perl5.003 to run
-this module. Otherwise Net::FTP is strongly recommended. LWP may be
-required for non-UNIX systems or if your nearest CPAN site is
-associated with a URL that is not C<ftp:>.
+In the case of C<mode=deterministic> the CPAN.pm will inject the
+according answer as soon as the stream matches the regular expression.
+In the case of C<mode=anyorder> the CPAN.pm will answer a question as
+soon as the timeout is reached for the next byte in the input stream.
+In the latter case it removes the according question/answer pair from
+the array, so if you want to answer the question C<Do you really want
+to do that> several times, then it must be included in the array at
+least as often as you want this answer to be given.
 
-If you have neither Net::FTP nor LWP, there is a fallback mechanism
-implemented for an external ftp command or for an external lynx
-command.
+=item env [hash]
 
-=head1 UTILITIES
+Environment variables to be set during the command
 
-=head2 Finding packages and VERSION
+=item expect [array]
 
-This module presumes that all packages on CPAN
+C<< expect: <array> >> is a short notation for
 
-=over 2
+  eexpect:
+    mode: deterministic
+    timeout: 15
+    talk: <array>
 
-=item *
+=back
 
-declare their $VERSION variable in an easy to parse manner. This
-prerequisite can hardly be relaxed because it consumes far too much
-memory to load all packages into the running program just to determine
-the $VERSION variable. Currently all programs that are dealing with
-version use something like this
+=head2 Schema verification with C<Kwalify>
 
-    perl -MExtUtils::MakeMaker -le \
-        'print MM->parse_version(shift)' filename
+If you have the C<Kwalify> module installed (which is part of the
+Bundle::CPANxxl), then all your distroprefs files are checked for
+syntactical correctness.
 
-If you are author of a package and wonder if your $VERSION can be
-parsed, please try the above method.
+=head2 Example Distroprefs Files
 
-=item *
+C<CPAN.pm> comes with a collection of example YAML files. Note that these
+are really just examples and should not be used without care because
+they cannot fit everybody's purpose. After all the authors of the
+packages that ask questions had a need to ask, so you should watch
+their questions and adjust the examples to your environment and your
+needs. You have beend warned:-)
 
-come as compressed or gzipped tarfiles or as zip files and contain a
-C<Makefile.PL> or C<Build.PL> (well, we try to handle a bit more, but
-without much enthusiasm).
+=head1 PROGRAMMER'S INTERFACE
 
-=back
+If you do not enter the shell, the available shell commands are both
+available as methods (C<CPAN::Shell-E<gt>install(...)>) and as
+functions in the calling package (C<install(...)>).  Before calling low-level
+commands it makes sense to initialize components of CPAN you need, e.g.:
 
-=head2 Debugging
+  CPAN::HandleConfig->load;
+  CPAN::Shell::setup_output;
+  CPAN::Index->reload;
 
-The debugging of this module is a bit complex, because we have
-interferences of the software producing the indices on CPAN, of the
-mirroring process on CPAN, of packaging, of configuration, of
-synchronicity, and of bugs within CPAN.pm.
+High-level commands do such initializations automatically.
 
-For debugging the code of CPAN.pm itself in interactive mode some more
-or less useful debugging aid can be turned on for most packages within
-CPAN.pm with one of
+There's currently only one class that has a stable interface -
+CPAN::Shell. All commands that are available in the CPAN shell are
+methods of the class CPAN::Shell. Each of the commands that produce
+listings of modules (C<r>, C<autobundle>, C<u>) also return a list of
+the IDs of all modules within the list.
 
 =over 2
 
-=item o debug package...
-
-sets debug mode for packages.
-
-=item o debug -package...
+=item expand($type,@things)
 
-unsets debug mode for packages.
+The IDs of all objects available within a program are strings that can
+be expanded to the corresponding real objects with the
+C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
+list of CPAN::Module objects according to the C<@things> arguments
+given. In scalar context it only returns the first element of the
+list.
 
-=item o debug all
+=item expandany(@things)
 
-turns debugging on for all packages.
+Like expand, but returns objects of the appropriate type, i.e.
+CPAN::Bundle objects for bundles, CPAN::Module objects for modules and
+CPAN::Distribution objects for distributions. Note: it does not expand
+to CPAN::Author objects.
 
-=item o debug number
+=item Programming Examples
+
+This enables the programmer to do operations that combine
+functionalities that are available in the shell.
+
+    # install everything that is outdated on my disk:
+    perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'
+
+    # install my favorite programs if necessary:
+    for $mod (qw(Net::FTP Digest::SHA Data::Dumper)){
+        CPAN::Shell->install($mod);
+    }
+
+    # list all modules on my disk that have no VERSION number
+    for $mod (CPAN::Shell->expand("Module","/./")){
+       next unless $mod->inst_file;
+        # MakeMaker convention for undefined $VERSION:
+       next unless $mod->inst_version eq "undef";
+       print "No VERSION in ", $mod->id, "\n";
+    }
+
+    # find out which distribution on CPAN contains a module:
+    print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file
+
+Or if you want to write a cronjob to watch The CPAN, you could list
+all modules that need updating. First a quick and dirty way:
+
+    perl -e 'use CPAN; CPAN::Shell->r;'
+
+If you don't want to get any output in the case that all modules are
+up to date, you can parse the output of above command for the regular
+expression //modules are up to date// and decide to mail the output
+only if it doesn't match. Ick?
+
+If you prefer to do it more in a programmer style in one single
+process, maybe something like this suits you better:
+
+  # list all modules on my disk that have newer versions on CPAN
+  for $mod (CPAN::Shell->expand("Module","/./")){
+    next unless $mod->inst_file;
+    next if $mod->uptodate;
+    printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
+        $mod->id, $mod->inst_version, $mod->cpan_version;
+  }
+
+If that gives you too much output every day, you maybe only want to
+watch for three modules. You can write
+
+  for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")){
+
+as the first line instead. Or you can combine some of the above
+tricks:
+
+  # watch only for a new mod_perl module
+  $mod = CPAN::Shell->expand("Module","mod_perl");
+  exit if $mod->uptodate;
+  # new mod_perl arrived, let me know all update recommendations
+  CPAN::Shell->r;
 
 =back
 
-which sets the debugging packages directly. Note that C<o debug 0>
-turns debugging off.
+=head2 Methods in the other Classes
 
-What seems quite a successful strategy is the combination of C<reload
-cpan> and the debugging switches. Add a new debug statement while
-running in the shell and then issue a C<reload cpan> and see the new
-debugging messages immediately without losing the current context.
+=over 4
 
-C<o debug> without an argument lists the valid package names and the
-current set of packages in debugging mode. C<o debug> has built-in
-completion support.
+=item CPAN::Author::as_glimpse()
 
-For debugging of CPAN data there is the C<dump> command which takes
-the same arguments as make/test/install and outputs each object's
-Data::Dumper dump. If an argument looks like a perl variable and
-contains one of C<$>, C<@> or C<%>, it is eval()ed and fed to
-Data::Dumper directly.
+Returns a one-line description of the author
 
-=head2 Floppy, Zip, Offline Mode
+=item CPAN::Author::as_string()
 
-CPAN.pm works nicely without network too. If you maintain machines
-that are not networked at all, you should consider working with file:
-URLs. Of course, you have to collect your modules somewhere first. So
-you might use CPAN.pm to put together all you need on a networked
-machine. Then copy the $CPAN::Config->{keep_source_where} (but not
-$CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
-of a personal CPAN. CPAN.pm on the non-networked machines works nicely
-with this floppy. See also below the paragraph about CD-ROM support.
+Returns a multi-line description of the author
 
-=head2 Basic Utilities for Programmers
+=item CPAN::Author::email()
 
-=over 2
+Returns the author's email address
 
-=item has_inst($module)
+=item CPAN::Author::fullname()
 
-Returns true if the module is installed. Used to load all modules into
-the running CPAN.pm which are considered optional. The config variable
-C<dontload_list> can be used to intercept the C<has_inst()> call such
-that an optional module is not loaded despite being available. For
-example the following command will prevent that C<YAML.pm> is being
-loaded:
+Returns the author's name
 
-    cpan> o conf dontload_list push YAML
+=item CPAN::Author::name()
 
-See the source for details.
+An alias for fullname
 
-=item has_usable($module)
+=item CPAN::Bundle::as_glimpse()
 
-Returns true if the module is installed and is in a usable state. Only
-useful for a handful of modules that are used internally. See the
-source for details.
+Returns a one-line description of the bundle
 
-=item instance($module)
+=item CPAN::Bundle::as_string()
 
-The constructor for all the singletons used to represent modules,
-distributions, authors and bundles. If the object already exists, this
-method returns the object, otherwise it calls the constructor.
+Returns a multi-line description of the bundle
 
-=back
+=item CPAN::Bundle::clean()
 
-=head1 CONFIGURATION
+Recursively runs the C<clean> method on all items contained in the bundle.
 
-When the CPAN module is used for the first time, a configuration
-dialog tries to determine a couple of site specific options. The
-result of the dialog is stored in a hash reference C< $CPAN::Config >
-in a file CPAN/Config.pm.
+=item CPAN::Bundle::contains()
 
-The default values defined in the CPAN/Config.pm file can be
-overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
-best placed in $HOME/.cpan/CPAN/MyConfig.pm, because $HOME/.cpan is
-added to the search path of the CPAN module before the use() or
-require() statements. The mkmyconfig command writes this file for you.
+Returns a list of objects' IDs contained in a bundle. The associated
+objects may be bundles, modules or distributions.
 
-The C<o conf> command has various bells and whistles:
+=item CPAN::Bundle::force($method,@args)
 
-=over
+Forces CPAN to perform a task that it normally would have refused to
+do. Force takes as arguments a method name to be called and any number
+of additional arguments that should be passed to the called method.
+The internals of the object get the needed changes so that CPAN.pm
+does not refuse to take the action. The C<force> is passed recursively
+to all contained objects. See also the section above on the C<force>
+and the C<fforce> pragma.
 
-=item completion support
+=item CPAN::Bundle::get()
 
-If you have a ReadLine module installed, you can hit TAB at any point
-of the commandline and C<o conf> will offer you completion for the
-built-in subcommands and/or config variable names.
+Recursively runs the C<get> method on all items contained in the bundle
 
-=item displaying some help: o conf help
+=item CPAN::Bundle::inst_file()
 
-Displays a short help
+Returns the highest installed version of the bundle in either @INC or
+C<$CPAN::Config->{cpan_home}>. Note that this is different from
+CPAN::Module::inst_file.
 
-=item displaying current values: o conf [KEY]
+=item CPAN::Bundle::inst_version()
 
-Displays the current value(s) for this config variable. Without KEY
-displays all subcommands and config variables.
+Like CPAN::Bundle::inst_file, but returns the $VERSION
 
-Example:
+=item CPAN::Bundle::uptodate()
 
-  o conf shell
+Returns 1 if the bundle itself and all its members are uptodate.
 
-=item changing of scalar values: o conf KEY VALUE
+=item CPAN::Bundle::install()
 
-Sets the config variable KEY to VALUE. The empty string can be
-specified as usual in shells, with C<''> or C<"">
+Recursively runs the C<install> method on all items contained in the bundle
 
-Example:
+=item CPAN::Bundle::make()
 
-  o conf wget /usr/bin/wget
+Recursively runs the C<make> method on all items contained in the bundle
 
-=item changing of list values: o conf KEY SHIFT|UNSHIFT|PUSH|POP|SPLICE|LIST
+=item CPAN::Bundle::readme()
 
-If a config variable name ends with C<list>, it is a list. C<o conf
-KEY shift> removes the first element of the list, C<o conf KEY pop>
-removes the last element of the list. C<o conf KEYS unshift LIST>
-prepends a list of values to the list, C<o conf KEYS push LIST>
-appends a list of valued to the list.
+Recursively runs the C<readme> method on all items contained in the bundle
 
-Likewise, C<o conf KEY splice LIST> passes the LIST to the according
-splice command.
+=item CPAN::Bundle::test()
 
-Finally, any other list of arguments is taken as a new list value for
-the KEY variable discarding the previous value.
+Recursively runs the C<test> method on all items contained in the bundle
 
-Examples:
+=item CPAN::Distribution::as_glimpse()
 
-  o conf urllist unshift http://cpan.dev.local/CPAN
-  o conf urllist splice 3 1
-  o conf urllist http://cpan1.local http://cpan2.local ftp://ftp.perl.org
+Returns a one-line description of the distribution
 
-=item interactive editing: o conf init [MATCH|LIST]
+=item CPAN::Distribution::as_string()
 
-Runs an interactive configuration dialog for matching variables.
-Without argument runs the dialog over all supported config variables.
-To specify a MATCH the argument must be enclosed by slashes.
+Returns a multi-line description of the distribution
 
-Examples:
+=item CPAN::Distribution::author
 
-  o conf init ftp_passive ftp_proxy
-  o conf init /color/
+Returns the CPAN::Author object of the maintainer who uploaded this
+distribution
 
-=item reverting to saved: o conf defaults
+=item CPAN::Distribution::clean()
 
-Reverts all config variables to the state in the saved config file.
+Changes to the directory where the distribution has been unpacked and
+runs C<make clean> there.
 
-=item saving the config: o conf commit
+=item CPAN::Distribution::containsmods()
 
-Saves all config variables to the current config file (CPAN/Config.pm
-or CPAN/MyConfig.pm that was loaded at start).
+Returns a list of IDs of modules contained in a distribution file.
+Only works for distributions listed in the 02packages.details.txt.gz
+file. This typically means that only the most recent version of a
+distribution is covered.
 
-=back
+=item CPAN::Distribution::cvs_import()
 
-The configuration dialog can be started any time later again by
-issuing the command C< o conf init > in the CPAN shell. A subset of
-the configuration dialog can be run by issuing C<o conf init WORD>
-where WORD is any valid config variable or a regular expression.
+Changes to the directory where the distribution has been unpacked and
+runs something like
 
-=head2 Config Variables
+    cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version
 
-Currently the following keys in the hash reference $CPAN::Config are
-defined:
+there.
 
-  applypatch         path to external prg
-  auto_commit        commit all changes to config variables to disk
-  build_cache        size of cache for directories to build modules
-  build_dir          locally accessible directory to build modules
-  build_dir_reuse    boolean if distros in build_dir are persistent
-  build_requires_install_policy
-                     to install or not to install: when a module is
-                     only needed for building. yes|no|ask/yes|ask/no
-  bzip2              path to external prg
-  cache_metadata     use serializer to cache metadata
-  commands_quote     prefered character to use for quoting external
-                     commands when running them. Defaults to double
-                     quote on Windows, single tick everywhere else;
-                     can be set to space to disable quoting
-  check_sigs         if signatures should be verified
-  colorize_debug     Term::ANSIColor attributes for debugging output
-  colorize_output    boolean if Term::ANSIColor should colorize output
-  colorize_print     Term::ANSIColor attributes for normal output
-  colorize_warn      Term::ANSIColor attributes for warnings
-  commandnumber_in_prompt
-                     boolean if you want to see current command number
-  cpan_home          local directory reserved for this package
-  curl               path to external prg
-  dontload_hash      DEPRECATED
-  dontload_list      arrayref: modules in the list will not be
-                     loaded by the CPAN::has_inst() routine
-  ftp                path to external prg
-  ftp_passive        if set, the envariable FTP_PASSIVE is set for downloads
-  ftp_proxy          proxy host for ftp requests
-  getcwd             see below
-  gpg                path to external prg
-  gzip              location of external program gzip
-  histfile           file to maintain history between sessions
-  histsize           maximum number of lines to keep in histfile
-  http_proxy         proxy host for http requests
-  inactivity_timeout breaks interactive Makefile.PLs or Build.PLs
-                     after this many seconds inactivity. Set to 0 to
-                     never break.
-  index_expire       after this many days refetch index files
-  inhibit_startup_message
-                     if true, does not print the startup message
-  keep_source_where  directory in which to keep the source (if we do)
-  lynx               path to external prg
-  make               location of external make program
-  make_arg          arguments that should always be passed to 'make'
-  make_install_make_command
-                     the make command for running 'make install', for
-                     example 'sudo make'
-  make_install_arg   same as make_arg for 'make install'
-  makepl_arg        arguments passed to 'perl Makefile.PL'
-  mbuild_arg        arguments passed to './Build'
-  mbuild_install_arg arguments passed to './Build install'
-  mbuild_install_build_command
-                     command to use instead of './Build' when we are
-                     in the install stage, for example 'sudo ./Build'
-  mbuildpl_arg       arguments passed to 'perl Build.PL'
-  ncftp              path to external prg
-  ncftpget           path to external prg
-  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
-                     comes with only one of the two, that one will be
-                     used in any case
-  prerequisites_policy
-                     what to do if you are missing module prerequisites
-                     ('follow' automatically, 'ask' me, or 'ignore')
-  prefs_dir          local directory to store per-distro build options
-  proxy_user         username for accessing an authenticating proxy
-  proxy_pass         password for accessing an authenticating proxy
-  randomize_urllist  add some randomness to the sequence of the urllist
-  scan_cache        controls scanning of cache ('atstart' or 'never')
-  shell              your favorite shell
-  show_upload_date   boolean if commands should try to determine upload date
-  tar                location of external program tar
-  term_is_latin      if true internal UTF-8 is translated to ISO-8859-1
-                     (and nonsense for characters outside latin range)
-  term_ornaments     boolean to turn ReadLine ornamenting on/off
-  test_report        email test reports (if CPAN::Reporter is installed)
-  unzip              location of external program unzip
-  urllist           arrayref to nearby CPAN sites (or equivalent locations)
-  use_sqlite         use CPAN::SQLite for metadata storage (fast and lean)
-  username           your username if you CPAN server wants one
-  wait_list          arrayref to a wait server to try (See CPAN::WAIT)
-  wget               path to external prg
-  yaml_module        which module to use to read/write YAML files
+=item CPAN::Distribution::dir()
+
+Returns the directory into which this distribution has been unpacked.
+
+=item CPAN::Distribution::force($method,@args)
+
+Forces CPAN to perform a task that it normally would have refused to
+do. Force takes as arguments a method name to be called and any number
+of additional arguments that should be passed to the called method.
+The internals of the object get the needed changes so that CPAN.pm
+does not refuse to take the action. See also the section above on the
+C<force> and the C<fforce> pragma.
+
+=item CPAN::Distribution::get()
+
+Downloads the distribution from CPAN and unpacks it. Does nothing if
+the distribution has already been downloaded and unpacked within the
+current session.
+
+=item CPAN::Distribution::install()
+
+Changes to the directory where the distribution has been unpacked and
+runs the external command C<make install> there. If C<make> has not
+yet been run, it will be run first. A C<make test> will be issued in
+any case and if this fails, the install will be canceled. The
+cancellation can be avoided by letting C<force> run the C<install> for
+you.
+
+This install method has only the power to install the distribution if
+there are no dependencies in the way. To install an object and all of
+its dependencies, use CPAN::Shell->install.
+
+Note that install() gives no meaningful return value. See uptodate().
+
+=item CPAN::Distribution::install_tested()
+
+Install all the distributions that have been tested sucessfully but
+not yet installed. See also C<is_tested>.
+
+=item CPAN::Distribution::isa_perl()
+
+Returns 1 if this distribution file seems to be a perl distribution.
+Normally this is derived from the file name only, but the index from
+CPAN can contain a hint to achieve a return value of true for other
+filenames too.
+
+=item CPAN::Distribution::is_tested()
+
+List all the distributions that have been tested sucessfully but not
+yet installed. See also C<install_tested>.
+
+=item CPAN::Distribution::look()
+
+Changes to the directory where the distribution has been unpacked and
+opens a subshell there. Exiting the subshell returns.
+
+=item CPAN::Distribution::make()
+
+First runs the C<get> method to make sure the distribution is
+downloaded and unpacked. Changes to the directory where the
+distribution has been unpacked and runs the external commands C<perl
+Makefile.PL> or C<perl Build.PL> and C<make> there.
+
+=item CPAN::Distribution::perldoc()
+
+Downloads the pod documentation of the file associated with a
+distribution (in html format) and runs it through the external
+command lynx specified in C<$CPAN::Config->{lynx}>. If lynx
+isn't available, it converts it to plain text with external
+command html2text and runs it through the pager specified
+in C<$CPAN::Config->{pager}>
+
+=item CPAN::Distribution::prefs()
+
+Returns the hash reference from the first matching YAML file that the
+user has deposited in the C<prefs_dir/> directory. The first
+succeeding match wins. The files in the C<prefs_dir/> are processed
+alphabetically and the canonical distroname (e.g.
+AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
+stored in the $root->{match}{distribution} attribute value.
+Additionally all module names contained in a distribution are matched
+agains the regular expressions in the $root->{match}{module} attribute
+value. The two match values are ANDed together. Each of the two
+attributes are optional.
+
+=item CPAN::Distribution::prereq_pm()
+
+Returns the hash reference that has been announced by a distribution
+as the the C<requires> and C<build_requires> elements. These can be
+declared either by the C<META.yml> (if authoritative) or can be
+deposited after the run of C<Build.PL> in the file C<./_build/prereqs>
+or after the run of C<Makfile.PL> written as the C<PREREQ_PM> hash in
+a comment in the produced C<Makefile>. I<Note>: this method only works
+after an attempt has been made to C<make> the distribution. Returns
+undef otherwise.
+
+=item CPAN::Distribution::readme()
+
+Downloads the README file associated with a distribution and runs it
+through the pager specified in C<$CPAN::Config->{pager}>.
+
+=item CPAN::Distribution::read_yaml()
+
+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. Also returns undef if the content of META.yml
+is not authoritative. (The rules about what exactly makes the content
+authoritative are still in flux.)
+
+=item CPAN::Distribution::test()
+
+Changes to the directory where the distribution has been unpacked and
+runs C<make test> there.
+
+=item CPAN::Distribution::uptodate()
+
+Returns 1 if all the modules contained in the distribution are
+uptodate. Relies on containsmods.
+
+=item CPAN::Index::force_reload()
+
+Forces a reload of all indices.
+
+=item CPAN::Index::reload()
+
+Reloads all indices if they have not been read for more than
+C<$CPAN::Config->{index_expire}> days.
+
+=item CPAN::InfoObj::dump()
+
+CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
+inherit this method. It prints the data structure associated with an
+object. Useful for debugging. Note: the data structure is considered
+internal and thus subject to change without notice.
+
+=item CPAN::Module::as_glimpse()
+
+Returns a one-line description of the module in four columns: The
+first column contains the word C<Module>, the second column consists
+of one character: an equals sign if this module is already installed
+and uptodate, a less-than sign if this module is installed but can be
+upgraded, and a space if the module is not installed. The third column
+is the name of the module and the fourth column gives maintainer or
+distribution information.
+
+=item CPAN::Module::as_string()
+
+Returns a multi-line description of the module
+
+=item CPAN::Module::clean()
+
+Runs a clean on the distribution associated with this module.
+
+=item CPAN::Module::cpan_file()
+
+Returns the filename on CPAN that is associated with the module.
+
+=item CPAN::Module::cpan_version()
+
+Returns the latest version of this module available on CPAN.
+
+=item CPAN::Module::cvs_import()
+
+Runs a cvs_import on the distribution associated with this module.
+
+=item CPAN::Module::description()
+
+Returns a 44 character description of this module. Only available for
+modules listed in The Module List (CPAN/modules/00modlist.long.html
+or 00modlist.long.txt.gz)
+
+=item CPAN::Module::distribution()
+
+Returns the CPAN::Distribution object that contains the current
+version of this module.
+
+=item CPAN::Module::dslip_status()
+
+Returns a hash reference. The keys of the hash are the letters C<D>,
+C<S>, C<L>, C<I>, and <P>, for development status, support level,
+language, interface and public licence respectively. The data for the
+DSLIP status are collected by pause.perl.org when authors register
+their namespaces. The values of the 5 hash elements are one-character
+words whose meaning is described in the table below. There are also 5
+hash elements C<DV>, C<SV>, C<LV>, C<IV>, and <PV> that carry a more
+verbose value of the 5 status variables.
+
+Where the 'DSLIP' characters have the following meanings:
+
+  D - Development Stage  (Note: *NO IMPLIED TIMESCALES*):
+    i   - Idea, listed to gain consensus or as a placeholder
+    c   - under construction but pre-alpha (not yet released)
+    a/b - Alpha/Beta testing
+    R   - Released
+    M   - Mature (no rigorous definition)
+    S   - Standard, supplied with Perl 5
+
+  S - Support Level:
+    m   - Mailing-list
+    d   - Developer
+    u   - Usenet newsgroup comp.lang.perl.modules
+    n   - None known, try comp.lang.perl.modules
+    a   - abandoned; volunteers welcome to take over maintainance
+
+  L - Language Used:
+    p   - Perl-only, no compiler needed, should be platform independent
+    c   - C and perl, a C compiler will be needed
+    h   - Hybrid, written in perl with optional C code, no compiler needed
+    +   - C++ and perl, a C++ compiler will be needed
+    o   - perl and another language other than C or C++
+
+  I - Interface Style
+    f   - plain Functions, no references used
+    h   - hybrid, object and function interfaces available
+    n   - no interface at all (huh?)
+    r   - some use of unblessed References or ties
+    O   - Object oriented using blessed references and/or inheritance
+
+  P - Public License
+    p   - Standard-Perl: user may choose between GPL and Artistic
+    g   - GPL: GNU General Public License
+    l   - LGPL: "GNU Lesser General Public License" (previously known as
+          "GNU Library General Public License")
+    b   - BSD: The BSD License
+    a   - Artistic license alone
+    o   - open source: appoved by www.opensource.org
+    d   - allows distribution without restrictions
+    r   - restricted distribtion
+    n   - no license at all
+
+=item CPAN::Module::force($method,@args)
+
+Forces CPAN to perform a task that it normally would have refused to
+do. Force takes as arguments a method name to be called and any number
+of additional arguments that should be passed to the called method.
+The internals of the object get the needed changes so that CPAN.pm
+does not refuse to take the action. See also the section above on the
+C<force> and the C<fforce> pragma.
+
+=item CPAN::Module::get()
+
+Runs a get on the distribution associated with this module.
+
+=item CPAN::Module::inst_file()
+
+Returns the filename of the module found in @INC. The first file found
+is reported just like perl itself stops searching @INC when it finds a
+module.
 
-You can set and query each of these options interactively in the cpan
-shell with the command set defined within the C<o conf> command:
+=item CPAN::Module::available_file()
 
-=over 2
+Returns the filename of the module found in PERL5LIB or @INC. The
+first file found is reported. The advantage of this method over
+C<inst_file> is that modules that have been tested but not yet
+installed are included because PERL5LIB keeps track of tested modules.
 
-=item C<o conf E<lt>scalar optionE<gt>>
+=item CPAN::Module::inst_version()
 
-prints the current value of the I<scalar option>
+Returns the version number of the installed module in readable format.
 
-=item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>
+=item CPAN::Module::available_version()
 
-Sets the value of the I<scalar option> to I<value>
+Returns the version number of the available module in readable format.
 
-=item C<o conf E<lt>list optionE<gt>>
+=item CPAN::Module::install()
 
-prints the current value of the I<list option> in MakeMaker's
-neatvalue format.
+Runs an C<install> on the distribution associated with this module.
 
-=item C<o conf E<lt>list optionE<gt> [shift|pop]>
+=item CPAN::Module::look()
 
-shifts or pops the array in the I<list option> variable
+Changes to the directory where the distribution associated with this
+module has been unpacked and opens a subshell there. Exiting the
+subshell returns.
 
-=item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>
+=item CPAN::Module::make()
 
-works like the corresponding perl commands.
+Runs a C<make> on the distribution associated with this module.
+
+=item CPAN::Module::manpage_headline()
+
+If module is installed, peeks into the module's manpage, reads the
+headline and returns it. Moreover, if the module has been downloaded
+within this session, does the equivalent on the downloaded module even
+if it is not installed.
+
+=item CPAN::Module::perldoc()
+
+Runs a C<perldoc> on this module.
+
+=item CPAN::Module::readme()
+
+Runs a C<readme> on the distribution associated with this module.
+
+=item CPAN::Module::test()
+
+Runs a C<test> on the distribution associated with this module.
+
+=item CPAN::Module::uptodate()
+
+Returns 1 if the module is installed and up-to-date.
+
+=item CPAN::Module::userid()
+
+Returns the author's ID of the module.
 
 =back
 
-=head2 CPAN::anycwd($path): Note on config variable getcwd
+=head2 Cache Manager
 
-CPAN.pm changes the current working directory often and needs to
-determine its own current working directory. Per default it uses
-Cwd::cwd but if this doesn't work on your system for some reason,
-alternatives can be configured according to the following table:
+Currently the cache manager only keeps track of the build directory
+($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
+deletes complete directories below C<build_dir> as soon as the size of
+all directories there gets bigger than $CPAN::Config->{build_cache}
+(in MB). The contents of this cache may be used for later
+re-installations that you intend to do manually, but will never be
+trusted by CPAN itself. This is due to the fact that the user might
+use these directories for building modules on different architectures.
+
+There is another directory ($CPAN::Config->{keep_source_where}) where
+the original distribution files are kept. This directory is not
+covered by the cache manager and must be controlled by the user. If
+you choose to have the same directory as build_dir and as
+keep_source_where directory, then your sources will be deleted with
+the same fifo mechanism.
+
+=head2 Bundles
+
+A bundle is just a perl module in the namespace Bundle:: that does not
+define any functions or methods. It usually only contains documentation.
+
+It starts like a perl module with a package declaration and a $VERSION
+variable. After that the pod section looks like any other pod with the
+only difference being that I<one special pod section> exists starting with
+(verbatim):
+
+       =head1 CONTENTS
+
+In this pod section each line obeys the format
+
+        Module_Name [Version_String] [- optional text]
+
+The only required part is the first field, the name of a module
+(e.g. Foo::Bar, ie. I<not> the name of the distribution file). The rest
+of the line is optional. The comment part is delimited by a dash just
+as in the man page header.
+
+The distribution of a bundle should follow the same convention as
+other distributions.
+
+Bundles are treated specially in the CPAN package. If you say 'install
+Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
+the modules in the CONTENTS section of the pod. You can install your
+own Bundles locally by placing a conformant Bundle file somewhere into
+your @INC path. The autobundle() command which is available in the
+shell interface does that for you by including all currently installed
+modules in a snapshot bundle file.
+
+=head1 PREREQUISITES
+
+If you have a local mirror of CPAN and can access all files with
+"file:" URLs, then you only need a perl better than perl5.003 to run
+this module. Otherwise Net::FTP is strongly recommended. LWP may be
+required for non-UNIX systems or if your nearest CPAN site is
+associated with a URL that is not C<ftp:>.
+
+If you have neither Net::FTP nor LWP, there is a fallback mechanism
+implemented for an external ftp command or for an external lynx
+command.
+
+=head1 UTILITIES
+
+=head2 Finding packages and VERSION
+
+This module presumes that all packages on CPAN
 
 =over 2
 
-=item cwd
+=item *
 
-Calls Cwd::cwd
+declare their $VERSION variable in an easy to parse manner. This
+prerequisite can hardly be relaxed because it consumes far too much
+memory to load all packages into the running program just to determine
+the $VERSION variable. Currently all programs that are dealing with
+version use something like this
 
-=item getcwd
+    perl -MExtUtils::MakeMaker -le \
+        'print MM->parse_version(shift)' filename
 
-Calls Cwd::getcwd
+If you are author of a package and wonder if your $VERSION can be
+parsed, please try the above method.
 
-=item fastcwd
+=item *
 
-Calls Cwd::fastcwd
+come as compressed or gzipped tarfiles or as zip files and contain a
+C<Makefile.PL> or C<Build.PL> (well, we try to handle a bit more, but
+without much enthusiasm).
 
-=item backtickcwd
+=back
 
-Calls the external command cwd.
+=head2 Debugging
+
+The debugging of this module is a bit complex, because we have
+interferences of the software producing the indices on CPAN, of the
+mirroring process on CPAN, of packaging, of configuration, of
+synchronicity, and of bugs within CPAN.pm.
+
+For debugging the code of CPAN.pm itself in interactive mode some more
+or less useful debugging aid can be turned on for most packages within
+CPAN.pm with one of
+
+=over 2
+
+=item o debug package...
+
+sets debug mode for packages.
+
+=item o debug -package...
+
+unsets debug mode for packages.
+
+=item o debug all
+
+turns debugging on for all packages.
+
+=item o debug number
 
 =back
 
-=head2 Note on the format of the urllist parameter
+which sets the debugging packages directly. Note that C<o debug 0>
+turns debugging off.
 
-urllist parameters are URLs according to RFC 1738. We do a little
-guessing if your URL is not compliant, but if you have problems with
-C<file> URLs, please try the correct format. Either:
+What seems quite a successful strategy is the combination of C<reload
+cpan> and the debugging switches. Add a new debug statement while
+running in the shell and then issue a C<reload cpan> and see the new
+debugging messages immediately without losing the current context.
 
-    file://localhost/whatever/ftp/pub/CPAN/
+C<o debug> without an argument lists the valid package names and the
+current set of packages in debugging mode. C<o debug> has built-in
+completion support.
 
-or
+For debugging of CPAN data there is the C<dump> command which takes
+the same arguments as make/test/install and outputs each object's
+Data::Dumper dump. If an argument looks like a perl variable and
+contains one of C<$>, C<@> or C<%>, it is eval()ed and fed to
+Data::Dumper directly.
 
-    file:///home/ftp/pub/CPAN/
+=head2 Floppy, Zip, Offline Mode
 
-=head2 urllist parameter has CD-ROM support
+CPAN.pm works nicely without network too. If you maintain machines
+that are not networked at all, you should consider working with file:
+URLs. Of course, you have to collect your modules somewhere first. So
+you might use CPAN.pm to put together all you need on a networked
+machine. Then copy the $CPAN::Config->{keep_source_where} (but not
+$CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
+of a personal CPAN. CPAN.pm on the non-networked machines works nicely
+with this floppy. See also below the paragraph about CD-ROM support.
 
-The C<urllist> parameter of the configuration table contains a list of
-URLs that are to be used for downloading. If the list contains any
-C<file> URLs, CPAN always tries to get files from there first. This
-feature is disabled for index files. So the recommendation for the
-owner of a CD-ROM with CPAN contents is: include your local, possibly
-outdated CD-ROM as a C<file> URL at the end of urllist, e.g.
+=head2 Basic Utilities for Programmers
 
-  o conf urllist push file://localhost/CDROM/CPAN
+=over 2
 
-CPAN.pm will then fetch the index files from one of the CPAN sites
-that come at the beginning of urllist. It will later check for each
-module if there is a local copy of the most recent version.
+=item has_inst($module)
 
-Another peculiarity of urllist is that the site that we could
-successfully fetch the last file from automatically gets a preference
-token and is tried as the first site for the next request. So if you
-add a new site at runtime it may happen that the previously preferred
-site will be tried another time. This means that if you want to disallow
-a site for the next transfer, it must be explicitly removed from
-urllist.
+Returns true if the module is installed. Used to load all modules into
+the running CPAN.pm which are considered optional. The config variable
+C<dontload_list> can be used to intercept the C<has_inst()> call such
+that an optional module is not loaded despite being available. For
+example the following command will prevent that C<YAML.pm> is being
+loaded:
 
-=head2 Maintaining the urllist parameter
+    cpan> o conf dontload_list push YAML
 
-If you have YAML.pm (or some other YAML module configured in
-C<yaml_module>) installed, CPAN.pm collects a few statistical data
-about recent downloads. You can view the statistics with the C<hosts>
-command or inspect them directly by looking into the C<FTPstats.yml>
-file in your C<cpan_home> directory.
+See the source for details.
 
-To get some interesting statistics it is recommended to set the
-C<randomize_urllist> parameter that introduces some amount of
-randomness into the URL selection.
+=item has_usable($module)
+
+Returns true if the module is installed and is in a usable state. Only
+useful for a handful of modules that are used internally. See the
+source for details.
 
-=head2 prefs_dir for avoiding interactive questions (ALPHA)
+=item instance($module)
 
-(B<Note:> This feature has been introduced in CPAN.pm 1.8854 and is
-still considered experimental and may still be changed)
-
-The files in the directory specified in C<prefs_dir> are YAML files
-that specify how CPAN.pm shall treat distributions that deviate from
-the normal non-interactive model of building and installing CPAN
-modules.
-
-Some modules try to get some data from the user interactively thus
-disturbing the installation of large bundles like Phalanx100 or
-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 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 because in flux. Please see the distroprefs
-directory of the CPAN distribution for examples and follow the
-C<00.README> file 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 a package
-used the prompt function provided by ExtUtils::MakeMaker and if the
-defaults are OK for you.
+The constructor for all the singletons used to represent modules,
+distributions, authors and bundles. If the object already exists, this
+method returns the object, otherwise it calls the constructor.
+
+=back
 
 =head1 SECURITY
 
index 8b412ab..06fe076 100644 (file)
@@ -19,7 +19,7 @@ use File::Basename ();
 use File::Path ();
 use File::Spec ();
 use vars qw($VERSION $urllist);
-$VERSION = sprintf "%.6f", substr(q$Rev: 1457 $,4)/1000000 + 5.4;
+$VERSION = sprintf "%.6f", substr(q$Rev: 1536 $,4)/1000000 + 5.4;
 
 =head1 NAME
 
@@ -58,6 +58,13 @@ sub init {
             $CPAN::Frontend->mysleep(2);
         }
     } elsif (0 == length $matcher) {
+    } elsif (0 && $matcher eq "~") { # extremely buggy, but a nice idea
+        my @unconfigured = grep { not exists $CPAN::Config->{$_}
+                                      or not defined $CPAN::Config->{$_}
+                                          or not length $CPAN::Config->{$_}
+                                  } keys %$CPAN::Config;
+        $matcher = "\\b(".join("|", @unconfigured).")\\b";
+        $CPAN::Frontend->mywarn("matcher[$matcher]");
     } else {
         # case WORD... => all arguments must be valid
         for my $arg (@{$args{args}}) {
@@ -318,6 +325,11 @@ Shall we use it as the general CPAN build and cache directory?
     #
     if (!$matcher or "yaml_module" =~ /$matcher/) {
         my_dflt_prompt(yaml_module => "YAML", $matcher);
+        unless ($CPAN::META->has_inst($CPAN::Config->{yaml_module})) {
+            $CPAN::Frontend->mywarn
+                ("Warning (maybe harmless): '$CPAN::Config->{yaml_module}' not installed.\n");
+            $CPAN::Frontend->mysleep(3);
+        }
     }
 
     #
@@ -1489,7 +1501,7 @@ At the time of this writing there are two competing YAML modules,
 YAML.pm and YAML::Syck. The latter is faster but needs a C compiler
 installed on your system. There may be more alternative YAML
 conforming modules but at the time of writing a potential third
-player, YAML::Tiny, is not yet sufficiently similar to the other two.
+player, YAML::Tiny, seemed not powerful enough to work with CPAN.pm.
 
 },
 
index e8859fc..d4495ef 100644 (file)
@@ -2,7 +2,7 @@ package CPAN::HandleConfig;
 use strict;
 use vars qw(%can %keys $VERSION);
 
-$VERSION = sprintf "%.6f", substr(q$Rev: 1467 $,4)/1000000 + 5.4;
+$VERSION = sprintf "%.6f", substr(q$Rev: 1566 $,4)/1000000 + 5.4;
 
 %can = (
         commit   => "Commit changes to disk",
@@ -171,6 +171,7 @@ sub edit {
                     # reset the cached values
                     undef $CPAN::FTP::Thesite;
                     undef $CPAN::FTP::Themethod;
+                    $CPAN::Index::LAST_TIME = 0;
                 } elsif ($o eq "dontload_list") {
                     # empty it, it will be built up again
                     $CPAN::META->{dontload_hash} = {};
@@ -684,7 +685,7 @@ sub prefs_lookup {
 
     use strict;
     use vars qw($AUTOLOAD $VERSION);
-    $VERSION = sprintf "%.2f", substr(q$Rev: 1467 $,4)/100;
+    $VERSION = sprintf "%.2f", substr(q$Rev: 1566 $,4)/100;
 
     # formerly CPAN::HandleConfig was known as CPAN::Config
     sub AUTOLOAD {
index 7cbff38..fa70c68 100644 (file)
@@ -48,7 +48,7 @@ use strict;
 # Hope that makes sense, my head is a bit off:-) -- AK
 
 use vars qw{ @All $VERSION };
-$VERSION = sprintf "%.6f", substr(q$Rev: 979 $,4)/1000000 + 5.4;
+$VERSION = sprintf "%.6f", substr(q$Rev: 1486 $,4)/1000000 + 5.4;
 
 # CPAN::Queue::new ;
 sub new {
@@ -117,13 +117,15 @@ sub jumpqueue {
             # CPAN->debug("i[$i]this[$All[$i]{qmod}]what[$what]") if $CPAN::DEBUG;
             if ($All[$i]{qmod} eq $what){
                 $jumped++;
-                if ($jumped > 100) { # one's OK if e.g. just
-                                     # processing now; more are OK if
-                                     # user typed it several times
+                if ($jumped > 25) { # one's OK if e.g. just processing
+                                    # now; more are OK if user typed
+                                    # it several times
+                    my $sleep = sprintf "%.1f", $jumped/10;
                     $CPAN::Frontend->mywarn(
-qq{Object [$what] queued more than 100 times, ignoring}
+qq{Warning: Object [$what] queued $jumped times, sleeping $sleep secs!\n}
                                 );
-                    next WHAT;
+                    $CPAN::Frontend->mysleep($sleep);
+                    # next WHAT;
                 }
             }
         }
index 071c0b9..e637e3e 100644 (file)
@@ -4,7 +4,7 @@ use strict;
 use vars qw($VERSION @ISA $BUGHUNTING);
 use CPAN::Debug;
 use File::Basename ();
-$VERSION = sprintf "%.6f", substr(q$Rev: 1301 $,4)/1000000 + 5.4;
+$VERSION = sprintf "%.6f", substr(q$Rev: 1525 $,4)/1000000 + 5.4;
 # module is internal to CPAN.pm
 
 @ISA = qw(CPAN::Debug);
@@ -210,7 +210,7 @@ sub untar {
     # should be default until Archive::Tar handles bzip2
     $prefer = 1;
   } elsif (
-           $CPAN::META->has_inst("Archive::Tar")
+           $CPAN::META->has_usable("Archive::Tar")
            &&
            $CPAN::META->has_inst("Compress::Zlib") ) {
     $prefer = 2;
@@ -257,7 +257,7 @@ installed. Can't continue.
       return 1;
     }
   } elsif ($prefer==2) { # 2 => modules
-    unless ($CPAN::META->has_inst("Archive::Tar")) {
+    unless ($CPAN::META->has_usable("Archive::Tar")) {
       $CPAN::Frontend->mydie("Archive::Tar not installed, please install it to continue");
     }
     my $tar = Archive::Tar->new($file,1);