1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $CPAN::VERSION = '1.9204';
5 $CPAN::VERSION = eval $CPAN::VERSION if $CPAN::VERSION =~ /_/;
7 use CPAN::HandleConfig;
12 use CPAN::DeferedCode;
18 use ExtUtils::MakeMaker qw(prompt); # for some unknown reason,
19 # 5.005_04 does not work without
21 use File::Basename ();
29 use Sys::Hostname qw(hostname);
30 use Text::ParseWords ();
35 # we need to run chdir all over and we would get at wrong libraries
38 if (File::Spec->can("rel2abs")) {
40 $inc = File::Spec->rel2abs($inc) unless ref $inc;
46 require Mac::BuildTools if $^O eq 'MacOS';
47 $ENV{PERL5_CPAN_IS_RUNNING}=$$;
48 $ENV{PERL5_CPANPLUS_IS_RUNNING}=$$; # https://rt.cpan.org/Ticket/Display.html?id=23735
50 END { $CPAN::End++; &cleanup; }
53 $CPAN::Frontend ||= "CPAN::Shell";
54 unless (@CPAN::Defaultsites) {
55 @CPAN::Defaultsites = map {
56 CPAN::URL->new(TEXT => $_, FROM => "DEF")
58 "http://www.perl.org/CPAN/",
59 "ftp://ftp.perl.org/pub/CPAN/";
61 # $CPAN::iCwd (i for initial) is going to be initialized during find_perl
62 $CPAN::Perl ||= CPAN::find_perl();
63 $CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
64 $CPAN::Defaultrecent ||= "http://search.cpan.org/uploads.rdf";
65 $CPAN::Defaultrecent ||= "http://cpan.uwinnipeg.ca/htdocs/cpan.xml";
67 # our globals are getting a mess
93 @CPAN::ISA = qw(CPAN::Debug Exporter);
95 # note that these functions live in CPAN::Shell and get executed via
96 # AUTOLOAD when called directly
123 sub soft_chdir_with_alternatives ($);
126 $autoload_recursion ||= 0;
128 #-> sub CPAN::AUTOLOAD ;
130 $autoload_recursion++;
134 warn "Refusing to autoload '$l' while signal pending";
135 $autoload_recursion--;
138 if ($autoload_recursion > 1) {
139 my $fullcommand = join " ", map { "'$_'" } $l, @_;
140 warn "Refusing to autoload $fullcommand in recursion\n";
141 $autoload_recursion--;
145 @export{@EXPORT} = '';
146 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
147 if (exists $export{$l}) {
150 die(qq{Unknown CPAN command "$AUTOLOAD". }.
151 qq{Type ? for help.\n});
153 $autoload_recursion--;
157 #-> sub CPAN::shell ;
160 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
161 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
163 my $oprompt = shift || CPAN::Prompt->new;
164 my $prompt = $oprompt;
165 my $commandline = shift || "";
166 $CPAN::CurrentCommandId ||= 1;
169 unless ($Suppress_readline) {
170 require Term::ReadLine;
173 $term->ReadLine eq "Term::ReadLine::Stub"
175 $term = Term::ReadLine->new('CPAN Monitor');
177 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
178 my $attribs = $term->Attribs;
179 $attribs->{attempted_completion_function} = sub {
180 &CPAN::Complete::gnu_cpl;
183 $readline::rl_completion_function =
184 $readline::rl_completion_function = 'CPAN::Complete::cpl';
186 if (my $histfile = $CPAN::Config->{'histfile'}) {{
187 unless ($term->can("AddHistory")) {
188 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
191 $META->readhist($term,$histfile);
193 for ($CPAN::Config->{term_ornaments}) { # alias
194 local $Term::ReadLine::termcap_nowarn = 1;
195 $term->ornaments($_) if defined;
197 # $term->OUT is autoflushed anyway
198 my $odef = select STDERR;
206 my @cwd = grep { defined $_ and length $_ }
208 File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
209 File::Spec->rootdir();
210 my $try_detect_readline;
211 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
212 unless ($CPAN::Config->{inhibit_startup_message}) {
213 my $rl_avail = $Suppress_readline ? "suppressed" :
214 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
215 "available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
216 $CPAN::Frontend->myprint(
218 cpan shell -- CPAN exploration and modules installation (v%s)
226 my($continuation) = "";
227 my $last_term_ornaments;
228 SHELLCOMMAND: while () {
229 if ($Suppress_readline) {
230 if ($Echo_readline) {
234 last SHELLCOMMAND unless defined ($_ = <> );
235 if ($Echo_readline) {
236 # backdoor: I could not find a way to record sessions
241 last SHELLCOMMAND unless
242 defined ($_ = $term->readline($prompt, $commandline));
244 $_ = "$continuation$_" if $continuation;
246 next SHELLCOMMAND if /^$/;
248 if (/^(?:q(?:uit)?|bye|exit)$/i) {
259 use vars qw($import_done);
260 CPAN->import(':DEFAULT') unless $import_done++;
261 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
268 eval { @line = Text::ParseWords::shellwords($_) };
269 warn($@), next SHELLCOMMAND if $@;
270 warn("Text::Parsewords could not parse the line [$_]"),
271 next SHELLCOMMAND unless @line;
272 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
273 my $command = shift @line;
274 eval { CPAN::Shell->$command(@line) };
280 my $dv = Dumpvalue->new();
281 Carp::cluck(sprintf "Catching error: %s", $dv->stringify($err));
291 # pragmas for classic commands
300 # only commands that tell us something about failed distros
301 CPAN::Shell->failed($CPAN::CurrentCommandId,1);
303 soft_chdir_with_alternatives(\@cwd);
304 $CPAN::Frontend->myprint("\n");
306 $CPAN::CurrentCommandId++;
310 $commandline = ""; # I do want to be able to pass a default to
311 # shell, but on the second command I see no
314 CPAN::Queue->nullify_queue;
315 if ($try_detect_readline) {
316 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
318 $CPAN::META->has_inst("Term::ReadLine::Perl")
320 delete $INC{"Term/ReadLine.pm"};
322 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
323 require Term::ReadLine;
324 $CPAN::Frontend->myprint("\n$redef subroutines in ".
325 "Term::ReadLine redefined\n");
329 if ($term and $term->can("ornaments")) {
330 for ($CPAN::Config->{term_ornaments}) { # alias
332 if (not defined $last_term_ornaments
333 or $_ != $last_term_ornaments
335 local $Term::ReadLine::termcap_nowarn = 1;
336 $term->ornaments($_);
337 $last_term_ornaments = $_;
340 undef $last_term_ornaments;
344 for my $class (qw(Module Distribution)) {
345 # again unsafe meta access?
346 for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
347 next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
348 CPAN->debug("BUG: $class '$dm' was in command state, resetting");
349 delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
353 $GOTOSHELL = 0; # not too often
354 $META->savehist if $CPAN::term && $CPAN::term->can("GetHistory");
359 soft_chdir_with_alternatives(\@cwd);
362 sub soft_chdir_with_alternatives ($) {
365 my $root = File::Spec->rootdir();
366 $CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
367 Trying '$root' as temporary haven.
372 if (chdir $cwd->[0]) {
376 $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
377 Trying to chdir to "$cwd->[1]" instead.
381 $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
389 if ($Config::Config{d_flock}) {
390 return flock $fh, $mode;
391 } elsif (!$Have_warned->{"d_flock"}++) {
392 $CPAN::Frontend->mywarn("Your OS does not support locking; continuing and ignoring all locking issues\n");
393 $CPAN::Frontend->mysleep(5);
400 sub _yaml_module () {
401 my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
403 $yaml_module ne "YAML"
405 !$CPAN::META->has_inst($yaml_module)
407 # $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
408 $yaml_module = "YAML";
410 if ($yaml_module eq "YAML"
412 $CPAN::META->has_inst($yaml_module)
414 $YAML::VERSION < 0.60
416 !$Have_warned->{"YAML"}++
418 $CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
419 "I'll continue but problems are *very* likely to happen.\n"
421 $CPAN::Frontend->mysleep(5);
426 # CPAN::_yaml_loadfile
428 my($self,$local_file) = @_;
429 return +[] unless -s $local_file;
430 my $yaml_module = _yaml_module;
431 if ($CPAN::META->has_inst($yaml_module)) {
432 # temporarly enable yaml code deserialisation
434 # 5.6.2 could not do the local() with the reference
435 local $YAML::LoadCode;
436 local $YAML::Syck::LoadCode;
437 ${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
440 if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
442 eval { @yaml = $code->($local_file); };
444 # this shall not be done by the frontend
445 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
448 } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
450 open FH, $local_file or die "Could not open '$local_file': $!";
454 eval { @yaml = $code->($ystream); };
456 # this shall not be done by the frontend
457 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
462 # this shall not be done by the frontend
463 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
468 # CPAN::_yaml_dumpfile
470 my($self,$local_file,@what) = @_;
471 my $yaml_module = _yaml_module;
472 if ($CPAN::META->has_inst($yaml_module)) {
474 if (UNIVERSAL::isa($local_file, "FileHandle")) {
475 $code = UNIVERSAL::can($yaml_module, "Dump");
476 eval { print $local_file $code->(@what) };
477 } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
478 eval { $code->($local_file,@what); };
479 } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
481 open FH, ">$local_file" or die "Could not open '$local_file': $!";
482 print FH $code->(@what);
485 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
488 if (UNIVERSAL::isa($local_file, "FileHandle")) {
489 # I think this case does not justify a warning at all
491 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
496 sub _init_sqlite () {
497 unless ($CPAN::META->has_inst("CPAN::SQLite")) {
498 $CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
499 unless $Have_warned->{"CPAN::SQLite"}++;
502 require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
503 $CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
507 my $negative_cache = {};
508 sub _sqlite_running {
509 if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
510 # need to cache the result, otherwise too slow
511 return $negative_cache->{fact};
513 $negative_cache = {}; # reset
515 my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
516 return $ret if $ret; # fast anyway
517 $negative_cache->{time} = time;
518 return $negative_cache->{fact} = $ret;
522 package CPAN::CacheMgr;
524 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
529 use Fcntl qw(:flock);
530 use vars qw($connect_to_internet_ok $Ua $Thesite $ThesiteURL $Themethod);
531 @CPAN::FTP::ISA = qw(CPAN::Debug);
533 package CPAN::LWP::UserAgent;
535 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
536 # we delay requiring LWP::UserAgent and setting up inheritance until we need it
538 package CPAN::Complete;
540 @CPAN::Complete::ISA = qw(CPAN::Debug);
541 # Q: where is the "How do I add a new command" HOWTO?
542 # A: svn diff -r 1048:1049 where andk added the report command
543 @CPAN::Complete::COMMANDS = sort qw(
544 ? ! a b d h i m o q r u
579 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $HAVE_REANIMATED);
580 @CPAN::Index::ISA = qw(CPAN::Debug);
583 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
586 package CPAN::InfoObj;
588 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
590 package CPAN::Author;
592 @CPAN::Author::ISA = qw(CPAN::InfoObj);
594 package CPAN::Distribution;
596 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
598 package CPAN::Bundle;
600 @CPAN::Bundle::ISA = qw(CPAN::Module);
602 package CPAN::Module;
604 @CPAN::Module::ISA = qw(CPAN::InfoObj);
606 package CPAN::Exception::RecursiveDependency;
608 use overload '""' => "as_string";
610 # a module sees its distribution (no version)
611 # a distribution sees its prereqs (which are module names) (usually with versions)
612 # a bundle sees its module names and/or its distributions (no version)
617 my (@deps,%seen,$loop_starts_with);
618 DCHAIN: for my $dep (@$deps) {
619 push @deps, {name => $dep, display_as => $dep};
621 $loop_starts_with = $dep;
626 for my $i (0..$#deps) {
627 my $x = $deps[$i]{name};
628 $in_loop ||= $x eq $loop_starts_with;
629 my $xo = CPAN::Shell->expandany($x) or next;
630 if ($xo->isa("CPAN::Module")) {
631 my $have = $xo->inst_version || "N/A";
632 my($want,$d,$want_type);
633 if ($i>0 and $d = $deps[$i-1]{name}) {
634 my $do = CPAN::Shell->expandany($d);
635 $want = $do->{prereq_pm}{requires}{$x};
637 $want_type = "requires: ";
639 $want = $do->{prereq_pm}{build_requires}{$x};
641 $want_type = "build_requires: ";
643 $want_type = "unknown status";
648 $want = $xo->cpan_version;
649 $want_type = "want: ";
651 $deps[$i]{have} = $have;
652 $deps[$i]{want_type} = $want_type;
653 $deps[$i]{want} = $want;
654 $deps[$i]{display_as} = "$x (have: $have; $want_type$want)";
655 } elsif ($xo->isa("CPAN::Distribution")) {
656 $deps[$i]{display_as} = $xo->pretty_id;
658 $xo->{make} = CPAN::Distrostatus->new("NO cannot resolve circular dependency");
660 $xo->{make} = CPAN::Distrostatus->new("NO one dependency ($loop_starts_with) is a circular dependency");
662 $xo->store_persistent_state; # otherwise I will not reach
663 # all involved parties for
667 bless { deps => \@deps }, $class;
672 my $ret = "\nRecursive dependency detected:\n ";
673 $ret .= join("\n => ", map {$_->{display_as}} @{$self->{deps}});
674 $ret .= ".\nCannot resolve.\n";
678 package CPAN::Exception::yaml_not_installed;
680 use overload '""' => "as_string";
683 my($class,$module,$file,$during) = @_;
684 bless { module => $module, file => $file, during => $during }, $class;
689 "'$self->{module}' not installed, cannot $self->{during} '$self->{file}'\n";
692 package CPAN::Exception::yaml_process_error;
694 use overload '""' => "as_string";
697 my($class,$module,$file,$during,$error) = @_;
698 bless { module => $module,
701 error => $error }, $class;
706 if ($self->{during}) {
708 if ($self->{module}) {
709 if ($self->{error}) {
710 return "Alert: While trying to '$self->{during}' YAML file\n".
711 " '$self->{file}'\n".
712 "with '$self->{module}' the following error was encountered:\n".
715 return "Alert: While trying to '$self->{during}' YAML file\n".
716 " '$self->{file}'\n".
717 "with '$self->{module}' some unknown error was encountered\n";
720 return "Alert: While trying to '$self->{during}' YAML file\n".
721 " '$self->{file}'\n".
722 "some unknown error was encountered\n";
725 return "Alert: While trying to '$self->{during}' some YAML file\n".
726 "some unknown error was encountered\n";
729 return "Alert: unknown error encountered\n";
733 package CPAN::Prompt; use overload '""' => "as_string";
734 use vars qw($prompt);
736 $CPAN::CurrentCommandId ||= 0;
742 unless ($CPAN::META->{LOCK}) {
743 $word = "nolock_cpan";
745 if ($CPAN::Config->{commandnumber_in_prompt}) {
746 sprintf "$word\[%d]> ", $CPAN::CurrentCommandId;
752 package CPAN::URL; use overload '""' => "as_string", fallback => 1;
753 # accessors: TEXT(the url string), FROM(DEF=>defaultlist,USER=>urllist),
754 # planned are things like age or quality
756 my($class,%args) = @_;
768 $self->{TEXT} = $set;
773 package CPAN::Distrostatus;
774 use overload '""' => "as_string",
777 my($class,$arg) = @_;
780 FAILED => substr($arg,0,2) eq "NO",
781 COMMANDID => $CPAN::CurrentCommandId,
785 sub commandid { shift->{COMMANDID} }
786 sub failed { shift->{FAILED} }
790 $self->{TEXT} = $set;
810 @CPAN::Shell::ISA = qw(CPAN::Debug);
811 $COLOR_REGISTERED ||= 0;
814 '!' => "eval the rest of the line as perl",
816 autobundle => "wtite inventory into a bundle file",
817 b => "info about bundle",
819 clean => "clean up a distribution's build directory",
821 d => "info about a distribution",
824 failed => "list all failed actions within current session",
825 fforce => "redo a command from scratch",
826 force => "redo a command",
828 help => "overview over commands; 'help ...' explains specific commands",
829 hosts => "statistics about recently used hosts",
830 i => "info about authors/bundles/distributions/modules",
831 install => "install a distribution",
832 install_tested => "install all distributions tested OK",
833 is_tested => "list all distributions tested OK",
834 look => "open a subshell in a distribution's directory",
835 ls => "list distributions according to a glob",
836 m => "info about a module",
837 make => "make/build a distribution",
838 mkmyconfig => "write current config into a CPAN/MyConfig.pm file",
839 notest => "run a (usually install) command but leave out the test phase",
840 o => "'o conf ...' for config stuff; 'o debug ...' for debugging",
841 perldoc => "try to get a manpage for a module",
843 quit => "leave the cpan shell",
844 r => "review over upgradeable modules",
845 readme => "display the README of a distro woth a pager",
846 recent => "show recent uploads to the CPAN",
848 reload => "'reload cpan' or 'reload index'",
849 report => "test a distribution and send a test report to cpantesters",
850 reports => "info about reported tests from cpantesters",
853 test => "test a distribution",
854 u => "display uninstalled modules",
855 upgrade => "combine 'r' command with immediate installation",
858 $autoload_recursion ||= 0;
860 #-> sub CPAN::Shell::AUTOLOAD ;
862 $autoload_recursion++;
864 my $class = shift(@_);
865 # warn "autoload[$l] class[$class]";
868 warn "Refusing to autoload '$l' while signal pending";
869 $autoload_recursion--;
872 if ($autoload_recursion > 1) {
873 my $fullcommand = join " ", map { "'$_'" } $l, @_;
874 warn "Refusing to autoload $fullcommand in recursion\n";
875 $autoload_recursion--;
879 # XXX needs to be reconsidered
880 if ($CPAN::META->has_inst('CPAN::WAIT')) {
883 $CPAN::Frontend->mywarn(qq{
884 Commands starting with "w" require CPAN::WAIT to be installed.
885 Please consider installing CPAN::WAIT to use the fulltext index.
886 For this you just need to type
891 $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }.
895 $autoload_recursion--;
902 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
904 # from here on only subs.
905 ################################################################################
907 sub _perl_fingerprint {
908 my($self,$other_fingerprint) = @_;
909 my $dll = eval {OS2::DLLname()};
912 $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
914 my $mtime_perl = (-f CPAN::find_perl ? (stat(_))[9] : '-1');
915 my $this_fingerprint = {
916 '$^X' => CPAN::find_perl,
917 sitearchexp => $Config::Config{sitearchexp},
918 'mtime_$^X' => $mtime_perl,
919 'mtime_dll' => $mtime_dll,
921 if ($other_fingerprint) {
922 if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
923 $other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
925 # mandatory keys since 1.88_57
926 for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
927 return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
931 return $this_fingerprint;
935 sub suggest_myconfig () {
936 SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
937 $CPAN::Frontend->myprint("You don't seem to have a user ".
938 "configuration (MyConfig.pm) yet.\n");
939 my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
940 "user configuration now? (Y/n)",
943 CPAN::Shell->mkmyconfig();
946 $CPAN::Frontend->mydie("OK, giving up.");
951 #-> sub CPAN::all_objects ;
953 my($mgr,$class) = @_;
954 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
955 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
957 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
960 # Called by shell, not in batch mode. In batch mode I see no risk in
961 # having many processes updating something as installations are
962 # continually checked at runtime. In shell mode I suspect it is
963 # unintentional to open more than one shell at a time
965 #-> sub CPAN::checklock ;
968 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
969 if (-f $lockfile && -M _ > 0) {
970 my $fh = FileHandle->new($lockfile) or
971 $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
972 my $otherpid = <$fh>;
973 my $otherhost = <$fh>;
975 if (defined $otherpid && $otherpid) {
978 if (defined $otherhost && $otherhost) {
981 my $thishost = hostname();
982 if (defined $otherhost && defined $thishost &&
983 $otherhost ne '' && $thishost ne '' &&
984 $otherhost ne $thishost) {
985 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
986 "reports other host $otherhost and other ".
987 "process $otherpid.\n".
988 "Cannot proceed.\n"));
989 } elsif ($RUN_DEGRADED) {
990 $CPAN::Frontend->mywarn("Running in degraded mode (experimental)\n");
991 } elsif (defined $otherpid && $otherpid) {
992 return if $$ == $otherpid; # should never happen
993 $CPAN::Frontend->mywarn(
995 There seems to be running another CPAN process (pid $otherpid). Contacting...
997 if (kill 0, $otherpid) {
998 $CPAN::Frontend->mywarn(qq{Other job is running.\n});
1000 CPAN::Shell::colorable_makemaker_prompt
1001 (qq{Shall I try to run in degraded }.
1002 qq{mode? (Y/n)},"y");
1003 if ($ans =~ /^y/i) {
1004 $CPAN::Frontend->mywarn("Running in degraded mode (experimental).
1005 Please report if something unexpected happens\n");
1007 for ($CPAN::Config) {
1009 # $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
1010 $_->{commandnumber_in_prompt} = 0; # visibility
1011 $_->{histfile} = ""; # who should win otherwise?
1012 $_->{cache_metadata} = 0; # better would be a lock?
1013 $_->{use_sqlite} = 0; # better would be a write lock!
1016 $CPAN::Frontend->mydie("
1017 You may want to kill the other job and delete the lockfile. On UNIX try:
1022 } elsif (-w $lockfile) {
1024 CPAN::Shell::colorable_makemaker_prompt
1025 (qq{Other job not responding. Shall I overwrite }.
1026 qq{the lockfile '$lockfile'? (Y/n)},"y");
1027 $CPAN::Frontend->myexit("Ok, bye\n")
1028 unless $ans =~ /^y/i;
1031 qq{Lockfile '$lockfile' not writeable by you. }.
1032 qq{Cannot proceed.\n}.
1033 qq{ On UNIX try:\n}.
1034 qq{ rm '$lockfile'\n}.
1035 qq{ and then rerun us.\n}
1039 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
1040 "'$lockfile', please remove. Cannot proceed.\n"));
1043 my $dotcpan = $CPAN::Config->{cpan_home};
1044 eval { File::Path::mkpath($dotcpan);};
1046 # A special case at least for Jarkko.
1047 my $firsterror = $@;
1051 $symlinkcpan = readlink $dotcpan;
1052 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
1053 eval { File::Path::mkpath($symlinkcpan); };
1057 $CPAN::Frontend->mywarn(qq{
1058 Working directory $symlinkcpan created.
1062 unless (-d $dotcpan) {
1064 Your configuration suggests "$dotcpan" as your
1065 CPAN.pm working directory. I could not create this directory due
1066 to this error: $firsterror\n};
1068 As "$dotcpan" is a symlink to "$symlinkcpan",
1069 I tried to create that, but I failed with this error: $seconderror
1072 Please make sure the directory exists and is writable.
1074 $CPAN::Frontend->mywarn($mess);
1075 return suggest_myconfig;
1077 } # $@ after eval mkpath $dotcpan
1078 if (0) { # to test what happens when a race condition occurs
1079 for (reverse 1..10) {
1085 if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
1087 unless ($fh = FileHandle->new("+>>$lockfile")) {
1088 if ($! =~ /Permission/) {
1089 $CPAN::Frontend->mywarn(qq{
1091 Your configuration suggests that CPAN.pm should use a working
1093 $CPAN::Config->{cpan_home}
1094 Unfortunately we could not create the lock file
1096 due to permission problems.
1098 Please make sure that the configuration variable
1099 \$CPAN::Config->{cpan_home}
1100 points to a directory where you can write a .lock file. You can set
1101 this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
1104 return suggest_myconfig;
1108 while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
1110 $CPAN::Frontend->mydie("Giving up\n");
1112 $CPAN::Frontend->mysleep($sleep++);
1113 $CPAN::Frontend->mywarn("Could not lock lockfile with flock: $!; retrying\n");
1119 $fh->print($$, "\n");
1120 $fh->print(hostname(), "\n");
1121 $self->{LOCK} = $lockfile;
1122 $self->{LOCKFH} = $fh;
1127 $CPAN::Frontend->mydie("Got SIG$sig, leaving");
1132 &cleanup if $Signal;
1133 die "Got yet another signal" if $Signal > 1;
1134 $CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
1135 $CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
1139 # From: Larry Wall <larry@wall.org>
1140 # Subject: Re: deprecating SIGDIE
1141 # To: perl5-porters@perl.org
1142 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
1144 # The original intent of __DIE__ was only to allow you to substitute one
1145 # kind of death for another on an application-wide basis without respect
1146 # to whether you were in an eval or not. As a global backstop, it should
1147 # not be used any more lightly (or any more heavily :-) than class
1148 # UNIVERSAL. Any attempt to build a general exception model on it should
1149 # be politely squashed. Any bug that causes every eval {} to have to be
1150 # modified should be not so politely squashed.
1152 # Those are my current opinions. It is also my optinion that polite
1153 # arguments degenerate to personal arguments far too frequently, and that
1154 # when they do, it's because both people wanted it to, or at least didn't
1155 # sufficiently want it not to.
1159 # global backstop to cleanup if we should really die
1160 $SIG{__DIE__} = \&cleanup;
1161 $self->debug("Signal handler set.") if $CPAN::DEBUG;
1164 #-> sub CPAN::DESTROY ;
1166 &cleanup; # need an eval?
1169 #-> sub CPAN::anycwd ;
1172 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
1177 sub cwd {Cwd::cwd();}
1179 #-> sub CPAN::getcwd ;
1180 sub getcwd {Cwd::getcwd();}
1182 #-> sub CPAN::fastcwd ;
1183 sub fastcwd {Cwd::fastcwd();}
1185 #-> sub CPAN::backtickcwd ;
1186 sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
1188 #-> sub CPAN::find_perl ;
1190 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
1191 my $pwd = $CPAN::iCwd = CPAN::anycwd();
1192 my $candidate = File::Spec->catfile($pwd,$^X);
1193 $perl ||= $candidate if MM->maybe_command($candidate);
1196 my ($component,$perl_name);
1197 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
1198 PATH_COMPONENT: foreach $component (File::Spec->path(),
1199 $Config::Config{'binexp'}) {
1200 next unless defined($component) && $component;
1201 my($abs) = File::Spec->catfile($component,$perl_name);
1202 if (MM->maybe_command($abs)) {
1214 #-> sub CPAN::exists ;
1216 my($mgr,$class,$id) = @_;
1217 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1218 CPAN::Index->reload;
1219 ### Carp::croak "exists called without class argument" unless $class;
1221 $id =~ s/:+/::/g if $class eq "CPAN::Module";
1223 if (CPAN::_sqlite_running) {
1224 $exists = (exists $META->{readonly}{$class}{$id} or
1225 $CPAN::SQLite->set($class, $id));
1227 $exists = exists $META->{readonly}{$class}{$id};
1229 $exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1232 #-> sub CPAN::delete ;
1234 my($mgr,$class,$id) = @_;
1235 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
1236 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1239 #-> sub CPAN::has_usable
1240 # has_inst is sometimes too optimistic, we should replace it with this
1241 # has_usable whenever a case is given
1243 my($self,$mod,$message) = @_;
1244 return 1 if $HAS_USABLE->{$mod};
1245 my $has_inst = $self->has_inst($mod,$message);
1246 return unless $has_inst;
1249 LWP => [ # we frequently had "Can't locate object
1250 # method "new" via package "LWP::UserAgent" at
1251 # (eval 69) line 2006
1253 sub {require LWP::UserAgent},
1254 sub {require HTTP::Request},
1255 sub {require URI::URL},
1258 sub {require Net::FTP},
1259 sub {require Net::Config},
1261 'File::HomeDir' => [
1262 sub {require File::HomeDir;
1263 unless (CPAN::Version->vge(File::HomeDir::->VERSION, 0.52)) {
1264 for ("Will not use File::HomeDir, need 0.52\n") {
1265 $CPAN::Frontend->mywarn($_);
1272 sub {require Archive::Tar;
1273 unless (CPAN::Version->vge(Archive::Tar::->VERSION, 1.00)) {
1274 for ("Will not use Archive::Tar, need 1.00\n") {
1275 $CPAN::Frontend->mywarn($_);
1282 # XXX we should probably delete from
1283 # %INC too so we can load after we
1284 # installed a new enough version --
1286 sub {require File::Temp;
1287 unless (CPAN::Version->vge(File::Temp::->VERSION,0.16)) {
1288 for ("Will not use File::Temp, need 0.16\n") {
1289 $CPAN::Frontend->mywarn($_);
1296 if ($usable->{$mod}) {
1297 for my $c (0..$#{$usable->{$mod}}) {
1298 my $code = $usable->{$mod}[$c];
1299 my $ret = eval { &$code() };
1300 $ret = "" unless defined $ret;
1302 # warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
1307 return $HAS_USABLE->{$mod} = 1;
1310 #-> sub CPAN::has_inst
1312 my($self,$mod,$message) = @_;
1313 Carp::croak("CPAN->has_inst() called without an argument")
1314 unless defined $mod;
1315 my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
1316 keys %{$CPAN::Config->{dontload_hash}||{}},
1317 @{$CPAN::Config->{dontload_list}||[]};
1318 if (defined $message && $message eq "no" # afair only used by Nox
1322 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
1330 # checking %INC is wrong, because $INC{LWP} may be true
1331 # although $INC{"URI/URL.pm"} may have failed. But as
1332 # I really want to say "bla loaded OK", I have to somehow
1334 ### warn "$file in %INC"; #debug
1336 } elsif (eval { require $file }) {
1337 # eval is good: if we haven't yet read the database it's
1338 # perfect and if we have installed the module in the meantime,
1339 # it tries again. The second require is only a NOOP returning
1340 # 1 if we had success, otherwise it's retrying
1342 my $mtime = (stat $INC{$file})[9];
1343 # privileged files loaded by has_inst; Note: we use $mtime
1344 # as a proxy for a checksum.
1345 $CPAN::Shell::reload->{$file} = $mtime;
1346 my $v = eval "\$$mod\::VERSION";
1347 $v = $v ? " (v$v)" : "";
1348 CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
1349 if ($mod eq "CPAN::WAIT") {
1350 push @CPAN::Shell::ISA, 'CPAN::WAIT';
1353 } elsif ($mod eq "Net::FTP") {
1354 $CPAN::Frontend->mywarn(qq{
1355 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
1357 install Bundle::libnet
1359 }) unless $Have_warned->{"Net::FTP"}++;
1360 $CPAN::Frontend->mysleep(3);
1361 } elsif ($mod eq "Digest::SHA") {
1362 if ($Have_warned->{"Digest::SHA"}++) {
1363 $CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
1364 qq{because Digest::SHA not installed.\n});
1366 $CPAN::Frontend->mywarn(qq{
1367 CPAN: checksum security checks disabled because Digest::SHA not installed.
1368 Please consider installing the Digest::SHA module.
1371 $CPAN::Frontend->mysleep(2);
1373 } elsif ($mod eq "Module::Signature") {
1374 # NOT prefs_lookup, we are not a distro
1375 my $check_sigs = $CPAN::Config->{check_sigs};
1376 if (not $check_sigs) {
1377 # they do not want us:-(
1378 } elsif (not $Have_warned->{"Module::Signature"}++) {
1379 # No point in complaining unless the user can
1380 # reasonably install and use it.
1381 if (eval { require Crypt::OpenPGP; 1 } ||
1383 defined $CPAN::Config->{'gpg'}
1385 $CPAN::Config->{'gpg'} =~ /\S/
1388 $CPAN::Frontend->mywarn(qq{
1389 CPAN: Module::Signature security checks disabled because Module::Signature
1390 not installed. Please consider installing the Module::Signature module.
1391 You may also need to be able to connect over the Internet to the public
1392 keyservers like pgp.mit.edu (port 11371).
1395 $CPAN::Frontend->mysleep(2);
1399 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
1404 #-> sub CPAN::instance ;
1406 my($mgr,$class,$id) = @_;
1407 CPAN::Index->reload;
1409 # unsafe meta access, ok?
1410 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
1411 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
1419 #-> sub CPAN::cleanup ;
1421 # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
1422 local $SIG{__DIE__} = '';
1427 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
1428 $ineval = 1, last if
1429 $subroutine eq '(eval)';
1431 return if $ineval && !$CPAN::End;
1432 return unless defined $META->{LOCK};
1433 return unless -f $META->{LOCK};
1435 close $META->{LOCKFH};
1436 unlink $META->{LOCK};
1438 # Carp::cluck("DEBUGGING");
1439 if ( $CPAN::CONFIG_DIRTY ) {
1440 $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
1442 $CPAN::Frontend->myprint("Lockfile removed.\n");
1445 #-> sub CPAN::readhist
1447 my($self,$term,$histfile) = @_;
1448 my($fh) = FileHandle->new;
1449 open $fh, "<$histfile" or last;
1453 $term->AddHistory($_);
1458 #-> sub CPAN::savehist
1461 my($histfile,$histsize);
1462 unless ($histfile = $CPAN::Config->{'histfile'}) {
1463 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
1466 $histsize = $CPAN::Config->{'histsize'} || 100;
1468 unless ($CPAN::term->can("GetHistory")) {
1469 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
1475 my @h = $CPAN::term->GetHistory;
1476 splice @h, 0, @h-$histsize if @h>$histsize;
1477 my($fh) = FileHandle->new;
1478 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
1479 local $\ = local $, = "\n";
1484 #-> sub CPAN::is_tested
1486 my($self,$what,$when) = @_;
1488 Carp::cluck("DEBUG: empty what");
1491 $self->{is_tested}{$what} = $when;
1494 #-> sub CPAN::is_installed
1495 # unsets the is_tested flag: as soon as the thing is installed, it is
1496 # not needed in set_perl5lib anymore
1498 my($self,$what) = @_;
1499 delete $self->{is_tested}{$what};
1502 sub _list_sorted_descending_is_tested {
1505 { ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
1506 keys %{$self->{is_tested}}
1509 #-> sub CPAN::set_perl5lib
1511 my($self,$for) = @_;
1513 (undef,undef,undef,$for) = caller(1);
1516 $self->{is_tested} ||= {};
1517 return unless %{$self->{is_tested}};
1518 my $env = $ENV{PERL5LIB};
1519 $env = $ENV{PERLLIB} unless defined $env;
1521 push @env, $env if defined $env and length $env;
1522 #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
1523 #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
1525 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
1527 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB for '$for'\n");
1528 } elsif (@dirs < 24) {
1529 my @d = map {my $cp = $_;
1530 $cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
1533 $CPAN::Frontend->myprint("Prepending @d to PERL5LIB; ".
1534 "%BUILDDIR%=$CPAN::Config->{build_dir} ".
1538 my $cnt = keys %{$self->{is_tested}};
1539 $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib of ".
1540 "$cnt build dirs to PERL5LIB; ".
1545 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
1548 package CPAN::CacheMgr;
1551 #-> sub CPAN::CacheMgr::as_string ;
1553 eval { require Data::Dumper };
1555 return shift->SUPER::as_string;
1557 return Data::Dumper::Dumper(shift);
1561 #-> sub CPAN::CacheMgr::cachesize ;
1566 #-> sub CPAN::CacheMgr::tidyup ;
1569 return unless $CPAN::META->{LOCK};
1570 return unless -d $self->{ID};
1571 my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
1572 for my $current (0..$#toremove) {
1573 my $toremove = $toremove[$current];
1574 $CPAN::Frontend->myprint(sprintf(
1575 "DEL(%d/%d): %s \n",
1581 return if $CPAN::Signal;
1582 $self->_clean_cache($toremove);
1583 return if $CPAN::Signal;
1587 #-> sub CPAN::CacheMgr::dir ;
1592 #-> sub CPAN::CacheMgr::entries ;
1594 my($self,$dir) = @_;
1595 return unless defined $dir;
1596 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
1597 $dir ||= $self->{ID};
1598 my($cwd) = CPAN::anycwd();
1599 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
1600 my $dh = DirHandle->new(File::Spec->curdir)
1601 or Carp::croak("Couldn't opendir $dir: $!");
1604 next if $_ eq "." || $_ eq "..";
1606 push @entries, File::Spec->catfile($dir,$_);
1608 push @entries, File::Spec->catdir($dir,$_);
1610 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
1613 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
1614 sort { -M $a <=> -M $b} @entries;
1617 #-> sub CPAN::CacheMgr::disk_usage ;
1619 my($self,$dir,$fast) = @_;
1620 return if exists $self->{SIZE}{$dir};
1621 return if $CPAN::Signal;
1626 unless (chmod 0755, $dir) {
1627 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
1628 "permission to change the permission; cannot ".
1629 "estimate disk usage of '$dir'\n");
1630 $CPAN::Frontend->mysleep(5);
1635 # nothing to say, no matter what the permissions
1638 $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
1642 $Du = 0; # placeholder
1646 $File::Find::prune++ if $CPAN::Signal;
1648 if ($^O eq 'MacOS') {
1650 my $cat = Mac::Files::FSpGetCatInfo($_);
1651 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
1655 unless (chmod 0755, $_) {
1656 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
1657 "the permission to change the permission; ".
1658 "can only partially estimate disk usage ".
1660 $CPAN::Frontend->mysleep(5);
1672 return if $CPAN::Signal;
1673 $self->{SIZE}{$dir} = $Du/1024/1024;
1674 unshift @{$self->{FIFO}}, $dir;
1675 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
1676 $self->{DU} += $Du/1024/1024;
1680 #-> sub CPAN::CacheMgr::_clean_cache ;
1682 my($self,$dir) = @_;
1683 return unless -e $dir;
1684 unless (File::Spec->canonpath(File::Basename::dirname($dir))
1685 eq File::Spec->canonpath($CPAN::Config->{build_dir})) {
1686 $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
1687 "will not remove\n");
1688 $CPAN::Frontend->mysleep(5);
1691 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
1693 File::Path::rmtree($dir);
1695 if ($dir !~ /\.yml$/ && -f "$dir.yml") {
1696 my $yaml_module = CPAN::_yaml_module;
1697 if ($CPAN::META->has_inst($yaml_module)) {
1698 my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
1700 $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
1701 unlink "$dir.yml" or
1702 $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
1704 } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
1705 $CPAN::META->delete("CPAN::Distribution", $id);
1707 # XXX we should restore the state NOW, otherise this
1708 # distro does not exist until we read an index. BUG ALERT(?)
1710 # $CPAN::Frontend->mywarn (" +++\n");
1714 unlink "$dir.yml"; # may fail
1715 unless ($id_deleted) {
1716 CPAN->debug("no distro found associated with '$dir'");
1719 $self->{DU} -= $self->{SIZE}{$dir};
1720 delete $self->{SIZE}{$dir};
1723 #-> sub CPAN::CacheMgr::new ;
1730 ID => $CPAN::Config->{build_dir},
1731 MAX => $CPAN::Config->{'build_cache'},
1732 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
1735 File::Path::mkpath($self->{ID});
1736 my $dh = DirHandle->new($self->{ID});
1737 bless $self, $class;
1740 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
1742 CPAN->debug($debug) if $CPAN::DEBUG;
1746 #-> sub CPAN::CacheMgr::scan_cache ;
1749 return if $self->{SCAN} eq 'never';
1750 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1751 unless $self->{SCAN} eq 'atstart';
1752 return unless $CPAN::META->{LOCK};
1753 $CPAN::Frontend->myprint(
1754 sprintf("Scanning cache %s for sizes\n",
1757 my @entries = $self->entries($self->{ID});
1762 if ($self->{DU} > $self->{MAX}) {
1764 $self->disk_usage($e,1);
1766 $self->disk_usage($e);
1769 while (($painted/76) < ($i/@entries)) {
1770 $CPAN::Frontend->myprint($symbol);
1773 return if $CPAN::Signal;
1775 $CPAN::Frontend->myprint("DONE\n");
1779 package CPAN::Shell;
1782 #-> sub CPAN::Shell::h ;
1784 my($class,$about) = @_;
1785 if (defined $about) {
1787 if (exists $Help->{$about}) {
1788 if (ref $Help->{$about}) { # aliases
1789 $about = ${$Help->{$about}};
1791 $help = $Help->{$about};
1793 $help = "No help available";
1795 $CPAN::Frontend->myprint("$about\: $help\n");
1797 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
1798 $CPAN::Frontend->myprint(qq{
1799 Display Information $filler (ver $CPAN::VERSION)
1800 command argument description
1801 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1802 i WORD or /REGEXP/ about any of the above
1803 ls AUTHOR or GLOB about files in the author's directory
1804 (with WORD being a module, bundle or author name or a distribution
1805 name of the form AUTHOR/DISTRIBUTION)
1807 Download, Test, Make, Install...
1808 get download clean make clean
1809 make make (implies get) look open subshell in dist directory
1810 test make test (implies make) readme display these README files
1811 install make install (implies test) perldoc display POD documentation
1814 r WORDs or /REGEXP/ or NONE report updates for some/matching/all modules
1815 upgrade WORDs or /REGEXP/ or NONE upgrade some/matching/all modules
1818 force CMD try hard to do command fforce CMD try harder
1819 notest CMD skip testing
1822 h,? display this menu ! perl-code eval a perl command
1823 o conf [opt] set and query options q quit the cpan shell
1824 reload cpan load CPAN.pm again reload index load newer indices
1825 autobundle Snapshot recent latest CPAN uploads});
1831 #-> sub CPAN::Shell::a ;
1833 my($self,@arg) = @_;
1834 # authors are always UPPERCASE
1836 $_ = uc $_ unless /=/;
1838 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1841 #-> sub CPAN::Shell::globls ;
1843 my($self,$s,$pragmas) = @_;
1844 # ls is really very different, but we had it once as an ordinary
1845 # command in the Shell (upto rev. 321) and we could not handle
1847 my(@accept,@preexpand);
1848 if ($s =~ /[\*\?\/]/) {
1849 if ($CPAN::META->has_inst("Text::Glob")) {
1850 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
1851 my $rau = Text::Glob::glob_to_regex(uc $au);
1852 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
1854 push @preexpand, map { $_->id . "/" . $pathglob }
1855 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
1857 my $rau = Text::Glob::glob_to_regex(uc $s);
1858 push @preexpand, map { $_->id }
1859 CPAN::Shell->expand_by_method('CPAN::Author',
1864 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
1867 push @preexpand, uc $s;
1870 unless (/^[A-Z0-9\-]+(\/|$)/i) {
1871 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1876 my $silent = @accept>1;
1877 my $last_alpha = "";
1879 for my $a (@accept) {
1880 my($author,$pathglob);
1881 if ($a =~ m|(.*?)/(.*)|) {
1884 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1887 or $CPAN::Frontend->mydie("No author found for $a2\n");
1889 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1892 or $CPAN::Frontend->mydie("No author found for $a\n");
1895 my $alpha = substr $author->id, 0, 1;
1897 if ($alpha eq $last_alpha) {
1901 $last_alpha = $alpha;
1903 $CPAN::Frontend->myprint($ad);
1905 for my $pragma (@$pragmas) {
1906 if ($author->can($pragma)) {
1910 push @results, $author->ls($pathglob,$silent); # silent if
1913 for my $pragma (@$pragmas) {
1914 my $unpragma = "un$pragma";
1915 if ($author->can($unpragma)) {
1916 $author->$unpragma();
1923 #-> sub CPAN::Shell::local_bundles ;
1925 my($self,@which) = @_;
1926 my($incdir,$bdir,$dh);
1927 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1928 my @bbase = "Bundle";
1929 while (my $bbase = shift @bbase) {
1930 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1931 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1932 if ($dh = DirHandle->new($bdir)) { # may fail
1934 for $entry ($dh->read) {
1935 next if $entry =~ /^\./;
1936 next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
1937 if (-d File::Spec->catdir($bdir,$entry)) {
1938 push @bbase, "$bbase\::$entry";
1940 next unless $entry =~ s/\.pm(?!\n)\Z//;
1941 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1949 #-> sub CPAN::Shell::b ;
1951 my($self,@which) = @_;
1952 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1953 $self->local_bundles;
1954 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1957 #-> sub CPAN::Shell::d ;
1958 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1960 #-> sub CPAN::Shell::m ;
1961 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1963 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1966 #-> sub CPAN::Shell::i ;
1970 @args = '/./' unless @args;
1972 for my $type (qw/Bundle Distribution Module/) {
1973 push @result, $self->expand($type,@args);
1975 # Authors are always uppercase.
1976 push @result, $self->expand("Author", map { uc $_ } @args);
1978 my $result = @result == 1 ?
1979 $result[0]->as_string :
1981 "No objects found of any type for argument @args\n" :
1983 (map {$_->as_glimpse} @result),
1984 scalar @result, " items found\n",
1986 $CPAN::Frontend->myprint($result);
1989 #-> sub CPAN::Shell::o ;
1991 # CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o
1992 # conf' calls through to CPAN::HandleConfig::edit. 'o conf' should
1993 # probably have been called 'set' and 'o debug' maybe 'set debug' or
1994 # 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
1996 my($self,$o_type,@o_what) = @_;
1998 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1999 if ($o_type eq 'conf') {
2000 my($cfilter) = $o_what[0] =~ m|^/(.*)/$| if @o_what;
2001 if (!@o_what or $cfilter) { # print all things, "o conf"
2003 my $qrfilter = eval 'qr/$cfilter/';
2005 $CPAN::Frontend->myprint("\$CPAN::Config options from ");
2007 if (exists $INC{'CPAN/Config.pm'}) {
2008 push @from, $INC{'CPAN/Config.pm'};
2010 if (exists $INC{'CPAN/MyConfig.pm'}) {
2011 push @from, $INC{'CPAN/MyConfig.pm'};
2013 $CPAN::Frontend->myprint(join " and ", map {"'$_'"} @from);
2014 $CPAN::Frontend->myprint(":\n");
2015 for $k (sort keys %CPAN::HandleConfig::can) {
2016 next unless $k =~ /$qrfilter/;
2017 $v = $CPAN::HandleConfig::can{$k};
2018 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
2020 $CPAN::Frontend->myprint("\n");
2021 for $k (sort keys %CPAN::HandleConfig::keys) {
2022 next unless $k =~ /$qrfilter/;
2023 CPAN::HandleConfig->prettyprint($k);
2025 $CPAN::Frontend->myprint("\n");
2027 if (CPAN::HandleConfig->edit(@o_what)) {
2029 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
2033 } elsif ($o_type eq 'debug') {
2035 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
2038 my($what) = shift @o_what;
2039 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
2040 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
2043 if ( exists $CPAN::DEBUG{$what} ) {
2044 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
2045 } elsif ($what =~ /^\d/) {
2046 $CPAN::DEBUG = $what;
2047 } elsif (lc $what eq 'all') {
2049 for (values %CPAN::DEBUG) {
2052 $CPAN::DEBUG = $max;
2055 for (keys %CPAN::DEBUG) {
2056 next unless lc($_) eq lc($what);
2057 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
2060 $CPAN::Frontend->myprint("unknown argument [$what]\n")
2065 my $raw = "Valid options for debug are ".
2066 join(", ",sort(keys %CPAN::DEBUG), 'all').
2067 qq{ or a number. Completion works on the options. }.
2068 qq{Case is ignored.};
2070 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
2071 $CPAN::Frontend->myprint("\n\n");
2074 $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n");
2076 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
2077 $v = $CPAN::DEBUG{$k};
2078 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
2079 if $v & $CPAN::DEBUG;
2082 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
2085 $CPAN::Frontend->myprint(qq{
2087 conf set or get configuration variables
2088 debug set or get debugging options
2093 # CPAN::Shell::paintdots_onreload
2094 sub paintdots_onreload {
2097 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
2101 # $CPAN::Frontend->myprint(".($subr)");
2102 $CPAN::Frontend->myprint(".");
2103 if ($subr =~ /\bshell\b/i) {
2104 # warn "debug[$_[0]]";
2106 # It would be nice if we could detect that a
2107 # subroutine has actually changed, but for now we
2108 # practically always set the GOTOSHELL global
2118 #-> sub CPAN::Shell::hosts ;
2121 my $fullstats = CPAN::FTP->_ftp_statistics();
2122 my $history = $fullstats->{history} || [];
2124 while (my $last = pop @$history) {
2125 my $attempts = $last->{attempts} or next;
2128 $start = $attempts->[-1]{start};
2129 if ($#$attempts > 0) {
2130 for my $i (0..$#$attempts-1) {
2131 my $url = $attempts->[$i]{url} or next;
2136 $start = $last->{start};
2138 next unless $last->{thesiteurl}; # C-C? bad filenames?
2140 $S{end} ||= $last->{end};
2141 my $dltime = $last->{end} - $start;
2142 my $dlsize = $last->{filesize} || 0;
2143 my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
2144 my $s = $S{ok}{$url} ||= {};
2147 $s->{dlsize} += $dlsize/1024;
2149 $s->{dltime} += $dltime;
2152 for my $url (keys %{$S{ok}}) {
2153 next if $S{ok}{$url}{dltime} == 0; # div by zero
2154 push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)},
2155 $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime},
2159 for my $url (keys %{$S{no}}) {
2160 push @{$res->{no}}, [$S{no}{$url},
2164 my $R = ""; # report
2165 if ($S{start} && $S{end}) {
2166 $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown";
2167 $R .= sprintf "Log ends : %s\n", $S{end} ? scalar(localtime $S{end}) : "unknown";
2169 if ($res->{ok} && @{$res->{ok}}) {
2170 $R .= sprintf "\nSuccessful downloads:
2171 N kB secs kB/s url\n";
2173 for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) {
2174 $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_;
2178 if ($res->{no} && @{$res->{no}}) {
2179 $R .= sprintf "\nUnsuccessful downloads:\n";
2181 for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) {
2182 $R .= sprintf "%4d %s\n", @$_;
2186 $CPAN::Frontend->myprint($R);
2189 #-> sub CPAN::Shell::reload ;
2191 my($self,$command,@arg) = @_;
2193 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
2194 if ($command =~ /^cpan$/i) {
2196 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
2201 "CPAN/FirstTime.pm",
2202 "CPAN/HandleConfig.pm",
2205 "CPAN/Reporter/Config.pm",
2206 "CPAN/Reporter/History.pm",
2212 MFILE: for my $f (@relo) {
2213 next unless exists $INC{$f};
2217 $CPAN::Frontend->myprint("($p");
2218 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
2219 $self->_reload_this($f) or $failed++;
2220 my $v = eval "$p\::->VERSION";
2221 $CPAN::Frontend->myprint("v$v)");
2223 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
2225 my $errors = $failed == 1 ? "error" : "errors";
2226 $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ".
2229 } elsif ($command =~ /^index$/i) {
2230 CPAN::Index->force_reload;
2232 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN modules
2233 index re-reads the index files\n});
2237 # reload means only load again what we have loaded before
2238 #-> sub CPAN::Shell::_reload_this ;
2240 my($self,$f,$args) = @_;
2241 CPAN->debug("f[$f]") if $CPAN::DEBUG;
2242 return 1 unless $INC{$f}; # we never loaded this, so we do not
2244 my $pwd = CPAN::anycwd();
2245 CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG;
2247 for my $inc (@INC) {
2248 $file = File::Spec->catfile($inc,split /\//, $f);
2252 CPAN->debug("file[$file]") if $CPAN::DEBUG;
2254 unless ($file && -f $file) {
2255 # this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
2257 unless (CPAN->has_inst("File::Basename")) {
2258 @inc = File::Basename::dirname($file);
2260 # do we ever need this?
2261 @inc = substr($file,0,-length($f)-1); # bring in back to me!
2264 CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
2266 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
2269 my $mtime = (stat $file)[9];
2270 if ($reload->{$f}) {
2271 } elsif ($^T < $mtime) {
2272 # since we started the file has changed, force it to be reloaded
2275 $reload->{$f} = $mtime;
2277 my $must_reload = $mtime != $reload->{$f};
2279 $must_reload ||= $args->{reloforce}; # o conf defaults needs this
2281 my $fh = FileHandle->new($file) or
2282 $CPAN::Frontend->mydie("Could not open $file: $!");
2285 my $content = <$fh>;
2286 CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128)))
2290 eval "require '$f'";
2295 $reload->{$f} = $mtime;
2297 $CPAN::Frontend->myprint("__unchanged__");
2302 #-> sub CPAN::Shell::mkmyconfig ;
2304 my($self, $cpanpm, %args) = @_;
2305 require CPAN::FirstTime;
2306 my $home = CPAN::HandleConfig::home;
2307 $cpanpm = $INC{'CPAN/MyConfig.pm'} ||
2308 File::Spec->catfile(split /\//, "$home/.cpan/CPAN/MyConfig.pm");
2309 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
2310 CPAN::HandleConfig::require_myconfig_or_config;
2311 $CPAN::Config ||= {};
2316 keep_source_where => undef,
2319 CPAN::FirstTime::init($cpanpm, %args);
2322 #-> sub CPAN::Shell::_binary_extensions ;
2323 sub _binary_extensions {
2324 my($self) = shift @_;
2325 my(@result,$module,%seen,%need,$headerdone);
2326 for $module ($self->expand('Module','/./')) {
2327 my $file = $module->cpan_file;
2328 next if $file eq "N/A";
2329 next if $file =~ /^Contact Author/;
2330 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
2331 next if $dist->isa_perl;
2332 next unless $module->xs_file;
2334 $CPAN::Frontend->myprint(".");
2335 push @result, $module;
2337 # print join " | ", @result;
2338 $CPAN::Frontend->myprint("\n");
2342 #-> sub CPAN::Shell::recompile ;
2344 my($self) = shift @_;
2345 my($module,@module,$cpan_file,%dist);
2346 @module = $self->_binary_extensions();
2347 for $module (@module) { # we force now and compile later, so we
2349 $cpan_file = $module->cpan_file;
2350 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2352 $dist{$cpan_file}++;
2354 for $cpan_file (sort keys %dist) {
2355 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
2356 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2358 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
2359 # stop a package from recompiling,
2360 # e.g. IO-1.12 when we have perl5.003_10
2364 #-> sub CPAN::Shell::scripts ;
2366 my($self, $arg) = @_;
2367 $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n");
2369 for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) {
2370 unless ($CPAN::META->has_inst($req)) {
2371 $CPAN::Frontend->mywarn(" $req not available\n");
2374 my $p = HTML::LinkExtor->new();
2375 my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html";
2376 unless (-f $indexfile) {
2377 $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n");
2379 $p->parse_file($indexfile);
2382 if ($arg =~ s|^/(.+)/$|$1|) {
2383 $qrarg = eval 'qr/$arg/'; # hide construct from 5.004
2385 for my $l ($p->links) {
2386 my $tag = shift @$l;
2387 next unless $tag eq "a";
2389 my $href = $att{href};
2390 next unless $href =~ s|^\.\./authors/id/./../||;
2393 if ($href =~ $qrarg) {
2397 if ($href =~ /\Q$arg\E/) {
2405 # now filter for the latest version if there is more than one of a name
2411 $stems{$stem} ||= [];
2412 push @{$stems{$stem}}, $href;
2414 for (sort keys %stems) {
2416 if (@{$stems{$_}} > 1) {
2417 $highest = List::Util::reduce {
2418 Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b
2421 $highest = $stems{$_}[0];
2423 $CPAN::Frontend->myprint("$highest\n");
2427 #-> sub CPAN::Shell::report ;
2429 my($self,@args) = @_;
2430 unless ($CPAN::META->has_inst("CPAN::Reporter")) {
2431 $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
2433 local $CPAN::Config->{test_report} = 1;
2434 $self->force("test",@args); # force is there so that the test be
2435 # re-run (as documented)
2438 # compare with is_tested
2439 #-> sub CPAN::Shell::install_tested
2440 sub install_tested {
2441 my($self,@some) = @_;
2442 $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"),
2444 CPAN::Index->reload;
2446 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2447 my $yaml = "$b.yml";
2449 $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
2452 my $yaml_content = CPAN->_yaml_loadfile($yaml);
2453 my $id = $yaml_content->[0]{distribution}{ID};
2455 $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
2458 my $do = CPAN::Shell->expandany($id);
2460 $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n");
2463 unless ($do->{build_dir}) {
2464 $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n");
2467 unless ($do->{build_dir} eq $b) {
2468 $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n");
2474 $CPAN::Frontend->mywarn("No tested distributions found.\n"),
2475 return unless @some;
2477 @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some;
2478 $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"),
2479 return unless @some;
2481 # @some = grep { not $_->uptodate } @some;
2482 # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"),
2483 # return unless @some;
2485 CPAN->debug("some[@some]");
2487 my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id;
2488 $CPAN::Frontend->myprint("install_tested: Running for $id\n");
2489 $CPAN::Frontend->mysleep(1);
2494 #-> sub CPAN::Shell::upgrade ;
2496 my($self,@args) = @_;
2497 $self->install($self->r(@args));
2500 #-> sub CPAN::Shell::_u_r_common ;
2502 my($self) = shift @_;
2503 my($what) = shift @_;
2504 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
2505 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
2506 $what && $what =~ /^[aru]$/;
2508 @args = '/./' unless @args;
2509 my(@result,$module,%seen,%need,$headerdone,
2510 $version_undefs,$version_zeroes,
2511 @version_undefs,@version_zeroes);
2512 $version_undefs = $version_zeroes = 0;
2513 my $sprintf = "%s%-25s%s %9s %9s %s\n";
2514 my @expand = $self->expand('Module',@args);
2515 my $expand = scalar @expand;
2516 if (0) { # Looks like noise to me, was very useful for debugging
2517 # for metadata cache
2518 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
2520 MODULE: for $module (@expand) {
2521 my $file = $module->cpan_file;
2522 next MODULE unless defined $file; # ??
2523 $file =~ s!^./../!!;
2524 my($latest) = $module->cpan_version;
2525 my($inst_file) = $module->inst_file;
2527 return if $CPAN::Signal;
2530 $have = $module->inst_version;
2531 } elsif ($what eq "r") {
2532 $have = $module->inst_version;
2534 if ($have eq "undef") {
2536 push @version_undefs, $module->as_glimpse;
2537 } elsif (CPAN::Version->vcmp($have,0)==0) {
2539 push @version_zeroes, $module->as_glimpse;
2541 next MODULE unless CPAN::Version->vgt($latest, $have);
2542 # to be pedantic we should probably say:
2543 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
2544 # to catch the case where CPAN has a version 0 and we have a version undef
2545 } elsif ($what eq "u") {
2551 } elsif ($what eq "r") {
2553 } elsif ($what eq "u") {
2557 return if $CPAN::Signal; # this is sometimes lengthy
2560 push @result, sprintf "%s %s\n", $module->id, $have;
2561 } elsif ($what eq "r") {
2562 push @result, $module->id;
2563 next MODULE if $seen{$file}++;
2564 } elsif ($what eq "u") {
2565 push @result, $module->id;
2566 next MODULE if $seen{$file}++;
2567 next MODULE if $file =~ /^Contact/;
2569 unless ($headerdone++) {
2570 $CPAN::Frontend->myprint("\n");
2571 $CPAN::Frontend->myprint(sprintf(
2574 "Package namespace",
2586 $CPAN::META->has_inst("Term::ANSIColor")
2588 $module->description
2590 $color_on = Term::ANSIColor::color("green");
2591 $color_off = Term::ANSIColor::color("reset");
2593 $CPAN::Frontend->myprint(sprintf $sprintf,
2600 $need{$module->id}++;
2604 $CPAN::Frontend->myprint("No modules found for @args\n");
2605 } elsif ($what eq "r") {
2606 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
2610 if ($version_zeroes) {
2611 my $s_has = $version_zeroes > 1 ? "s have" : " has";
2612 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
2613 qq{a version number of 0\n});
2614 if ($CPAN::Config->{show_zero_versions}) {
2616 $CPAN::Frontend->myprint(qq{ they are\n\t@version_zeroes\n});
2617 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }.
2618 qq{to hide them)\n});
2620 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }.
2621 qq{to show them)\n});
2624 if ($version_undefs) {
2625 my $s_has = $version_undefs > 1 ? "s have" : " has";
2626 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
2627 qq{parseable version number\n});
2628 if ($CPAN::Config->{show_unparsable_versions}) {
2630 $CPAN::Frontend->myprint(qq{ they are\n\t@version_undefs\n});
2631 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }.
2632 qq{to hide them)\n});
2634 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }.
2635 qq{to show them)\n});
2642 #-> sub CPAN::Shell::r ;
2644 shift->_u_r_common("r",@_);
2647 #-> sub CPAN::Shell::u ;
2649 shift->_u_r_common("u",@_);
2652 #-> sub CPAN::Shell::failed ;
2654 my($self,$only_id,$silent) = @_;
2656 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
2658 NAY: for my $nosayer ( # order matters!
2667 next unless exists $d->{$nosayer};
2668 next unless defined $d->{$nosayer};
2670 UNIVERSAL::can($d->{$nosayer},"failed") ?
2671 $d->{$nosayer}->failed :
2672 $d->{$nosayer} =~ /^NO/
2674 next NAY if $only_id && $only_id != (
2675 UNIVERSAL::can($d->{$nosayer},"commandid")
2677 $d->{$nosayer}->commandid
2679 $CPAN::CurrentCommandId
2684 next DIST unless $failed;
2688 # " %-45s: %s %s\n",
2691 UNIVERSAL::can($d->{$failed},"failed") ?
2693 $d->{$failed}->commandid,
2696 $d->{$failed}->text,
2697 $d->{$failed}{TIME}||0,
2710 $scope = "this command";
2711 } elsif ($CPAN::Index::HAVE_REANIMATED) {
2712 $scope = "this or a previous session";
2713 # it might be nice to have a section for previous session and
2716 $scope = "this session";
2723 map { sprintf "%5d %-45s: %s %s\n", @$_ }
2724 sort { $a->[0] <=> $b->[0] } @failed;
2727 map { sprintf " %-45s: %s %s\n", @$_[1..3] }
2734 $CPAN::Frontend->myprint("Failed during $scope:\n$print");
2735 } elsif (!$only_id || !$silent) {
2736 $CPAN::Frontend->myprint("Nothing failed in $scope\n");
2740 # XXX intentionally undocumented because completely bogus, unportable,
2743 #-> sub CPAN::Shell::status ;
2746 require Devel::Size;
2747 my $ps = FileHandle->new;
2748 open $ps, "/proc/$$/status";
2751 next unless /VmSize:\s+(\d+)/;
2755 $CPAN::Frontend->mywarn(sprintf(
2756 "%-27s %6d\n%-27s %6d\n",
2760 Devel::Size::total_size($CPAN::META)/1024,
2762 for my $k (sort keys %$CPAN::META) {
2763 next unless substr($k,0,4) eq "read";
2764 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
2765 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
2766 warn sprintf " %-25s %6d (keys: %6d)\n",
2768 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
2769 scalar keys %{$CPAN::META->{$k}{$k2}};
2774 # compare with install_tested
2775 #-> sub CPAN::Shell::is_tested
2778 CPAN::Index->reload;
2779 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2781 if ($CPAN::META->{is_tested}{$b}) {
2782 $time = scalar(localtime $CPAN::META->{is_tested}{$b});
2784 $time = scalar localtime;
2787 $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b);
2791 #-> sub CPAN::Shell::autobundle ;
2794 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
2795 my(@bundle) = $self->_u_r_common("a",@_);
2796 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
2797 File::Path::mkpath($todir);
2798 unless (-d $todir) {
2799 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
2802 my($y,$m,$d) = (localtime)[5,4,3];
2806 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
2807 my($to) = File::Spec->catfile($todir,"$me.pm");
2809 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
2810 $to = File::Spec->catfile($todir,"$me.pm");
2812 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
2814 "package Bundle::$me;\n\n",
2815 "\$VERSION = '0.01';\n\n",
2819 "Bundle::$me - Snapshot of installation on ",
2820 $Config::Config{'myhostname'},
2823 "\n\n=head1 SYNOPSIS\n\n",
2824 "perl -MCPAN -e 'install Bundle::$me'\n\n",
2825 "=head1 CONTENTS\n\n",
2826 join("\n", @bundle),
2827 "\n\n=head1 CONFIGURATION\n\n",
2829 "\n\n=head1 AUTHOR\n\n",
2830 "This Bundle has been generated automatically ",
2831 "by the autobundle routine in CPAN.pm.\n",
2834 $CPAN::Frontend->myprint("\nWrote bundle file
2838 #-> sub CPAN::Shell::expandany ;
2841 CPAN->debug("s[$s]") if $CPAN::DEBUG;
2842 if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
2843 $s = CPAN::Distribution->normalize($s);
2844 return $CPAN::META->instance('CPAN::Distribution',$s);
2845 # Distributions spring into existence, not expand
2846 } elsif ($s =~ m|^Bundle::|) {
2847 $self->local_bundles; # scanning so late for bundles seems
2848 # both attractive and crumpy: always
2849 # current state but easy to forget
2851 return $self->expand('Bundle',$s);
2853 return $self->expand('Module',$s)
2854 if $CPAN::META->exists('CPAN::Module',$s);
2859 #-> sub CPAN::Shell::expand ;
2862 my($type,@args) = @_;
2863 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
2864 my $class = "CPAN::$type";
2865 my $methods = ['id'];
2866 for my $meth (qw(name)) {
2867 next unless $class->can($meth);
2868 push @$methods, $meth;
2870 $self->expand_by_method($class,$methods,@args);
2873 #-> sub CPAN::Shell::expand_by_method ;
2874 sub expand_by_method {
2876 my($class,$methods,@args) = @_;
2879 my($regex,$command);
2880 if ($arg =~ m|^/(.*)/$|) {
2882 # FIXME: there seem to be some ='s in the author data, which trigger
2883 # a failure here. This needs to be contemplated.
2884 # } elsif ($arg =~ m/=/) {
2888 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
2890 defined $regex ? $regex : "UNDEFINED",
2891 defined $command ? $command : "UNDEFINED",
2893 if (defined $regex) {
2894 if (CPAN::_sqlite_running) {
2895 $CPAN::SQLite->search($class, $regex);
2898 $CPAN::META->all_objects($class)
2900 unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) {
2901 # BUG, we got an empty object somewhere
2902 require Data::Dumper;
2903 CPAN->debug(sprintf(
2904 "Bug in CPAN: Empty id on obj[%s][%s]",
2906 Data::Dumper::Dumper($obj)
2910 for my $method (@$methods) {
2911 my $match = eval {$obj->$method() =~ /$regex/i};
2913 my($err) = $@ =~ /^(.+) at .+? line \d+\.$/;
2914 $err ||= $@; # if we were too restrictive above
2915 $CPAN::Frontend->mydie("$err\n");
2922 } elsif ($command) {
2923 die "equal sign in command disabled (immature interface), ".
2925 ! \$CPAN::Shell::ADVANCED_QUERY=1
2926 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
2927 that may go away anytime.\n"
2928 unless $ADVANCED_QUERY;
2929 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
2930 my($matchcrit) = $criterion =~ m/^~(.+)/;
2934 $CPAN::META->all_objects($class)
2936 my $lhs = $self->$method() or next; # () for 5.00503
2938 push @m, $self if $lhs =~ m/$matchcrit/;
2940 push @m, $self if $lhs eq $criterion;
2945 if ( $class eq 'CPAN::Bundle' ) {
2946 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
2947 } elsif ($class eq "CPAN::Distribution") {
2948 $xarg = CPAN::Distribution->normalize($arg);
2952 if ($CPAN::META->exists($class,$xarg)) {
2953 $obj = $CPAN::META->instance($class,$xarg);
2954 } elsif ($CPAN::META->exists($class,$arg)) {
2955 $obj = $CPAN::META->instance($class,$arg);
2962 @m = sort {$a->id cmp $b->id} @m;
2963 if ( $CPAN::DEBUG ) {
2964 my $wantarray = wantarray;
2965 my $join_m = join ",", map {$_->id} @m;
2966 $self->debug("wantarray[$wantarray]join_m[$join_m]");
2968 return wantarray ? @m : $m[0];
2971 #-> sub CPAN::Shell::format_result ;
2974 my($type,@args) = @_;
2975 @args = '/./' unless @args;
2976 my(@result) = $self->expand($type,@args);
2977 my $result = @result == 1 ?
2978 $result[0]->as_string :
2980 "No objects of type $type found for argument @args\n" :
2982 (map {$_->as_glimpse} @result),
2983 scalar @result, " items found\n",
2988 #-> sub CPAN::Shell::report_fh ;
2990 my $installation_report_fh;
2991 my $previously_noticed = 0;
2994 return $installation_report_fh if $installation_report_fh;
2995 if ($CPAN::META->has_usable("File::Temp")) {
2996 $installation_report_fh
2998 dir => File::Spec->tmpdir,
2999 template => 'cpan_install_XXXX',
3004 unless ( $installation_report_fh ) {
3005 warn("Couldn't open installation report file; " .
3006 "no report file will be generated."
3007 ) unless $previously_noticed++;
3013 # The only reason for this method is currently to have a reliable
3014 # debugging utility that reveals which output is going through which
3015 # channel. No, I don't like the colors ;-)
3017 # to turn colordebugging on, write
3018 # cpan> o conf colorize_output 1
3020 #-> sub CPAN::Shell::print_ornamented ;
3022 my $print_ornamented_have_warned = 0;
3023 sub colorize_output {
3024 my $colorize_output = $CPAN::Config->{colorize_output};
3025 if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
3026 unless ($print_ornamented_have_warned++) {
3027 # no myprint/mywarn within myprint/mywarn!
3028 warn "Colorize_output is set to true but Term::ANSIColor is not
3029 installed. To activate colorized output, please install Term::ANSIColor.\n\n";
3031 $colorize_output = 0;
3033 return $colorize_output;
3038 #-> sub CPAN::Shell::print_ornamented ;
3039 sub print_ornamented {
3040 my($self,$what,$ornament) = @_;
3041 return unless defined $what;
3043 local $| = 1; # Flush immediately
3044 if ( $CPAN::Be_Silent ) {
3045 print {report_fh()} $what;
3048 my $swhat = "$what"; # stringify if it is an object
3049 if ($CPAN::Config->{term_is_latin}) {
3050 # note: deprecated, need to switch to $LANG and $LC_*
3053 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
3055 if ($self->colorize_output) {
3056 if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) {
3057 # if you want to have this configurable, please file a bugreport
3058 $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan";
3060 my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
3062 print "Term::ANSIColor rejects color[$ornament]: $@\n
3063 Please choose a different color (Hint: try 'o conf init /color/')\n";
3065 # GGOLDBACH/Test-GreaterVersion-0.008 broke wthout this
3066 # $trailer construct. We want the newline be the last thing if
3067 # there is a newline at the end ensuring that the next line is
3068 # empty for other players
3070 $trailer = $1 if $swhat =~ s/([\r\n]+)\z//;
3073 Term::ANSIColor::color("reset"),
3080 #-> sub CPAN::Shell::myprint ;
3082 # where is myprint/mywarn/Frontend/etc. documented? Where to use what?
3083 # I think, we send everything to STDOUT and use print for normal/good
3084 # news and warn for news that need more attention. Yes, this is our
3085 # working contract for now.
3087 my($self,$what) = @_;
3088 $self->print_ornamented($what,
3089 $CPAN::Config->{colorize_print}||'bold blue on_white',
3094 my($self,$category,$what) = @_;
3095 my $vname = $category . "_verbosity";
3096 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
3097 if (!$CPAN::Config->{$vname}
3098 || $CPAN::Config->{$vname} =~ /^v/
3100 $CPAN::Frontend->myprint($what);
3104 #-> sub CPAN::Shell::myexit ;
3106 my($self,$what) = @_;
3107 $self->myprint($what);
3111 #-> sub CPAN::Shell::mywarn ;
3113 my($self,$what) = @_;
3114 $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
3117 # only to be used for shell commands
3118 #-> sub CPAN::Shell::mydie ;
3120 my($self,$what) = @_;
3121 $self->mywarn($what);
3123 # If it is the shell, we want the following die to be silent,
3124 # but if it is not the shell, we would need a 'die $what'. We need
3125 # to take care that only shell commands use mydie. Is this
3131 # sub CPAN::Shell::colorable_makemaker_prompt ;
3132 sub colorable_makemaker_prompt {
3134 if (CPAN::Shell->colorize_output) {
3135 my $ornament = $CPAN::Config->{colorize_print}||'bold blue on_white';
3136 my $color_on = eval { Term::ANSIColor::color($ornament); } || "";
3139 my $ans = ExtUtils::MakeMaker::prompt($foo,$bar);
3140 if (CPAN::Shell->colorize_output) {
3141 print Term::ANSIColor::color('reset');
3146 # use this only for unrecoverable errors!
3147 #-> sub CPAN::Shell::unrecoverable_error ;
3148 sub unrecoverable_error {
3149 my($self,$what) = @_;
3150 my @lines = split /\n/, $what;
3152 for my $l (@lines) {
3153 $longest = length $l if length $l > $longest;
3155 $longest = 62 if $longest > 62;
3156 for my $l (@lines) {
3157 if ($l =~ /^\s*$/) {
3162 if (length $l < 66) {
3163 $l = pack "A66 A*", $l, "<==";
3167 unshift @lines, "\n";
3168 $self->mydie(join "", @lines);
3171 #-> sub CPAN::Shell::mysleep ;
3173 my($self, $sleep) = @_;
3174 if (CPAN->has_inst("Time::HiRes")) {
3175 Time::HiRes::sleep($sleep);
3177 sleep($sleep < 1 ? 1 : int($sleep + 0.5));
3181 #-> sub CPAN::Shell::setup_output ;
3183 return if -t STDOUT;
3184 my $odef = select STDERR;
3191 #-> sub CPAN::Shell::rematein ;
3192 # RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here
3195 my($meth,@some) = @_;
3197 while($meth =~ /^(ff?orce|notest)$/) {
3198 push @pragma, $meth;
3199 $meth = shift @some or
3200 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
3204 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
3206 # Here is the place to set "test_count" on all involved parties to
3207 # 0. We then can pass this counter on to the involved
3208 # distributions and those can refuse to test if test_count > X. In
3209 # the first stab at it we could use a 1 for "X".
3211 # But when do I reset the distributions to start with 0 again?
3212 # Jost suggested to have a random or cycling interaction ID that
3213 # we pass through. But the ID is something that is just left lying
3214 # around in addition to the counter, so I'd prefer to set the
3215 # counter to 0 now, and repeat at the end of the loop. But what
3216 # about dependencies? They appear later and are not reset, they
3217 # enter the queue but not its copy. How do they get a sensible
3220 # With configure_requires, "get" is vulnerable in recursion.
3222 my $needs_recursion_protection = "get|make|test|install";
3224 # construct the queue
3226 STHING: foreach $s (@some) {
3229 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
3231 } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
3232 } elsif ($s =~ m|^/|) { # looks like a regexp
3233 if (substr($s,-1,1) eq ".") {
3234 $obj = CPAN::Shell->expandany($s);
3236 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
3237 "not supported.\nRejecting argument '$s'\n");
3238 $CPAN::Frontend->mysleep(2);
3241 } elsif ($meth eq "ls") {
3242 $self->globls($s,\@pragma);
3245 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
3246 $obj = CPAN::Shell->expandany($s);
3249 } elsif (ref $obj) {
3250 if ($meth =~ /^($needs_recursion_protection)$/) {
3251 # it would be silly to check for recursion for look or dump
3252 # (we are in CPAN::Shell::rematein)
3253 CPAN->debug("Going to test against recursion") if $CPAN::DEBUG;
3254 eval { $obj->color_cmd_tmps(0,1); };
3257 and $@->isa("CPAN::Exception::RecursiveDependency")) {
3258 $CPAN::Frontend->mywarn($@);
3262 Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@);
3268 CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c");
3270 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
3271 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
3272 if ($meth =~ /^(dump|ls|reports)$/) {
3275 $CPAN::Frontend->mywarn(
3277 "Don't be silly, you can't $meth ",
3281 $CPAN::Frontend->mysleep(2);
3283 } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") {
3284 CPAN::InfoObj->dump($s);
3287 ->mywarn(qq{Warning: Cannot $meth $s, }.
3288 qq{don't know what it is.
3293 to find objects with matching identifiers.
3295 $CPAN::Frontend->mysleep(2);
3299 # queuerunner (please be warned: when I started to change the
3300 # queue to hold objects instead of names, I made one or two
3301 # mistakes and never found which. I reverted back instead)
3302 while (my $q = CPAN::Queue->first) {
3304 my $s = $q->as_string;
3305 my $reqtype = $q->reqtype || "";
3306 $obj = CPAN::Shell->expandany($s);
3308 # don't know how this can happen, maybe we should panic,
3309 # but maybe we get a solution from the first user who hits
3310 # this unfortunate exception?
3311 $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
3312 "to an object. Skipping.\n");
3313 $CPAN::Frontend->mysleep(5);
3314 CPAN::Queue->delete_first($s);
3317 $obj->{reqtype} ||= "";
3319 # force debugging because CPAN::SQLite somehow delivers us
3322 # local $CPAN::DEBUG = 1024; # Shell; probably fixed now
3324 CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]".
3325 "q-reqtype[$reqtype]") if $CPAN::DEBUG;
3327 if ($obj->{reqtype}) {
3328 if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) {
3329 $obj->{reqtype} = $reqtype;
3331 exists $obj->{install}
3334 UNIVERSAL::can($obj->{install},"failed") ?
3335 $obj->{install}->failed :
3336 $obj->{install} =~ /^NO/
3339 delete $obj->{install};
3340 $CPAN::Frontend->mywarn
3341 ("Promoting $obj->{ID} from 'build_requires' to 'requires'");
3345 $obj->{reqtype} = $reqtype;
3348 for my $pragma (@pragma) {
3351 $obj->can($pragma)) {
3352 $obj->$pragma($meth);
3355 if (UNIVERSAL::can($obj, 'called_for')) {
3356 $obj->called_for($s);
3358 CPAN->debug(qq{pragma[@pragma]meth[$meth]}.
3359 qq{ID[$obj->{ID}]}) if $CPAN::DEBUG;
3362 if ($meth =~ /^(report)$/) { # they came here with a pragma?
3364 } elsif (! UNIVERSAL::can($obj,$meth)) {
3366 my $serialized = "";
3368 } elsif ($CPAN::META->has_inst("YAML::Syck")) {
3369 $serialized = YAML::Syck::Dump($obj);
3370 } elsif ($CPAN::META->has_inst("YAML")) {
3371 $serialized = YAML::Dump($obj);
3372 } elsif ($CPAN::META->has_inst("Data::Dumper")) {
3373 $serialized = Data::Dumper::Dumper($obj);
3376 $serialized = overload::StrVal($obj);
3378 CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
3379 $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
3380 } elsif ($obj->$meth()) {
3381 CPAN::Queue->delete($s);
3382 CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG;
3384 CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG;
3388 for my $pragma (@pragma) {
3389 my $unpragma = "un$pragma";
3390 if ($obj->can($unpragma)) {
3394 CPAN::Queue->delete_first($s);
3396 if ($meth =~ /^($needs_recursion_protection)$/) {
3397 for my $obj (@qcopy) {
3398 $obj->color_cmd_tmps(0,0);
3403 #-> sub CPAN::Shell::recent ;
3406 if ($CPAN::META->has_inst("XML::LibXML")) {
3407 my $url = $CPAN::Defaultrecent;
3408 $CPAN::Frontend->myprint("Going to fetch '$url'\n");
3409 unless ($CPAN::META->has_usable("LWP")) {
3410 $CPAN::Frontend->mydie("LWP not installed; cannot continue");
3412 CPAN::LWP::UserAgent->config;
3414 eval { $Ua = CPAN::LWP::UserAgent->new; };
3416 $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
3418 my $resp = $Ua->get($url);
3419 unless ($resp->is_success) {
3420 $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
3422 $CPAN::Frontend->myprint("DONE\n\n");
3423 my $xml = XML::LibXML->new->parse_string($resp->content);
3425 my $s = $xml->serialize(2);
3426 $s =~ s/\n\s*\n/\n/g;
3427 $CPAN::Frontend->myprint($s);
3431 if ($url =~ /winnipeg/) {
3432 my $pubdate = $xml->findvalue("/rss/channel/pubDate");
3433 $CPAN::Frontend->myprint(" pubDate: $pubdate\n\n");
3434 for my $eitem ($xml->findnodes("/rss/channel/item")) {
3435 my $distro = $eitem->findvalue("enclosure/\@url");
3436 $distro =~ s|.*?/authors/id/./../||;
3437 my $size = $eitem->findvalue("enclosure/\@length");
3438 my $desc = $eitem->findvalue("description");
3439 \0 $desc =~ s/.+? - //;
3440 $CPAN::Frontend->myprint("$distro [$size b]\n $desc\n");
3441 push @distros, $distro;
3443 } elsif ($url =~ /search.*uploads.rdf/) {
3444 # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
3445 # xmlns="http://purl.org/rss/1.0/"
3446 # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
3447 # xmlns:dc="http://purl.org/dc/elements/1.1/"
3448 # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
3449 # xmlns:admin="http://webns.net/mvcb/"
3452 my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']");
3453 $CPAN::Frontend->myprint(" dc:date: $dc_date\n\n");
3454 my $finish_eitem = 0;
3455 local $SIG{INT} = sub { $finish_eitem = 1 };
3456 EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) {
3457 my $distro = $eitem->findvalue("\@rdf:about");
3458 $distro =~ s|.*~||; # remove up to the tilde before the name
3459 $distro =~ s|/$||; # remove trailing slash
3460 $distro =~ s|([^/]+)|\U$1\E|; # upcase the name
3461 my $author = uc $1 or die "distro[$distro] without author, cannot continue";
3462 my $desc = $eitem->findvalue("*[local-name(.) = 'description']");
3464 SUBDIRTEST: while () {
3465 last SUBDIRTEST if ++$i >= 6; # half a dozen must do!
3466 if (my @ret = $self->globls("$distro*")) {
3467 @ret = grep {$_->[2] !~ /meta/} @ret;
3468 @ret = grep {length $_->[2]} @ret;
3470 $distro = "$author/$ret[0][2]";
3474 $distro =~ s|/|/*/|; # allow it to reside in a subdirectory
3477 next EITEM if $distro =~ m|\*|; # did not find the thing
3478 $CPAN::Frontend->myprint("____$desc\n");
3479 push @distros, $distro;
3480 last EITEM if $finish_eitem;
3485 # deprecated old version
3486 $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n");
3490 #-> sub CPAN::Shell::smoke ;
3493 my $distros = $self->recent;
3494 DISTRO: for my $distro (@$distros) {
3495 $CPAN::Frontend->myprint(sprintf "Going to download and test '$distro'\n");
3498 local $SIG{INT} = sub { $skip = 1 };
3500 $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_);
3503 $CPAN::Frontend->myprint(" skipped\n");
3508 $CPAN::Frontend->myprint("\r \n"); # leave the dirty line with a newline
3509 $self->test($distro);
3514 # set up the dispatching methods
3516 for my $command (qw(
3533 *$command = sub { shift->rematein($command, @_); };
3537 package CPAN::LWP::UserAgent;
3541 return if $SETUPDONE;
3542 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3543 require LWP::UserAgent;
3544 @ISA = qw(Exporter LWP::UserAgent);
3547 $CPAN::Frontend->mywarn(" LWP::UserAgent not available\n");
3551 sub get_basic_credentials {
3552 my($self, $realm, $uri, $proxy) = @_;
3553 if ($USER && $PASSWD) {
3554 return ($USER, $PASSWD);
3557 ($USER,$PASSWD) = $self->get_proxy_credentials();
3559 ($USER,$PASSWD) = $self->get_non_proxy_credentials();
3561 return($USER,$PASSWD);
3564 sub get_proxy_credentials {
3566 my ($user, $password);
3567 if ( defined $CPAN::Config->{proxy_user} &&
3568 defined $CPAN::Config->{proxy_pass}) {
3569 $user = $CPAN::Config->{proxy_user};
3570 $password = $CPAN::Config->{proxy_pass};
3571 return ($user, $password);
3573 my $username_prompt = "\nProxy authentication needed!
3574 (Note: to permanently configure username and password run
3575 o conf proxy_user your_username
3576 o conf proxy_pass your_password
3578 ($user, $password) =
3579 _get_username_and_password_from_user($username_prompt);
3580 return ($user,$password);
3583 sub get_non_proxy_credentials {
3585 my ($user,$password);
3586 if ( defined $CPAN::Config->{username} &&
3587 defined $CPAN::Config->{password}) {
3588 $user = $CPAN::Config->{username};
3589 $password = $CPAN::Config->{password};
3590 return ($user, $password);
3592 my $username_prompt = "\nAuthentication needed!
3593 (Note: to permanently configure username and password run
3594 o conf username your_username
3595 o conf password your_password
3598 ($user, $password) =
3599 _get_username_and_password_from_user($username_prompt);
3600 return ($user,$password);
3603 sub _get_username_and_password_from_user {
3604 my $username_message = shift;
3605 my ($username,$password);
3607 ExtUtils::MakeMaker->import(qw(prompt));
3608 $username = prompt($username_message);
3609 if ($CPAN::META->has_inst("Term::ReadKey")) {
3610 Term::ReadKey::ReadMode("noecho");
3613 $CPAN::Frontend->mywarn(
3614 "Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n"
3617 $password = prompt("Password:");
3619 if ($CPAN::META->has_inst("Term::ReadKey")) {
3620 Term::ReadKey::ReadMode("restore");
3622 $CPAN::Frontend->myprint("\n\n");
3623 return ($username,$password);
3626 # mirror(): Its purpose is to deal with proxy authentication. When we
3627 # call SUPER::mirror, we relly call the mirror method in
3628 # LWP::UserAgent. LWP::UserAgent will then call
3629 # $self->get_basic_credentials or some equivalent and this will be
3630 # $self->dispatched to our own get_basic_credentials method.
3632 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3634 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3635 # although we have gone through our get_basic_credentials, the proxy
3636 # server refuses to connect. This could be a case where the username or
3637 # password has changed in the meantime, so I'm trying once again without
3638 # $USER and $PASSWD to give the get_basic_credentials routine another
3639 # chance to set $USER and $PASSWD.
3641 # mirror(): Its purpose is to deal with proxy authentication. When we
3642 # call SUPER::mirror, we relly call the mirror method in
3643 # LWP::UserAgent. LWP::UserAgent will then call
3644 # $self->get_basic_credentials or some equivalent and this will be
3645 # $self->dispatched to our own get_basic_credentials method.
3647 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3649 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3650 # although we have gone through our get_basic_credentials, the proxy
3651 # server refuses to connect. This could be a case where the username or
3652 # password has changed in the meantime, so I'm trying once again without
3653 # $USER and $PASSWD to give the get_basic_credentials routine another
3654 # chance to set $USER and $PASSWD.
3657 my($self,$url,$aslocal) = @_;
3658 my $result = $self->SUPER::mirror($url,$aslocal);
3659 if ($result->code == 407) {
3662 $result = $self->SUPER::mirror($url,$aslocal);
3670 #-> sub CPAN::FTP::ftp_statistics
3671 # if they want to rewrite, they need to pass in a filehandle
3672 sub _ftp_statistics {
3674 my $locktype = $fh ? LOCK_EX : LOCK_SH;
3675 $fh ||= FileHandle->new;
3676 my $file = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3677 open $fh, "+>>$file" or $CPAN::Frontend->mydie("Could not open '$file': $!");
3680 while (!CPAN::_flock($fh, $locktype|LOCK_NB)) {
3681 $waitstart ||= localtime();
3683 $CPAN::Frontend->mywarn("Waiting for a read lock on '$file' (since $waitstart)\n");
3685 $CPAN::Frontend->mysleep($sleep);
3688 } elsif ($sleep <=6) {
3692 my $stats = eval { CPAN->_yaml_loadfile($file); };
3695 if (ref $@ eq "CPAN::Exception::yaml_not_installed") {
3696 $CPAN::Frontend->myprint("Warning (usually harmless): $@");
3698 } elsif (ref $@ eq "CPAN::Exception::yaml_process_error") {
3699 $CPAN::Frontend->mydie($@);
3702 $CPAN::Frontend->mydie($@);
3708 #-> sub CPAN::FTP::_mytime
3710 if (CPAN->has_inst("Time::HiRes")) {
3711 return Time::HiRes::time();
3717 #-> sub CPAN::FTP::_new_stats
3719 my($self,$file) = @_;
3728 #-> sub CPAN::FTP::_add_to_statistics
3729 sub _add_to_statistics {
3730 my($self,$stats) = @_;
3731 my $yaml_module = CPAN::_yaml_module;
3732 $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG;
3733 if ($CPAN::META->has_inst($yaml_module)) {
3734 $stats->{thesiteurl} = $ThesiteURL;
3735 if (CPAN->has_inst("Time::HiRes")) {
3736 $stats->{end} = Time::HiRes::time();
3738 $stats->{end} = time;
3740 my $fh = FileHandle->new;
3744 @debug = $time if $sdebug;
3745 my $fullstats = $self->_ftp_statistics($fh);
3747 $fullstats->{history} ||= [];
3748 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3749 push @debug, time if $sdebug;
3750 push @{$fullstats->{history}}, $stats;
3751 # arbitrary hardcoded constants until somebody demands to have
3752 # them settable; YAML.pm 0.62 is unacceptably slow with 999;
3753 # YAML::Syck 0.82 has no noticable performance problem with 999;
3755 @{$fullstats->{history}} > 99
3756 || $time - $fullstats->{history}[0]{start} > 14*86400
3758 shift @{$fullstats->{history}}
3760 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3761 push @debug, time if $sdebug;
3762 push @debug, scalar localtime($fullstats->{history}[0]{start}) if $sdebug;
3763 # need no eval because if this fails, it is serious
3764 my $sfile = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3765 CPAN->_yaml_dumpfile("$sfile.$$",$fullstats);
3767 local $CPAN::DEBUG = 512; # FTP
3769 CPAN->debug(sprintf("DEBUG history: before_read[%d]before[%d]at[%d]".
3770 "after[%d]at[%d]oldest[%s]dumped backat[%d]",
3774 # Win32 cannot rename a file to an existing filename
3775 unlink($sfile) if ($^O eq 'MSWin32');
3776 rename "$sfile.$$", $sfile
3777 or $CPAN::Frontend->mydie("Could not rename '$sfile.$$' to '$sfile': $!\n");
3781 # if file is CHECKSUMS, suggest the place where we got the file to be
3782 # checked from, maybe only for young files?
3783 #-> sub CPAN::FTP::_recommend_url_for
3784 sub _recommend_url_for {
3785 my($self, $file) = @_;
3786 my $urllist = $self->_get_urllist;
3787 if ($file =~ s|/CHECKSUMS(.gz)?$||) {
3788 my $fullstats = $self->_ftp_statistics();
3789 my $history = $fullstats->{history} || [];
3790 while (my $last = pop @$history) {
3791 last if $last->{end} - time > 3600; # only young results are interesting
3792 next unless $last->{file}; # dirname of nothing dies!
3793 next unless $file eq File::Basename::dirname($last->{file});
3794 return $last->{thesiteurl};
3797 if ($CPAN::Config->{randomize_urllist}
3799 rand(1) < $CPAN::Config->{randomize_urllist}
3801 $urllist->[int rand scalar @$urllist];
3807 #-> sub CPAN::FTP::_get_urllist
3810 $CPAN::Config->{urllist} ||= [];
3811 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
3812 $CPAN::Frontend->mywarn("Malformed urllist; ignoring. Configuration file corrupt?\n");
3813 $CPAN::Config->{urllist} = [];
3815 my @urllist = grep { defined $_ and length $_ } @{$CPAN::Config->{urllist}};
3816 for my $u (@urllist) {
3817 CPAN->debug("u[$u]") if $CPAN::DEBUG;
3818 if (UNIVERSAL::can($u,"text")) {
3819 $u->{TEXT} .= "/" unless substr($u->{TEXT},-1) eq "/";
3821 $u .= "/" unless substr($u,-1) eq "/";
3822 $u = CPAN::URL->new(TEXT => $u, FROM => "USER");
3828 #-> sub CPAN::FTP::ftp_get ;
3830 my($class,$host,$dir,$file,$target) = @_;
3832 qq[Going to fetch file [$file] from dir [$dir]
3833 on host [$host] as local [$target]\n]
3835 my $ftp = Net::FTP->new($host);
3837 $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
3840 return 0 unless defined $ftp;
3841 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
3842 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
3843 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ) {
3844 my $msg = $ftp->message;
3845 $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
3848 unless ( $ftp->cwd($dir) ) {
3849 my $msg = $ftp->message;
3850 $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
3854 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
3855 unless ( $ftp->get($file,$target) ) {
3856 my $msg = $ftp->message;
3857 $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
3860 $ftp->quit; # it's ok if this fails
3864 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
3866 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
3867 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
3869 # > *** 1562,1567 ****
3870 # > --- 1562,1580 ----
3871 # > return 1 if substr($url,0,4) eq "file";
3872 # > return 1 unless $url =~ m|://([^/]+)|;
3874 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
3876 # > + $proxy =~ m|://([^/:]+)|;
3878 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
3879 # > + if ($noproxy) {
3880 # > + if ($host !~ /$noproxy$/) {
3881 # > + $host = $proxy;
3884 # > + $host = $proxy;
3887 # > require Net::Ping;
3888 # > return 1 unless $Net::Ping::VERSION >= 2;
3892 #-> sub CPAN::FTP::localize ;
3894 my($self,$file,$aslocal,$force) = @_;
3896 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
3897 unless defined $aslocal;
3898 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
3901 if ($^O eq 'MacOS') {
3902 # Comment by AK on 2000-09-03: Uniq short filenames would be
3903 # available in CHECKSUMS file
3904 my($name, $path) = File::Basename::fileparse($aslocal, '');
3905 if (length($name) > 31) {
3916 my $size = 31 - length($suf);
3917 while (length($name) > $size) {
3921 $aslocal = File::Spec->catfile($path, $name);
3925 if (-f $aslocal && -r _ && !($force & 1)) {
3927 if ($size = -s $aslocal) {
3928 $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG;
3931 # empty file from a previous unsuccessful attempt to download it
3933 $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I ".
3934 "could not remove.");
3937 my($maybe_restore) = 0;
3939 rename $aslocal, "$aslocal.bak$$";
3943 my($aslocal_dir) = File::Basename::dirname($aslocal);
3944 $self->mymkpath($aslocal_dir); # too early for file URLs / RT #28438
3945 # Inheritance is not easier to manage than a few if/else branches
3946 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3948 CPAN::LWP::UserAgent->config;
3949 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
3951 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
3955 $Ua->proxy('ftp', $var)
3956 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
3957 $Ua->proxy('http', $var)
3958 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
3960 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
3964 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
3965 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
3968 # Try the list of urls for each single object. We keep a record
3969 # where we did get a file from
3970 my(@reordered,$last);
3971 my $ccurllist = $self->_get_urllist;
3972 $last = $#$ccurllist;
3973 if ($force & 2) { # local cpans probably out of date, don't reorder
3974 @reordered = (0..$last);
3978 (substr($ccurllist->[$b],0,4) eq "file")
3980 (substr($ccurllist->[$a],0,4) eq "file")
3982 defined($ThesiteURL)
3984 ($ccurllist->[$b] eq $ThesiteURL)
3986 ($ccurllist->[$a] eq $ThesiteURL)
3991 $self->debug("Themethod[$Themethod]reordered[@reordered]") if $CPAN::DEBUG;
3997 ["dleasy", "http","defaultsites"],
3998 ["dlhard", "http","defaultsites"],
3999 ["dleasy", "ftp", "defaultsites"],
4000 ["dlhard", "ftp", "defaultsites"],
4001 ["dlhardest","", "defaultsites"],
4004 @levels = grep {$_->[0] eq $Themethod} @all_levels;
4005 push @levels, grep {$_->[0] ne $Themethod} @all_levels;
4007 @levels = @all_levels;
4009 @levels = qw/dleasy/ if $^O eq 'MacOS';
4011 local $ENV{FTP_PASSIVE} =
4012 exists $CPAN::Config->{ftp_passive} ?
4013 $CPAN::Config->{ftp_passive} : 1;
4015 my $stats = $self->_new_stats($file);
4016 LEVEL: for $levelno (0..$#levels) {
4017 my $level_tuple = $levels[$levelno];
4018 my($level,$scheme,$sitetag) = @$level_tuple;
4019 my $defaultsites = $sitetag && $sitetag eq "defaultsites";
4021 if ($defaultsites) {
4022 unless (defined $connect_to_internet_ok) {
4023 $CPAN::Frontend->myprint(sprintf qq{
4024 I would like to connect to one of the following sites to get '%s':
4029 join("",map { " ".$_->text."\n" } @CPAN::Defaultsites),
4031 my $answer = CPAN::Shell::colorable_makemaker_prompt("Is it OK to try to connect to the Internet?", "yes");
4032 if ($answer =~ /^y/i) {
4033 $connect_to_internet_ok = 1;
4035 $connect_to_internet_ok = 0;
4038 if ($connect_to_internet_ok) {
4039 @urllist = @CPAN::Defaultsites;
4044 my @host_seq = $level =~ /dleasy/ ?
4045 @reordered : 0..$last; # reordered has file and $Thesiteurl first
4046 @urllist = map { $ccurllist->[$_] } @host_seq;
4048 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4049 my $aslocal_tempfile = $aslocal . ".tmp" . $$;
4050 if (my $recommend = $self->_recommend_url_for($file)) {
4051 @urllist = grep { $_ ne $recommend } @urllist;
4052 unshift @urllist, $recommend;
4054 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4055 $ret = $self->hostdlxxx($level,$scheme,\@urllist,$file,$aslocal_tempfile,$stats);
4057 CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG;
4058 if ($ret eq $aslocal_tempfile) {
4059 # if we got it exactly as we asked for, only then we
4061 rename $aslocal_tempfile, $aslocal
4062 or $CPAN::Frontend->mydie("Error while trying to rename ".
4063 "'$ret' to '$aslocal': $!");
4066 $Themethod = $level;
4068 # utime $now, $now, $aslocal; # too bad, if we do that, we
4069 # might alter a local mirror
4070 $self->debug("level[$level]") if $CPAN::DEBUG;
4073 unlink $aslocal_tempfile;
4074 last if $CPAN::Signal; # need to cleanup
4078 $stats->{filesize} = -s $ret;
4080 $self->debug("before _add_to_statistics") if $CPAN::DEBUG;
4081 $self->_add_to_statistics($stats);
4082 $self->debug("after _add_to_statistics") if $CPAN::DEBUG;
4084 unlink "$aslocal.bak$$";
4087 unless ($CPAN::Signal) {
4090 if (@{$CPAN::Config->{urllist}}) {
4092 qq{Please check, if the URLs I found in your configuration file \(}.
4093 join(", ", @{$CPAN::Config->{urllist}}).
4096 push @mess, qq{Your urllist is empty!};
4098 push @mess, qq{The urllist can be edited.},
4099 qq{E.g. with 'o conf urllist push ftp://myurl/'};
4100 $CPAN::Frontend->mywarn(Text::Wrap::wrap("","","@mess"). "\n\n");
4101 $CPAN::Frontend->mywarn("Could not fetch $file\n");
4102 $CPAN::Frontend->mysleep(2);
4104 if ($maybe_restore) {
4105 rename "$aslocal.bak$$", $aslocal;
4106 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
4107 $self->ls($aslocal));
4114 my($self, $aslocal_dir) = @_;
4115 File::Path::mkpath($aslocal_dir);
4116 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
4117 qq{directory "$aslocal_dir".
4118 I\'ll continue, but if you encounter problems, they may be due
4119 to insufficient permissions.\n}) unless -w $aslocal_dir;
4127 $h = [ grep /^\Q$scheme\E:/, @$h ] if $scheme;
4128 my $method = "host$level";
4129 $self->$method($h, @_);
4133 my($self,$stats,$method,$url) = @_;
4134 push @{$stats->{attempts}}, {
4141 # package CPAN::FTP;
4143 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4145 HOSTEASY: for $ro_url (@$host_seq) {
4146 $self->_set_attempt($stats,"dleasy",$ro_url);
4147 my $url .= "$ro_url$file";
4148 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
4149 if ($url =~ /^file:/) {
4151 if ($CPAN::META->has_inst('URI::URL')) {
4152 my $u = URI::URL->new($url);
4154 } else { # works only on Unix, is poorly constructed, but
4155 # hopefully better than nothing.
4156 # RFC 1738 says fileurl BNF is
4157 # fileurl = "file://" [ host | "localhost" ] "/" fpath
4158 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
4160 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
4161 $l =~ s|^file:||; # assume they
4165 if ! -f $l && $l =~ m|^/\w:|; # e.g. /P:
4167 $self->debug("local file[$l]") if $CPAN::DEBUG;
4168 if ( -f $l && -r _) {
4169 $ThesiteURL = $ro_url;
4172 if ($l =~ /(.+)\.gz$/) {
4174 if ( -f $ungz && -r _) {
4175 $ThesiteURL = $ro_url;
4179 # Maybe mirror has compressed it?
4181 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
4182 eval { CPAN::Tarzip->new("$l.gz")->gunzip($aslocal) };
4184 $ThesiteURL = $ro_url;
4188 $CPAN::Frontend->mywarn("Could not find '$l'\n");
4190 $self->debug("it was not a file URL") if $CPAN::DEBUG;
4191 if ($CPAN::META->has_usable('LWP')) {
4192 $CPAN::Frontend->myprint("Fetching with LWP:
4196 CPAN::LWP::UserAgent->config;
4197 eval { $Ua = CPAN::LWP::UserAgent->new; };
4199 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
4202 my $res = $Ua->mirror($url, $aslocal);
4203 if ($res->is_success) {
4204 $ThesiteURL = $ro_url;
4206 utime $now, $now, $aslocal; # download time is more
4207 # important than upload
4210 } elsif ($url !~ /\.gz(?!\n)\Z/) {
4211 my $gzurl = "$url.gz";
4212 $CPAN::Frontend->myprint("Fetching with LWP:
4215 $res = $Ua->mirror($gzurl, "$aslocal.gz");
4216 if ($res->is_success) {
4217 if (eval {CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)}) {
4218 $ThesiteURL = $ro_url;
4223 $CPAN::Frontend->myprint(sprintf(
4224 "LWP failed with code[%s] message[%s]\n",
4228 # Alan Burlison informed me that in firewall environments
4229 # Net::FTP can still succeed where LWP fails. So we do not
4230 # skip Net::FTP anymore when LWP is available.
4233 $CPAN::Frontend->mywarn(" LWP not available\n");
4235 return if $CPAN::Signal;
4236 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4237 # that's the nice and easy way thanks to Graham
4238 $self->debug("recognized ftp") if $CPAN::DEBUG;
4239 my($host,$dir,$getfile) = ($1,$2,$3);
4240 if ($CPAN::META->has_usable('Net::FTP')) {
4242 $CPAN::Frontend->myprint("Fetching with Net::FTP:
4245 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
4246 "aslocal[$aslocal]") if $CPAN::DEBUG;
4247 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
4248 $ThesiteURL = $ro_url;
4251 if ($aslocal !~ /\.gz(?!\n)\Z/) {
4252 my $gz = "$aslocal.gz";
4253 $CPAN::Frontend->myprint("Fetching with Net::FTP
4256 if (CPAN::FTP->ftp_get($host,
4260 eval{CPAN::Tarzip->new($gz)->gunzip($aslocal)}
4262 $ThesiteURL = $ro_url;
4268 CPAN->debug("Net::FTP does not count as usable atm") if $CPAN::DEBUG;
4272 UNIVERSAL::can($ro_url,"text")
4274 $ro_url->{FROM} eq "USER"
4276 ##address #17973: default URLs should not try to override
4277 ##user-defined URLs just because LWP is not available
4278 my $ret = $self->hostdlhard([$ro_url],$file,$aslocal,$stats);
4279 return $ret if $ret;
4281 return if $CPAN::Signal;
4285 # package CPAN::FTP;
4287 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4289 # Came back if Net::FTP couldn't establish connection (or
4290 # failed otherwise) Maybe they are behind a firewall, but they
4291 # gave us a socksified (or other) ftp program...
4294 my($devnull) = $CPAN::Config->{devnull} || "";
4296 my($aslocal_dir) = File::Basename::dirname($aslocal);
4297 File::Path::mkpath($aslocal_dir);
4298 HOSTHARD: for $ro_url (@$host_seq) {
4299 $self->_set_attempt($stats,"dlhard",$ro_url);
4300 my $url = "$ro_url$file";
4301 my($proto,$host,$dir,$getfile);
4303 # Courtesy Mark Conty mark_conty@cargill.com change from
4304 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4306 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
4307 # proto not yet used
4308 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
4310 next HOSTHARD; # who said, we could ftp anything except ftp?
4312 next HOSTHARD if $proto eq "file"; # file URLs would have had
4313 # success above. Likely a bogus URL
4315 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
4317 # Try the most capable first and leave ncftp* for last as it only
4319 DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) {
4320 my $funkyftp = CPAN::HandleConfig->safe_quote($CPAN::Config->{$f});
4321 next unless defined $funkyftp;
4322 next if $funkyftp =~ /^\s*$/;
4324 my($asl_ungz, $asl_gz);
4325 ($asl_ungz = $aslocal) =~ s/\.gz//;
4326 $asl_gz = "$asl_ungz.gz";
4328 my($src_switch) = "";
4330 my($stdout_redir) = " > $asl_ungz";
4332 $src_switch = " -source";
4333 } elsif ($f eq "ncftp") {
4334 $src_switch = " -c";
4335 } elsif ($f eq "wget") {