1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $CPAN::VERSION = '1.9205';
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 #-> CPAN::soft_chdir_with_alternatives ;
363 sub soft_chdir_with_alternatives ($) {
366 my $root = File::Spec->rootdir();
367 $CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
368 Trying '$root' as temporary haven.
373 if (chdir $cwd->[0]) {
377 $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
378 Trying to chdir to "$cwd->[1]" instead.
382 $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
390 if ($Config::Config{d_flock}) {
391 return flock $fh, $mode;
392 } elsif (!$Have_warned->{"d_flock"}++) {
393 $CPAN::Frontend->mywarn("Your OS does not support locking; continuing and ignoring all locking issues\n");
394 $CPAN::Frontend->mysleep(5);
401 sub _yaml_module () {
402 my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
404 $yaml_module ne "YAML"
406 !$CPAN::META->has_inst($yaml_module)
408 # $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
409 $yaml_module = "YAML";
411 if ($yaml_module eq "YAML"
413 $CPAN::META->has_inst($yaml_module)
415 $YAML::VERSION < 0.60
417 !$Have_warned->{"YAML"}++
419 $CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
420 "I'll continue but problems are *very* likely to happen.\n"
422 $CPAN::Frontend->mysleep(5);
427 # CPAN::_yaml_loadfile
429 my($self,$local_file) = @_;
430 return +[] unless -s $local_file;
431 my $yaml_module = _yaml_module;
432 if ($CPAN::META->has_inst($yaml_module)) {
433 # temporarly enable yaml code deserialisation
435 # 5.6.2 could not do the local() with the reference
436 local $YAML::LoadCode;
437 local $YAML::Syck::LoadCode;
438 ${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
441 if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
443 eval { @yaml = $code->($local_file); };
445 # this shall not be done by the frontend
446 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
449 } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
451 open FH, $local_file or die "Could not open '$local_file': $!";
455 eval { @yaml = $code->($ystream); };
457 # this shall not be done by the frontend
458 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
463 # this shall not be done by the frontend
464 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
469 # CPAN::_yaml_dumpfile
471 my($self,$local_file,@what) = @_;
472 my $yaml_module = _yaml_module;
473 if ($CPAN::META->has_inst($yaml_module)) {
475 if (UNIVERSAL::isa($local_file, "FileHandle")) {
476 $code = UNIVERSAL::can($yaml_module, "Dump");
477 eval { print $local_file $code->(@what) };
478 } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
479 eval { $code->($local_file,@what); };
480 } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
482 open FH, ">$local_file" or die "Could not open '$local_file': $!";
483 print FH $code->(@what);
486 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
489 if (UNIVERSAL::isa($local_file, "FileHandle")) {
490 # I think this case does not justify a warning at all
492 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
497 sub _init_sqlite () {
498 unless ($CPAN::META->has_inst("CPAN::SQLite")) {
499 $CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
500 unless $Have_warned->{"CPAN::SQLite"}++;
503 require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
504 $CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
508 my $negative_cache = {};
509 sub _sqlite_running {
510 if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
511 # need to cache the result, otherwise too slow
512 return $negative_cache->{fact};
514 $negative_cache = {}; # reset
516 my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
517 return $ret if $ret; # fast anyway
518 $negative_cache->{time} = time;
519 return $negative_cache->{fact} = $ret;
523 package CPAN::CacheMgr;
525 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
530 use Fcntl qw(:flock);
531 use vars qw($connect_to_internet_ok $Ua $Thesite $ThesiteURL $Themethod);
532 @CPAN::FTP::ISA = qw(CPAN::Debug);
534 package CPAN::LWP::UserAgent;
536 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
537 # we delay requiring LWP::UserAgent and setting up inheritance until we need it
539 package CPAN::Complete;
541 @CPAN::Complete::ISA = qw(CPAN::Debug);
542 # Q: where is the "How do I add a new command" HOWTO?
543 # A: svn diff -r 1048:1049 where andk added the report command
544 @CPAN::Complete::COMMANDS = sort qw(
545 ? ! a b d h i m o q r u
580 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $HAVE_REANIMATED);
581 @CPAN::Index::ISA = qw(CPAN::Debug);
584 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
587 package CPAN::InfoObj;
589 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
591 package CPAN::Author;
593 @CPAN::Author::ISA = qw(CPAN::InfoObj);
595 package CPAN::Distribution;
597 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
599 package CPAN::Bundle;
601 @CPAN::Bundle::ISA = qw(CPAN::Module);
603 package CPAN::Module;
605 @CPAN::Module::ISA = qw(CPAN::InfoObj);
607 package CPAN::Exception::RecursiveDependency;
609 use overload '""' => "as_string";
611 # a module sees its distribution (no version)
612 # a distribution sees its prereqs (which are module names) (usually with versions)
613 # a bundle sees its module names and/or its distributions (no version)
618 my (@deps,%seen,$loop_starts_with);
619 DCHAIN: for my $dep (@$deps) {
620 push @deps, {name => $dep, display_as => $dep};
622 $loop_starts_with = $dep;
627 for my $i (0..$#deps) {
628 my $x = $deps[$i]{name};
629 $in_loop ||= $x eq $loop_starts_with;
630 my $xo = CPAN::Shell->expandany($x) or next;
631 if ($xo->isa("CPAN::Module")) {
632 my $have = $xo->inst_version || "N/A";
633 my($want,$d,$want_type);
634 if ($i>0 and $d = $deps[$i-1]{name}) {
635 my $do = CPAN::Shell->expandany($d);
636 $want = $do->{prereq_pm}{requires}{$x};
638 $want_type = "requires: ";
640 $want = $do->{prereq_pm}{build_requires}{$x};
642 $want_type = "build_requires: ";
644 $want_type = "unknown status";
649 $want = $xo->cpan_version;
650 $want_type = "want: ";
652 $deps[$i]{have} = $have;
653 $deps[$i]{want_type} = $want_type;
654 $deps[$i]{want} = $want;
655 $deps[$i]{display_as} = "$x (have: $have; $want_type$want)";
656 } elsif ($xo->isa("CPAN::Distribution")) {
657 $deps[$i]{display_as} = $xo->pretty_id;
659 $xo->{make} = CPAN::Distrostatus->new("NO cannot resolve circular dependency");
661 $xo->{make} = CPAN::Distrostatus->new("NO one dependency ($loop_starts_with) is a circular dependency");
663 $xo->store_persistent_state; # otherwise I will not reach
664 # all involved parties for
668 bless { deps => \@deps }, $class;
673 my $ret = "\nRecursive dependency detected:\n ";
674 $ret .= join("\n => ", map {$_->{display_as}} @{$self->{deps}});
675 $ret .= ".\nCannot resolve.\n";
679 package CPAN::Exception::yaml_not_installed;
681 use overload '""' => "as_string";
684 my($class,$module,$file,$during) = @_;
685 bless { module => $module, file => $file, during => $during }, $class;
690 "'$self->{module}' not installed, cannot $self->{during} '$self->{file}'\n";
693 package CPAN::Exception::yaml_process_error;
695 use overload '""' => "as_string";
698 my($class,$module,$file,$during,$error) = @_;
699 bless { module => $module,
702 error => $error }, $class;
707 if ($self->{during}) {
709 if ($self->{module}) {
710 if ($self->{error}) {
711 return "Alert: While trying to '$self->{during}' YAML file\n".
712 " '$self->{file}'\n".
713 "with '$self->{module}' the following error was encountered:\n".
716 return "Alert: While trying to '$self->{during}' YAML file\n".
717 " '$self->{file}'\n".
718 "with '$self->{module}' some unknown error was encountered\n";
721 return "Alert: While trying to '$self->{during}' YAML file\n".
722 " '$self->{file}'\n".
723 "some unknown error was encountered\n";
726 return "Alert: While trying to '$self->{during}' some YAML file\n".
727 "some unknown error was encountered\n";
730 return "Alert: unknown error encountered\n";
734 package CPAN::Prompt; use overload '""' => "as_string";
735 use vars qw($prompt);
737 $CPAN::CurrentCommandId ||= 0;
743 unless ($CPAN::META->{LOCK}) {
744 $word = "nolock_cpan";
746 if ($CPAN::Config->{commandnumber_in_prompt}) {
747 sprintf "$word\[%d]> ", $CPAN::CurrentCommandId;
753 package CPAN::URL; use overload '""' => "as_string", fallback => 1;
754 # accessors: TEXT(the url string), FROM(DEF=>defaultlist,USER=>urllist),
755 # planned are things like age or quality
757 my($class,%args) = @_;
769 $self->{TEXT} = $set;
774 package CPAN::Distrostatus;
775 use overload '""' => "as_string",
778 my($class,$arg) = @_;
781 FAILED => substr($arg,0,2) eq "NO",
782 COMMANDID => $CPAN::CurrentCommandId,
786 sub commandid { shift->{COMMANDID} }
787 sub failed { shift->{FAILED} }
791 $self->{TEXT} = $set;
811 @CPAN::Shell::ISA = qw(CPAN::Debug);
812 $COLOR_REGISTERED ||= 0;
815 '!' => "eval the rest of the line as perl",
817 autobundle => "wtite inventory into a bundle file",
818 b => "info about bundle",
820 clean => "clean up a distribution's build directory",
822 d => "info about a distribution",
825 failed => "list all failed actions within current session",
826 fforce => "redo a command from scratch",
827 force => "redo a command",
829 help => "overview over commands; 'help ...' explains specific commands",
830 hosts => "statistics about recently used hosts",
831 i => "info about authors/bundles/distributions/modules",
832 install => "install a distribution",
833 install_tested => "install all distributions tested OK",
834 is_tested => "list all distributions tested OK",
835 look => "open a subshell in a distribution's directory",
836 ls => "list distributions according to a glob",
837 m => "info about a module",
838 make => "make/build a distribution",
839 mkmyconfig => "write current config into a CPAN/MyConfig.pm file",
840 notest => "run a (usually install) command but leave out the test phase",
841 o => "'o conf ...' for config stuff; 'o debug ...' for debugging",
842 perldoc => "try to get a manpage for a module",
844 quit => "leave the cpan shell",
845 r => "review over upgradeable modules",
846 readme => "display the README of a distro woth a pager",
847 recent => "show recent uploads to the CPAN",
849 reload => "'reload cpan' or 'reload index'",
850 report => "test a distribution and send a test report to cpantesters",
851 reports => "info about reported tests from cpantesters",
854 test => "test a distribution",
855 u => "display uninstalled modules",
856 upgrade => "combine 'r' command with immediate installation",
859 $autoload_recursion ||= 0;
861 #-> sub CPAN::Shell::AUTOLOAD ;
863 $autoload_recursion++;
865 my $class = shift(@_);
866 # warn "autoload[$l] class[$class]";
869 warn "Refusing to autoload '$l' while signal pending";
870 $autoload_recursion--;
873 if ($autoload_recursion > 1) {
874 my $fullcommand = join " ", map { "'$_'" } $l, @_;
875 warn "Refusing to autoload $fullcommand in recursion\n";
876 $autoload_recursion--;
880 # XXX needs to be reconsidered
881 if ($CPAN::META->has_inst('CPAN::WAIT')) {
884 $CPAN::Frontend->mywarn(qq{
885 Commands starting with "w" require CPAN::WAIT to be installed.
886 Please consider installing CPAN::WAIT to use the fulltext index.
887 For this you just need to type
892 $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }.
896 $autoload_recursion--;
903 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
905 # from here on only subs.
906 ################################################################################
908 sub _perl_fingerprint {
909 my($self,$other_fingerprint) = @_;
910 my $dll = eval {OS2::DLLname()};
913 $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
915 my $mtime_perl = (-f CPAN::find_perl ? (stat(_))[9] : '-1');
916 my $this_fingerprint = {
917 '$^X' => CPAN::find_perl,
918 sitearchexp => $Config::Config{sitearchexp},
919 'mtime_$^X' => $mtime_perl,
920 'mtime_dll' => $mtime_dll,
922 if ($other_fingerprint) {
923 if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
924 $other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
926 # mandatory keys since 1.88_57
927 for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
928 return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
932 return $this_fingerprint;
936 sub suggest_myconfig () {
937 SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
938 $CPAN::Frontend->myprint("You don't seem to have a user ".
939 "configuration (MyConfig.pm) yet.\n");
940 my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
941 "user configuration now? (Y/n)",
944 CPAN::Shell->mkmyconfig();
947 $CPAN::Frontend->mydie("OK, giving up.");
952 #-> sub CPAN::all_objects ;
954 my($mgr,$class) = @_;
955 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
956 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
958 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
961 # Called by shell, not in batch mode. In batch mode I see no risk in
962 # having many processes updating something as installations are
963 # continually checked at runtime. In shell mode I suspect it is
964 # unintentional to open more than one shell at a time
966 #-> sub CPAN::checklock ;
969 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
970 if (-f $lockfile && -M _ > 0) {
971 my $fh = FileHandle->new($lockfile) or
972 $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
973 my $otherpid = <$fh>;
974 my $otherhost = <$fh>;
976 if (defined $otherpid && $otherpid) {
979 if (defined $otherhost && $otherhost) {
982 my $thishost = hostname();
983 if (defined $otherhost && defined $thishost &&
984 $otherhost ne '' && $thishost ne '' &&
985 $otherhost ne $thishost) {
986 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
987 "reports other host $otherhost and other ".
988 "process $otherpid.\n".
989 "Cannot proceed.\n"));
990 } elsif ($RUN_DEGRADED) {
991 $CPAN::Frontend->mywarn("Running in degraded mode (experimental)\n");
992 } elsif (defined $otherpid && $otherpid) {
993 return if $$ == $otherpid; # should never happen
994 $CPAN::Frontend->mywarn(
996 There seems to be running another CPAN process (pid $otherpid). Contacting...
998 if (kill 0, $otherpid) {
999 $CPAN::Frontend->mywarn(qq{Other job is running.\n});
1001 CPAN::Shell::colorable_makemaker_prompt
1002 (qq{Shall I try to run in degraded }.
1003 qq{mode? (Y/n)},"y");
1004 if ($ans =~ /^y/i) {
1005 $CPAN::Frontend->mywarn("Running in degraded mode (experimental).
1006 Please report if something unexpected happens\n");
1008 for ($CPAN::Config) {
1010 # $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
1011 $_->{commandnumber_in_prompt} = 0; # visibility
1012 $_->{histfile} = ""; # who should win otherwise?
1013 $_->{cache_metadata} = 0; # better would be a lock?
1014 $_->{use_sqlite} = 0; # better would be a write lock!
1017 $CPAN::Frontend->mydie("
1018 You may want to kill the other job and delete the lockfile. On UNIX try:
1023 } elsif (-w $lockfile) {
1025 CPAN::Shell::colorable_makemaker_prompt
1026 (qq{Other job not responding. Shall I overwrite }.
1027 qq{the lockfile '$lockfile'? (Y/n)},"y");
1028 $CPAN::Frontend->myexit("Ok, bye\n")
1029 unless $ans =~ /^y/i;
1032 qq{Lockfile '$lockfile' not writeable by you. }.
1033 qq{Cannot proceed.\n}.
1034 qq{ On UNIX try:\n}.
1035 qq{ rm '$lockfile'\n}.
1036 qq{ and then rerun us.\n}
1040 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
1041 "'$lockfile', please remove. Cannot proceed.\n"));
1044 my $dotcpan = $CPAN::Config->{cpan_home};
1045 eval { File::Path::mkpath($dotcpan);};
1047 # A special case at least for Jarkko.
1048 my $firsterror = $@;
1052 $symlinkcpan = readlink $dotcpan;
1053 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
1054 eval { File::Path::mkpath($symlinkcpan); };
1058 $CPAN::Frontend->mywarn(qq{
1059 Working directory $symlinkcpan created.
1063 unless (-d $dotcpan) {
1065 Your configuration suggests "$dotcpan" as your
1066 CPAN.pm working directory. I could not create this directory due
1067 to this error: $firsterror\n};
1069 As "$dotcpan" is a symlink to "$symlinkcpan",
1070 I tried to create that, but I failed with this error: $seconderror
1073 Please make sure the directory exists and is writable.
1075 $CPAN::Frontend->mywarn($mess);
1076 return suggest_myconfig;
1078 } # $@ after eval mkpath $dotcpan
1079 if (0) { # to test what happens when a race condition occurs
1080 for (reverse 1..10) {
1086 if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
1088 unless ($fh = FileHandle->new("+>>$lockfile")) {
1089 if ($! =~ /Permission/) {
1090 $CPAN::Frontend->mywarn(qq{
1092 Your configuration suggests that CPAN.pm should use a working
1094 $CPAN::Config->{cpan_home}
1095 Unfortunately we could not create the lock file
1097 due to permission problems.
1099 Please make sure that the configuration variable
1100 \$CPAN::Config->{cpan_home}
1101 points to a directory where you can write a .lock file. You can set
1102 this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
1105 return suggest_myconfig;
1109 while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
1111 $CPAN::Frontend->mydie("Giving up\n");
1113 $CPAN::Frontend->mysleep($sleep++);
1114 $CPAN::Frontend->mywarn("Could not lock lockfile with flock: $!; retrying\n");
1120 $fh->print($$, "\n");
1121 $fh->print(hostname(), "\n");
1122 $self->{LOCK} = $lockfile;
1123 $self->{LOCKFH} = $fh;
1128 $CPAN::Frontend->mydie("Got SIG$sig, leaving");
1133 &cleanup if $Signal;
1134 die "Got yet another signal" if $Signal > 1;
1135 $CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
1136 $CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
1140 # From: Larry Wall <larry@wall.org>
1141 # Subject: Re: deprecating SIGDIE
1142 # To: perl5-porters@perl.org
1143 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
1145 # The original intent of __DIE__ was only to allow you to substitute one
1146 # kind of death for another on an application-wide basis without respect
1147 # to whether you were in an eval or not. As a global backstop, it should
1148 # not be used any more lightly (or any more heavily :-) than class
1149 # UNIVERSAL. Any attempt to build a general exception model on it should
1150 # be politely squashed. Any bug that causes every eval {} to have to be
1151 # modified should be not so politely squashed.
1153 # Those are my current opinions. It is also my optinion that polite
1154 # arguments degenerate to personal arguments far too frequently, and that
1155 # when they do, it's because both people wanted it to, or at least didn't
1156 # sufficiently want it not to.
1160 # global backstop to cleanup if we should really die
1161 $SIG{__DIE__} = \&cleanup;
1162 $self->debug("Signal handler set.") if $CPAN::DEBUG;
1165 #-> sub CPAN::DESTROY ;
1167 &cleanup; # need an eval?
1170 #-> sub CPAN::anycwd ;
1173 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
1178 sub cwd {Cwd::cwd();}
1180 #-> sub CPAN::getcwd ;
1181 sub getcwd {Cwd::getcwd();}
1183 #-> sub CPAN::fastcwd ;
1184 sub fastcwd {Cwd::fastcwd();}
1186 #-> sub CPAN::backtickcwd ;
1187 sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
1189 #-> sub CPAN::find_perl ;
1191 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
1192 my $pwd = $CPAN::iCwd = CPAN::anycwd();
1193 my $candidate = File::Spec->catfile($pwd,$^X);
1194 $perl ||= $candidate if MM->maybe_command($candidate);
1197 my ($component,$perl_name);
1198 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
1199 PATH_COMPONENT: foreach $component (File::Spec->path(),
1200 $Config::Config{'binexp'}) {
1201 next unless defined($component) && $component;
1202 my($abs) = File::Spec->catfile($component,$perl_name);
1203 if (MM->maybe_command($abs)) {
1215 #-> sub CPAN::exists ;
1217 my($mgr,$class,$id) = @_;
1218 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1219 CPAN::Index->reload;
1220 ### Carp::croak "exists called without class argument" unless $class;
1222 $id =~ s/:+/::/g if $class eq "CPAN::Module";
1224 if (CPAN::_sqlite_running) {
1225 $exists = (exists $META->{readonly}{$class}{$id} or
1226 $CPAN::SQLite->set($class, $id));
1228 $exists = exists $META->{readonly}{$class}{$id};
1230 $exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1233 #-> sub CPAN::delete ;
1235 my($mgr,$class,$id) = @_;
1236 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
1237 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1240 #-> sub CPAN::has_usable
1241 # has_inst is sometimes too optimistic, we should replace it with this
1242 # has_usable whenever a case is given
1244 my($self,$mod,$message) = @_;
1245 return 1 if $HAS_USABLE->{$mod};
1246 my $has_inst = $self->has_inst($mod,$message);
1247 return unless $has_inst;
1250 LWP => [ # we frequently had "Can't locate object
1251 # method "new" via package "LWP::UserAgent" at
1252 # (eval 69) line 2006
1254 sub {require LWP::UserAgent},
1255 sub {require HTTP::Request},
1256 sub {require URI::URL},
1259 sub {require Net::FTP},
1260 sub {require Net::Config},
1262 'File::HomeDir' => [
1263 sub {require File::HomeDir;
1264 unless (CPAN::Version->vge(File::HomeDir::->VERSION, 0.52)) {
1265 for ("Will not use File::HomeDir, need 0.52\n") {
1266 $CPAN::Frontend->mywarn($_);
1273 sub {require Archive::Tar;
1274 unless (CPAN::Version->vge(Archive::Tar::->VERSION, 1.00)) {
1275 for ("Will not use Archive::Tar, need 1.00\n") {
1276 $CPAN::Frontend->mywarn($_);
1283 # XXX we should probably delete from
1284 # %INC too so we can load after we
1285 # installed a new enough version --
1287 sub {require File::Temp;
1288 unless (CPAN::Version->vge(File::Temp::->VERSION,0.16)) {
1289 for ("Will not use File::Temp, need 0.16\n") {
1290 $CPAN::Frontend->mywarn($_);
1297 if ($usable->{$mod}) {
1298 for my $c (0..$#{$usable->{$mod}}) {
1299 my $code = $usable->{$mod}[$c];
1300 my $ret = eval { &$code() };
1301 $ret = "" unless defined $ret;
1303 # warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
1308 return $HAS_USABLE->{$mod} = 1;
1311 #-> sub CPAN::has_inst
1313 my($self,$mod,$message) = @_;
1314 Carp::croak("CPAN->has_inst() called without an argument")
1315 unless defined $mod;
1316 my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
1317 keys %{$CPAN::Config->{dontload_hash}||{}},
1318 @{$CPAN::Config->{dontload_list}||[]};
1319 if (defined $message && $message eq "no" # afair only used by Nox
1323 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
1331 # checking %INC is wrong, because $INC{LWP} may be true
1332 # although $INC{"URI/URL.pm"} may have failed. But as
1333 # I really want to say "bla loaded OK", I have to somehow
1335 ### warn "$file in %INC"; #debug
1337 } elsif (eval { require $file }) {
1338 # eval is good: if we haven't yet read the database it's
1339 # perfect and if we have installed the module in the meantime,
1340 # it tries again. The second require is only a NOOP returning
1341 # 1 if we had success, otherwise it's retrying
1343 my $mtime = (stat $INC{$file})[9];
1344 # privileged files loaded by has_inst; Note: we use $mtime
1345 # as a proxy for a checksum.
1346 $CPAN::Shell::reload->{$file} = $mtime;
1347 my $v = eval "\$$mod\::VERSION";
1348 $v = $v ? " (v$v)" : "";
1349 CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
1350 if ($mod eq "CPAN::WAIT") {
1351 push @CPAN::Shell::ISA, 'CPAN::WAIT';
1354 } elsif ($mod eq "Net::FTP") {
1355 $CPAN::Frontend->mywarn(qq{
1356 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
1358 install Bundle::libnet
1360 }) unless $Have_warned->{"Net::FTP"}++;
1361 $CPAN::Frontend->mysleep(3);
1362 } elsif ($mod eq "Digest::SHA") {
1363 if ($Have_warned->{"Digest::SHA"}++) {
1364 $CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
1365 qq{because Digest::SHA not installed.\n});
1367 $CPAN::Frontend->mywarn(qq{
1368 CPAN: checksum security checks disabled because Digest::SHA not installed.
1369 Please consider installing the Digest::SHA module.
1372 $CPAN::Frontend->mysleep(2);
1374 } elsif ($mod eq "Module::Signature") {
1375 # NOT prefs_lookup, we are not a distro
1376 my $check_sigs = $CPAN::Config->{check_sigs};
1377 if (not $check_sigs) {
1378 # they do not want us:-(
1379 } elsif (not $Have_warned->{"Module::Signature"}++) {
1380 # No point in complaining unless the user can
1381 # reasonably install and use it.
1382 if (eval { require Crypt::OpenPGP; 1 } ||
1384 defined $CPAN::Config->{'gpg'}
1386 $CPAN::Config->{'gpg'} =~ /\S/
1389 $CPAN::Frontend->mywarn(qq{
1390 CPAN: Module::Signature security checks disabled because Module::Signature
1391 not installed. Please consider installing the Module::Signature module.
1392 You may also need to be able to connect over the Internet to the public
1393 keyservers like pgp.mit.edu (port 11371).
1396 $CPAN::Frontend->mysleep(2);
1400 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
1405 #-> sub CPAN::instance ;
1407 my($mgr,$class,$id) = @_;
1408 CPAN::Index->reload;
1410 # unsafe meta access, ok?
1411 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
1412 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
1420 #-> sub CPAN::cleanup ;
1422 # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
1423 local $SIG{__DIE__} = '';
1428 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
1429 $ineval = 1, last if
1430 $subroutine eq '(eval)';
1432 return if $ineval && !$CPAN::End;
1433 return unless defined $META->{LOCK};
1434 return unless -f $META->{LOCK};
1436 close $META->{LOCKFH};
1437 unlink $META->{LOCK};
1439 # Carp::cluck("DEBUGGING");
1440 if ( $CPAN::CONFIG_DIRTY ) {
1441 $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
1443 $CPAN::Frontend->myprint("Lockfile removed.\n");
1446 #-> sub CPAN::readhist
1448 my($self,$term,$histfile) = @_;
1449 my($fh) = FileHandle->new;
1450 open $fh, "<$histfile" or last;
1454 $term->AddHistory($_);
1459 #-> sub CPAN::savehist
1462 my($histfile,$histsize);
1463 unless ($histfile = $CPAN::Config->{'histfile'}) {
1464 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
1467 $histsize = $CPAN::Config->{'histsize'} || 100;
1469 unless ($CPAN::term->can("GetHistory")) {
1470 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
1476 my @h = $CPAN::term->GetHistory;
1477 splice @h, 0, @h-$histsize if @h>$histsize;
1478 my($fh) = FileHandle->new;
1479 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
1480 local $\ = local $, = "\n";
1485 #-> sub CPAN::is_tested
1487 my($self,$what,$when) = @_;
1489 Carp::cluck("DEBUG: empty what");
1492 $self->{is_tested}{$what} = $when;
1495 #-> sub CPAN::is_installed
1496 # unsets the is_tested flag: as soon as the thing is installed, it is
1497 # not needed in set_perl5lib anymore
1499 my($self,$what) = @_;
1500 delete $self->{is_tested}{$what};
1503 sub _list_sorted_descending_is_tested {
1506 { ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
1507 keys %{$self->{is_tested}}
1510 #-> sub CPAN::set_perl5lib
1512 my($self,$for) = @_;
1514 (undef,undef,undef,$for) = caller(1);
1517 $self->{is_tested} ||= {};
1518 return unless %{$self->{is_tested}};
1519 my $env = $ENV{PERL5LIB};
1520 $env = $ENV{PERLLIB} unless defined $env;
1522 push @env, $env if defined $env and length $env;
1523 #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
1524 #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
1526 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
1528 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB for '$for'\n");
1529 } elsif (@dirs < 24) {
1530 my @d = map {my $cp = $_;
1531 $cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
1534 $CPAN::Frontend->myprint("Prepending @d to PERL5LIB; ".
1535 "%BUILDDIR%=$CPAN::Config->{build_dir} ".
1539 my $cnt = keys %{$self->{is_tested}};
1540 $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib of ".
1541 "$cnt build dirs to PERL5LIB; ".
1546 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
1549 package CPAN::CacheMgr;
1552 #-> sub CPAN::CacheMgr::as_string ;
1554 eval { require Data::Dumper };
1556 return shift->SUPER::as_string;
1558 return Data::Dumper::Dumper(shift);
1562 #-> sub CPAN::CacheMgr::cachesize ;
1567 #-> sub CPAN::CacheMgr::tidyup ;
1570 return unless $CPAN::META->{LOCK};
1571 return unless -d $self->{ID};
1572 my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
1573 for my $current (0..$#toremove) {
1574 my $toremove = $toremove[$current];
1575 $CPAN::Frontend->myprint(sprintf(
1576 "DEL(%d/%d): %s \n",
1582 return if $CPAN::Signal;
1583 $self->_clean_cache($toremove);
1584 return if $CPAN::Signal;
1588 #-> sub CPAN::CacheMgr::dir ;
1593 #-> sub CPAN::CacheMgr::entries ;
1595 my($self,$dir) = @_;
1596 return unless defined $dir;
1597 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
1598 $dir ||= $self->{ID};
1599 my($cwd) = CPAN::anycwd();
1600 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
1601 my $dh = DirHandle->new(File::Spec->curdir)
1602 or Carp::croak("Couldn't opendir $dir: $!");
1605 next if $_ eq "." || $_ eq "..";
1607 push @entries, File::Spec->catfile($dir,$_);
1609 push @entries, File::Spec->catdir($dir,$_);
1611 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
1614 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
1615 sort { -M $a <=> -M $b} @entries;
1618 #-> sub CPAN::CacheMgr::disk_usage ;
1620 my($self,$dir,$fast) = @_;
1621 return if exists $self->{SIZE}{$dir};
1622 return if $CPAN::Signal;
1627 unless (chmod 0755, $dir) {
1628 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
1629 "permission to change the permission; cannot ".
1630 "estimate disk usage of '$dir'\n");
1631 $CPAN::Frontend->mysleep(5);
1636 # nothing to say, no matter what the permissions
1639 $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
1643 $Du = 0; # placeholder
1647 $File::Find::prune++ if $CPAN::Signal;
1649 if ($^O eq 'MacOS') {
1651 my $cat = Mac::Files::FSpGetCatInfo($_);
1652 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
1656 unless (chmod 0755, $_) {
1657 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
1658 "the permission to change the permission; ".
1659 "can only partially estimate disk usage ".
1661 $CPAN::Frontend->mysleep(5);
1673 return if $CPAN::Signal;
1674 $self->{SIZE}{$dir} = $Du/1024/1024;
1675 unshift @{$self->{FIFO}}, $dir;
1676 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
1677 $self->{DU} += $Du/1024/1024;
1681 #-> sub CPAN::CacheMgr::_clean_cache ;
1683 my($self,$dir) = @_;
1684 return unless -e $dir;
1685 unless (File::Spec->canonpath(File::Basename::dirname($dir))
1686 eq File::Spec->canonpath($CPAN::Config->{build_dir})) {
1687 $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
1688 "will not remove\n");
1689 $CPAN::Frontend->mysleep(5);
1692 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
1694 File::Path::rmtree($dir);
1696 if ($dir !~ /\.yml$/ && -f "$dir.yml") {
1697 my $yaml_module = CPAN::_yaml_module;
1698 if ($CPAN::META->has_inst($yaml_module)) {
1699 my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
1701 $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
1702 unlink "$dir.yml" or
1703 $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
1705 } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
1706 $CPAN::META->delete("CPAN::Distribution", $id);
1708 # XXX we should restore the state NOW, otherise this
1709 # distro does not exist until we read an index. BUG ALERT(?)
1711 # $CPAN::Frontend->mywarn (" +++\n");
1715 unlink "$dir.yml"; # may fail
1716 unless ($id_deleted) {
1717 CPAN->debug("no distro found associated with '$dir'");
1720 $self->{DU} -= $self->{SIZE}{$dir};
1721 delete $self->{SIZE}{$dir};
1724 #-> sub CPAN::CacheMgr::new ;
1731 ID => $CPAN::Config->{build_dir},
1732 MAX => $CPAN::Config->{'build_cache'},
1733 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
1736 File::Path::mkpath($self->{ID});
1737 my $dh = DirHandle->new($self->{ID});
1738 bless $self, $class;
1741 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
1743 CPAN->debug($debug) if $CPAN::DEBUG;
1747 #-> sub CPAN::CacheMgr::scan_cache ;
1750 return if $self->{SCAN} eq 'never';
1751 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1752 unless $self->{SCAN} eq 'atstart';
1753 return unless $CPAN::META->{LOCK};
1754 $CPAN::Frontend->myprint(
1755 sprintf("Scanning cache %s for sizes\n",
1758 my @entries = $self->entries($self->{ID});
1763 if ($self->{DU} > $self->{MAX}) {
1765 $self->disk_usage($e,1);
1767 $self->disk_usage($e);
1770 while (($painted/76) < ($i/@entries)) {
1771 $CPAN::Frontend->myprint($symbol);
1774 return if $CPAN::Signal;
1776 $CPAN::Frontend->myprint("DONE\n");
1780 package CPAN::Shell;
1783 #-> sub CPAN::Shell::h ;
1785 my($class,$about) = @_;
1786 if (defined $about) {
1788 if (exists $Help->{$about}) {
1789 if (ref $Help->{$about}) { # aliases
1790 $about = ${$Help->{$about}};
1792 $help = $Help->{$about};
1794 $help = "No help available";
1796 $CPAN::Frontend->myprint("$about\: $help\n");
1798 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
1799 $CPAN::Frontend->myprint(qq{
1800 Display Information $filler (ver $CPAN::VERSION)
1801 command argument description
1802 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1803 i WORD or /REGEXP/ about any of the above
1804 ls AUTHOR or GLOB about files in the author's directory
1805 (with WORD being a module, bundle or author name or a distribution
1806 name of the form AUTHOR/DISTRIBUTION)
1808 Download, Test, Make, Install...
1809 get download clean make clean
1810 make make (implies get) look open subshell in dist directory
1811 test make test (implies make) readme display these README files
1812 install make install (implies test) perldoc display POD documentation
1815 r WORDs or /REGEXP/ or NONE report updates for some/matching/all modules
1816 upgrade WORDs or /REGEXP/ or NONE upgrade some/matching/all modules
1819 force CMD try hard to do command fforce CMD try harder
1820 notest CMD skip testing
1823 h,? display this menu ! perl-code eval a perl command
1824 o conf [opt] set and query options q quit the cpan shell
1825 reload cpan load CPAN.pm again reload index load newer indices
1826 autobundle Snapshot recent latest CPAN uploads});
1832 #-> sub CPAN::Shell::a ;
1834 my($self,@arg) = @_;
1835 # authors are always UPPERCASE
1837 $_ = uc $_ unless /=/;
1839 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1842 #-> sub CPAN::Shell::globls ;
1844 my($self,$s,$pragmas) = @_;
1845 # ls is really very different, but we had it once as an ordinary
1846 # command in the Shell (upto rev. 321) and we could not handle
1848 my(@accept,@preexpand);
1849 if ($s =~ /[\*\?\/]/) {
1850 if ($CPAN::META->has_inst("Text::Glob")) {
1851 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
1852 my $rau = Text::Glob::glob_to_regex(uc $au);
1853 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
1855 push @preexpand, map { $_->id . "/" . $pathglob }
1856 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
1858 my $rau = Text::Glob::glob_to_regex(uc $s);
1859 push @preexpand, map { $_->id }
1860 CPAN::Shell->expand_by_method('CPAN::Author',
1865 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
1868 push @preexpand, uc $s;
1871 unless (/^[A-Z0-9\-]+(\/|$)/i) {
1872 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1877 my $silent = @accept>1;
1878 my $last_alpha = "";
1880 for my $a (@accept) {
1881 my($author,$pathglob);
1882 if ($a =~ m|(.*?)/(.*)|) {
1885 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1888 or $CPAN::Frontend->mydie("No author found for $a2\n");
1890 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1893 or $CPAN::Frontend->mydie("No author found for $a\n");
1896 my $alpha = substr $author->id, 0, 1;
1898 if ($alpha eq $last_alpha) {
1902 $last_alpha = $alpha;
1904 $CPAN::Frontend->myprint($ad);
1906 for my $pragma (@$pragmas) {
1907 if ($author->can($pragma)) {
1911 push @results, $author->ls($pathglob,$silent); # silent if
1914 for my $pragma (@$pragmas) {
1915 my $unpragma = "un$pragma";
1916 if ($author->can($unpragma)) {
1917 $author->$unpragma();
1924 #-> sub CPAN::Shell::local_bundles ;
1926 my($self,@which) = @_;
1927 my($incdir,$bdir,$dh);
1928 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1929 my @bbase = "Bundle";
1930 while (my $bbase = shift @bbase) {
1931 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1932 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1933 if ($dh = DirHandle->new($bdir)) { # may fail
1935 for $entry ($dh->read) {
1936 next if $entry =~ /^\./;
1937 next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
1938 if (-d File::Spec->catdir($bdir,$entry)) {
1939 push @bbase, "$bbase\::$entry";
1941 next unless $entry =~ s/\.pm(?!\n)\Z//;
1942 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1950 #-> sub CPAN::Shell::b ;
1952 my($self,@which) = @_;
1953 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1954 $self->local_bundles;
1955 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1958 #-> sub CPAN::Shell::d ;
1959 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1961 #-> sub CPAN::Shell::m ;
1962 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1964 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1967 #-> sub CPAN::Shell::i ;
1971 @args = '/./' unless @args;
1973 for my $type (qw/Bundle Distribution Module/) {
1974 push @result, $self->expand($type,@args);
1976 # Authors are always uppercase.
1977 push @result, $self->expand("Author", map { uc $_ } @args);
1979 my $result = @result == 1 ?
1980 $result[0]->as_string :
1982 "No objects found of any type for argument @args\n" :
1984 (map {$_->as_glimpse} @result),
1985 scalar @result, " items found\n",
1987 $CPAN::Frontend->myprint($result);
1990 #-> sub CPAN::Shell::o ;
1992 # CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o
1993 # conf' calls through to CPAN::HandleConfig::edit. 'o conf' should
1994 # probably have been called 'set' and 'o debug' maybe 'set debug' or
1995 # 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
1997 my($self,$o_type,@o_what) = @_;
1999 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
2000 if ($o_type eq 'conf') {
2002 ($cfilter) = $o_what[0] =~ m|^/(.*)/$| if @o_what;
2003 if (!@o_what or $cfilter) { # print all things, "o conf"
2005 my $qrfilter = eval 'qr/$cfilter/';
2007 $CPAN::Frontend->myprint("\$CPAN::Config options from ");
2009 if (exists $INC{'CPAN/Config.pm'}) {
2010 push @from, $INC{'CPAN/Config.pm'};
2012 if (exists $INC{'CPAN/MyConfig.pm'}) {
2013 push @from, $INC{'CPAN/MyConfig.pm'};
2015 $CPAN::Frontend->myprint(join " and ", map {"'$_'"} @from);
2016 $CPAN::Frontend->myprint(":\n");
2017 for $k (sort keys %CPAN::HandleConfig::can) {
2018 next unless $k =~ /$qrfilter/;
2019 $v = $CPAN::HandleConfig::can{$k};
2020 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
2022 $CPAN::Frontend->myprint("\n");
2023 for $k (sort keys %CPAN::HandleConfig::keys) {
2024 next unless $k =~ /$qrfilter/;
2025 CPAN::HandleConfig->prettyprint($k);
2027 $CPAN::Frontend->myprint("\n");
2029 if (CPAN::HandleConfig->edit(@o_what)) {
2031 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
2035 } elsif ($o_type eq 'debug') {
2037 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
2040 my($what) = shift @o_what;
2041 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
2042 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
2045 if ( exists $CPAN::DEBUG{$what} ) {
2046 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
2047 } elsif ($what =~ /^\d/) {
2048 $CPAN::DEBUG = $what;
2049 } elsif (lc $what eq 'all') {
2051 for (values %CPAN::DEBUG) {
2054 $CPAN::DEBUG = $max;
2057 for (keys %CPAN::DEBUG) {
2058 next unless lc($_) eq lc($what);
2059 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
2062 $CPAN::Frontend->myprint("unknown argument [$what]\n")
2067 my $raw = "Valid options for debug are ".
2068 join(", ",sort(keys %CPAN::DEBUG), 'all').
2069 qq{ or a number. Completion works on the options. }.
2070 qq{Case is ignored.};
2072 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
2073 $CPAN::Frontend->myprint("\n\n");
2076 $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n");
2078 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
2079 $v = $CPAN::DEBUG{$k};
2080 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
2081 if $v & $CPAN::DEBUG;
2084 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
2087 $CPAN::Frontend->myprint(qq{
2089 conf set or get configuration variables
2090 debug set or get debugging options
2095 # CPAN::Shell::paintdots_onreload
2096 sub paintdots_onreload {
2099 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
2103 # $CPAN::Frontend->myprint(".($subr)");
2104 $CPAN::Frontend->myprint(".");
2105 if ($subr =~ /\bshell\b/i) {
2106 # warn "debug[$_[0]]";
2108 # It would be nice if we could detect that a
2109 # subroutine has actually changed, but for now we
2110 # practically always set the GOTOSHELL global
2120 #-> sub CPAN::Shell::hosts ;
2123 my $fullstats = CPAN::FTP->_ftp_statistics();
2124 my $history = $fullstats->{history} || [];
2126 while (my $last = pop @$history) {
2127 my $attempts = $last->{attempts} or next;
2130 $start = $attempts->[-1]{start};
2131 if ($#$attempts > 0) {
2132 for my $i (0..$#$attempts-1) {
2133 my $url = $attempts->[$i]{url} or next;
2138 $start = $last->{start};
2140 next unless $last->{thesiteurl}; # C-C? bad filenames?
2142 $S{end} ||= $last->{end};
2143 my $dltime = $last->{end} - $start;
2144 my $dlsize = $last->{filesize} || 0;
2145 my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
2146 my $s = $S{ok}{$url} ||= {};
2149 $s->{dlsize} += $dlsize/1024;
2151 $s->{dltime} += $dltime;
2154 for my $url (keys %{$S{ok}}) {
2155 next if $S{ok}{$url}{dltime} == 0; # div by zero
2156 push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)},
2157 $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime},
2161 for my $url (keys %{$S{no}}) {
2162 push @{$res->{no}}, [$S{no}{$url},
2166 my $R = ""; # report
2167 if ($S{start} && $S{end}) {
2168 $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown";
2169 $R .= sprintf "Log ends : %s\n", $S{end} ? scalar(localtime $S{end}) : "unknown";
2171 if ($res->{ok} && @{$res->{ok}}) {
2172 $R .= sprintf "\nSuccessful downloads:
2173 N kB secs kB/s url\n";
2175 for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) {
2176 $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_;
2180 if ($res->{no} && @{$res->{no}}) {
2181 $R .= sprintf "\nUnsuccessful downloads:\n";
2183 for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) {
2184 $R .= sprintf "%4d %s\n", @$_;
2188 $CPAN::Frontend->myprint($R);
2191 #-> sub CPAN::Shell::reload ;
2193 my($self,$command,@arg) = @_;
2195 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
2196 if ($command =~ /^cpan$/i) {
2198 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
2203 "CPAN/FirstTime.pm",
2204 "CPAN/HandleConfig.pm",
2207 "CPAN/Reporter/Config.pm",
2208 "CPAN/Reporter/History.pm",
2214 MFILE: for my $f (@relo) {
2215 next unless exists $INC{$f};
2219 $CPAN::Frontend->myprint("($p");
2220 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
2221 $self->_reload_this($f) or $failed++;
2222 my $v = eval "$p\::->VERSION";
2223 $CPAN::Frontend->myprint("v$v)");
2225 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
2227 my $errors = $failed == 1 ? "error" : "errors";
2228 $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ".
2231 } elsif ($command =~ /^index$/i) {
2232 CPAN::Index->force_reload;
2234 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN modules
2235 index re-reads the index files\n});
2239 # reload means only load again what we have loaded before
2240 #-> sub CPAN::Shell::_reload_this ;
2242 my($self,$f,$args) = @_;
2243 CPAN->debug("f[$f]") if $CPAN::DEBUG;
2244 return 1 unless $INC{$f}; # we never loaded this, so we do not
2246 my $pwd = CPAN::anycwd();
2247 CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG;
2249 for my $inc (@INC) {
2250 $file = File::Spec->catfile($inc,split /\//, $f);
2254 CPAN->debug("file[$file]") if $CPAN::DEBUG;
2256 unless ($file && -f $file) {
2257 # this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
2259 unless (CPAN->has_inst("File::Basename")) {
2260 @inc = File::Basename::dirname($file);
2262 # do we ever need this?
2263 @inc = substr($file,0,-length($f)-1); # bring in back to me!
2266 CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
2268 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
2271 my $mtime = (stat $file)[9];
2272 if ($reload->{$f}) {
2273 } elsif ($^T < $mtime) {
2274 # since we started the file has changed, force it to be reloaded
2277 $reload->{$f} = $mtime;
2279 my $must_reload = $mtime != $reload->{$f};
2281 $must_reload ||= $args->{reloforce}; # o conf defaults needs this
2283 my $fh = FileHandle->new($file) or
2284 $CPAN::Frontend->mydie("Could not open $file: $!");
2287 my $content = <$fh>;
2288 CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128)))
2292 eval "require '$f'";
2297 $reload->{$f} = $mtime;
2299 $CPAN::Frontend->myprint("__unchanged__");
2304 #-> sub CPAN::Shell::mkmyconfig ;
2306 my($self, $cpanpm, %args) = @_;
2307 require CPAN::FirstTime;
2308 my $home = CPAN::HandleConfig::home;
2309 $cpanpm = $INC{'CPAN/MyConfig.pm'} ||
2310 File::Spec->catfile(split /\//, "$home/.cpan/CPAN/MyConfig.pm");
2311 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
2312 CPAN::HandleConfig::require_myconfig_or_config;
2313 $CPAN::Config ||= {};
2318 keep_source_where => undef,
2321 CPAN::FirstTime::init($cpanpm, %args);
2324 #-> sub CPAN::Shell::_binary_extensions ;
2325 sub _binary_extensions {
2326 my($self) = shift @_;
2327 my(@result,$module,%seen,%need,$headerdone);
2328 for $module ($self->expand('Module','/./')) {
2329 my $file = $module->cpan_file;
2330 next if $file eq "N/A";
2331 next if $file =~ /^Contact Author/;
2332 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
2333 next if $dist->isa_perl;
2334 next unless $module->xs_file;
2336 $CPAN::Frontend->myprint(".");
2337 push @result, $module;
2339 # print join " | ", @result;
2340 $CPAN::Frontend->myprint("\n");
2344 #-> sub CPAN::Shell::recompile ;
2346 my($self) = shift @_;
2347 my($module,@module,$cpan_file,%dist);
2348 @module = $self->_binary_extensions();
2349 for $module (@module) { # we force now and compile later, so we
2351 $cpan_file = $module->cpan_file;
2352 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2354 $dist{$cpan_file}++;
2356 for $cpan_file (sort keys %dist) {
2357 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
2358 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2360 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
2361 # stop a package from recompiling,
2362 # e.g. IO-1.12 when we have perl5.003_10
2366 #-> sub CPAN::Shell::scripts ;
2368 my($self, $arg) = @_;
2369 $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n");
2371 for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) {
2372 unless ($CPAN::META->has_inst($req)) {
2373 $CPAN::Frontend->mywarn(" $req not available\n");
2376 my $p = HTML::LinkExtor->new();
2377 my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html";
2378 unless (-f $indexfile) {
2379 $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n");
2381 $p->parse_file($indexfile);
2384 if ($arg =~ s|^/(.+)/$|$1|) {
2385 $qrarg = eval 'qr/$arg/'; # hide construct from 5.004
2387 for my $l ($p->links) {
2388 my $tag = shift @$l;
2389 next unless $tag eq "a";
2391 my $href = $att{href};
2392 next unless $href =~ s|^\.\./authors/id/./../||;
2395 if ($href =~ $qrarg) {
2399 if ($href =~ /\Q$arg\E/) {
2407 # now filter for the latest version if there is more than one of a name
2413 $stems{$stem} ||= [];
2414 push @{$stems{$stem}}, $href;
2416 for (sort keys %stems) {
2418 if (@{$stems{$_}} > 1) {
2419 $highest = List::Util::reduce {
2420 Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b
2423 $highest = $stems{$_}[0];
2425 $CPAN::Frontend->myprint("$highest\n");
2429 #-> sub CPAN::Shell::report ;
2431 my($self,@args) = @_;
2432 unless ($CPAN::META->has_inst("CPAN::Reporter")) {
2433 $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
2435 local $CPAN::Config->{test_report} = 1;
2436 $self->force("test",@args); # force is there so that the test be
2437 # re-run (as documented)
2440 # compare with is_tested
2441 #-> sub CPAN::Shell::install_tested
2442 sub install_tested {
2443 my($self,@some) = @_;
2444 $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"),
2446 CPAN::Index->reload;
2448 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2449 my $yaml = "$b.yml";
2451 $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
2454 my $yaml_content = CPAN->_yaml_loadfile($yaml);
2455 my $id = $yaml_content->[0]{distribution}{ID};
2457 $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
2460 my $do = CPAN::Shell->expandany($id);
2462 $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n");
2465 unless ($do->{build_dir}) {
2466 $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n");
2469 unless ($do->{build_dir} eq $b) {
2470 $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n");
2476 $CPAN::Frontend->mywarn("No tested distributions found.\n"),
2477 return unless @some;
2479 @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some;
2480 $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"),
2481 return unless @some;
2483 # @some = grep { not $_->uptodate } @some;
2484 # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"),
2485 # return unless @some;
2487 CPAN->debug("some[@some]");
2489 my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id;
2490 $CPAN::Frontend->myprint("install_tested: Running for $id\n");
2491 $CPAN::Frontend->mysleep(1);
2496 #-> sub CPAN::Shell::upgrade ;
2498 my($self,@args) = @_;
2499 $self->install($self->r(@args));
2502 #-> sub CPAN::Shell::_u_r_common ;
2504 my($self) = shift @_;
2505 my($what) = shift @_;
2506 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
2507 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
2508 $what && $what =~ /^[aru]$/;
2510 @args = '/./' unless @args;
2511 my(@result,$module,%seen,%need,$headerdone,
2512 $version_undefs,$version_zeroes,
2513 @version_undefs,@version_zeroes);
2514 $version_undefs = $version_zeroes = 0;
2515 my $sprintf = "%s%-25s%s %9s %9s %s\n";
2516 my @expand = $self->expand('Module',@args);
2517 my $expand = scalar @expand;
2518 if (0) { # Looks like noise to me, was very useful for debugging
2519 # for metadata cache
2520 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
2522 MODULE: for $module (@expand) {
2523 my $file = $module->cpan_file;
2524 next MODULE unless defined $file; # ??
2525 $file =~ s!^./../!!;
2526 my($latest) = $module->cpan_version;
2527 my($inst_file) = $module->inst_file;
2529 return if $CPAN::Signal;
2532 $have = $module->inst_version;
2533 } elsif ($what eq "r") {
2534 $have = $module->inst_version;
2536 if ($have eq "undef") {
2538 push @version_undefs, $module->as_glimpse;
2539 } elsif (CPAN::Version->vcmp($have,0)==0) {
2541 push @version_zeroes, $module->as_glimpse;
2543 next MODULE unless CPAN::Version->vgt($latest, $have);
2544 # to be pedantic we should probably say:
2545 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
2546 # to catch the case where CPAN has a version 0 and we have a version undef
2547 } elsif ($what eq "u") {
2553 } elsif ($what eq "r") {
2555 } elsif ($what eq "u") {
2559 return if $CPAN::Signal; # this is sometimes lengthy
2562 push @result, sprintf "%s %s\n", $module->id, $have;
2563 } elsif ($what eq "r") {
2564 push @result, $module->id;
2565 next MODULE if $seen{$file}++;
2566 } elsif ($what eq "u") {
2567 push @result, $module->id;
2568 next MODULE if $seen{$file}++;
2569 next MODULE if $file =~ /^Contact/;
2571 unless ($headerdone++) {
2572 $CPAN::Frontend->myprint("\n");
2573 $CPAN::Frontend->myprint(sprintf(
2576 "Package namespace",
2588 $CPAN::META->has_inst("Term::ANSIColor")
2590 $module->description
2592 $color_on = Term::ANSIColor::color("green");
2593 $color_off = Term::ANSIColor::color("reset");
2595 $CPAN::Frontend->myprint(sprintf $sprintf,
2602 $need{$module->id}++;
2606 $CPAN::Frontend->myprint("No modules found for @args\n");
2607 } elsif ($what eq "r") {
2608 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
2612 if ($version_zeroes) {
2613 my $s_has = $version_zeroes > 1 ? "s have" : " has";
2614 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
2615 qq{a version number of 0\n});
2616 if ($CPAN::Config->{show_zero_versions}) {
2618 $CPAN::Frontend->myprint(qq{ they are\n\t@version_zeroes\n});
2619 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }.
2620 qq{to hide them)\n});
2622 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }.
2623 qq{to show them)\n});
2626 if ($version_undefs) {
2627 my $s_has = $version_undefs > 1 ? "s have" : " has";
2628 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
2629 qq{parseable version number\n});
2630 if ($CPAN::Config->{show_unparsable_versions}) {
2632 $CPAN::Frontend->myprint(qq{ they are\n\t@version_undefs\n});
2633 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }.
2634 qq{to hide them)\n});
2636 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }.
2637 qq{to show them)\n});
2644 #-> sub CPAN::Shell::r ;
2646 shift->_u_r_common("r",@_);
2649 #-> sub CPAN::Shell::u ;
2651 shift->_u_r_common("u",@_);
2654 #-> sub CPAN::Shell::failed ;
2656 my($self,$only_id,$silent) = @_;
2658 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
2660 NAY: for my $nosayer ( # order matters!
2669 next unless exists $d->{$nosayer};
2670 next unless defined $d->{$nosayer};
2672 UNIVERSAL::can($d->{$nosayer},"failed") ?
2673 $d->{$nosayer}->failed :
2674 $d->{$nosayer} =~ /^NO/
2676 next NAY if $only_id && $only_id != (
2677 UNIVERSAL::can($d->{$nosayer},"commandid")
2679 $d->{$nosayer}->commandid
2681 $CPAN::CurrentCommandId
2686 next DIST unless $failed;
2690 # " %-45s: %s %s\n",
2693 UNIVERSAL::can($d->{$failed},"failed") ?
2695 $d->{$failed}->commandid,
2698 $d->{$failed}->text,
2699 $d->{$failed}{TIME}||0,
2712 $scope = "this command";
2713 } elsif ($CPAN::Index::HAVE_REANIMATED) {
2714 $scope = "this or a previous session";
2715 # it might be nice to have a section for previous session and
2718 $scope = "this session";
2725 map { sprintf "%5d %-45s: %s %s\n", @$_ }
2726 sort { $a->[0] <=> $b->[0] } @failed;
2729 map { sprintf " %-45s: %s %s\n", @$_[1..3] }
2736 $CPAN::Frontend->myprint("Failed during $scope:\n$print");
2737 } elsif (!$only_id || !$silent) {
2738 $CPAN::Frontend->myprint("Nothing failed in $scope\n");
2742 # XXX intentionally undocumented because completely bogus, unportable,
2745 #-> sub CPAN::Shell::status ;
2748 require Devel::Size;
2749 my $ps = FileHandle->new;
2750 open $ps, "/proc/$$/status";
2753 next unless /VmSize:\s+(\d+)/;
2757 $CPAN::Frontend->mywarn(sprintf(
2758 "%-27s %6d\n%-27s %6d\n",
2762 Devel::Size::total_size($CPAN::META)/1024,
2764 for my $k (sort keys %$CPAN::META) {
2765 next unless substr($k,0,4) eq "read";
2766 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
2767 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
2768 warn sprintf " %-25s %6d (keys: %6d)\n",
2770 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
2771 scalar keys %{$CPAN::META->{$k}{$k2}};
2776 # compare with install_tested
2777 #-> sub CPAN::Shell::is_tested
2780 CPAN::Index->reload;
2781 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2783 if ($CPAN::META->{is_tested}{$b}) {
2784 $time = scalar(localtime $CPAN::META->{is_tested}{$b});
2786 $time = scalar localtime;
2789 $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b);
2793 #-> sub CPAN::Shell::autobundle ;
2796 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
2797 my(@bundle) = $self->_u_r_common("a",@_);
2798 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
2799 File::Path::mkpath($todir);
2800 unless (-d $todir) {
2801 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
2804 my($y,$m,$d) = (localtime)[5,4,3];
2808 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
2809 my($to) = File::Spec->catfile($todir,"$me.pm");
2811 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
2812 $to = File::Spec->catfile($todir,"$me.pm");
2814 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
2816 "package Bundle::$me;\n\n",
2817 "\$VERSION = '0.01';\n\n",
2821 "Bundle::$me - Snapshot of installation on ",
2822 $Config::Config{'myhostname'},
2825 "\n\n=head1 SYNOPSIS\n\n",
2826 "perl -MCPAN -e 'install Bundle::$me'\n\n",
2827 "=head1 CONTENTS\n\n",
2828 join("\n", @bundle),
2829 "\n\n=head1 CONFIGURATION\n\n",
2831 "\n\n=head1 AUTHOR\n\n",
2832 "This Bundle has been generated automatically ",
2833 "by the autobundle routine in CPAN.pm.\n",
2836 $CPAN::Frontend->myprint("\nWrote bundle file
2840 #-> sub CPAN::Shell::expandany ;
2843 CPAN->debug("s[$s]") if $CPAN::DEBUG;
2844 if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
2845 $s = CPAN::Distribution->normalize($s);
2846 return $CPAN::META->instance('CPAN::Distribution',$s);
2847 # Distributions spring into existence, not expand
2848 } elsif ($s =~ m|^Bundle::|) {
2849 $self->local_bundles; # scanning so late for bundles seems
2850 # both attractive and crumpy: always
2851 # current state but easy to forget
2853 return $self->expand('Bundle',$s);
2855 return $self->expand('Module',$s)
2856 if $CPAN::META->exists('CPAN::Module',$s);
2861 #-> sub CPAN::Shell::expand ;
2864 my($type,@args) = @_;
2865 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
2866 my $class = "CPAN::$type";
2867 my $methods = ['id'];
2868 for my $meth (qw(name)) {
2869 next unless $class->can($meth);
2870 push @$methods, $meth;
2872 $self->expand_by_method($class,$methods,@args);
2875 #-> sub CPAN::Shell::expand_by_method ;
2876 sub expand_by_method {
2878 my($class,$methods,@args) = @_;
2881 my($regex,$command);
2882 if ($arg =~ m|^/(.*)/$|) {
2884 # FIXME: there seem to be some ='s in the author data, which trigger
2885 # a failure here. This needs to be contemplated.
2886 # } elsif ($arg =~ m/=/) {
2890 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
2892 defined $regex ? $regex : "UNDEFINED",
2893 defined $command ? $command : "UNDEFINED",
2895 if (defined $regex) {
2896 if (CPAN::_sqlite_running) {
2897 $CPAN::SQLite->search($class, $regex);
2900 $CPAN::META->all_objects($class)
2902 unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) {
2903 # BUG, we got an empty object somewhere
2904 require Data::Dumper;
2905 CPAN->debug(sprintf(
2906 "Bug in CPAN: Empty id on obj[%s][%s]",
2908 Data::Dumper::Dumper($obj)
2912 for my $method (@$methods) {
2913 my $match = eval {$obj->$method() =~ /$regex/i};
2915 my($err) = $@ =~ /^(.+) at .+? line \d+\.$/;
2916 $err ||= $@; # if we were too restrictive above
2917 $CPAN::Frontend->mydie("$err\n");
2924 } elsif ($command) {
2925 die "equal sign in command disabled (immature interface), ".
2927 ! \$CPAN::Shell::ADVANCED_QUERY=1
2928 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
2929 that may go away anytime.\n"
2930 unless $ADVANCED_QUERY;
2931 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
2932 my($matchcrit) = $criterion =~ m/^~(.+)/;
2936 $CPAN::META->all_objects($class)
2938 my $lhs = $self->$method() or next; # () for 5.00503
2940 push @m, $self if $lhs =~ m/$matchcrit/;
2942 push @m, $self if $lhs eq $criterion;
2947 if ( $class eq 'CPAN::Bundle' ) {
2948 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
2949 } elsif ($class eq "CPAN::Distribution") {
2950 $xarg = CPAN::Distribution->normalize($arg);
2954 if ($CPAN::META->exists($class,$xarg)) {
2955 $obj = $CPAN::META->instance($class,$xarg);
2956 } elsif ($CPAN::META->exists($class,$arg)) {
2957 $obj = $CPAN::META->instance($class,$arg);
2964 @m = sort {$a->id cmp $b->id} @m;
2965 if ( $CPAN::DEBUG ) {
2966 my $wantarray = wantarray;
2967 my $join_m = join ",", map {$_->id} @m;
2968 $self->debug("wantarray[$wantarray]join_m[$join_m]");
2970 return wantarray ? @m : $m[0];
2973 #-> sub CPAN::Shell::format_result ;
2976 my($type,@args) = @_;
2977 @args = '/./' unless @args;
2978 my(@result) = $self->expand($type,@args);
2979 my $result = @result == 1 ?
2980 $result[0]->as_string :
2982 "No objects of type $type found for argument @args\n" :
2984 (map {$_->as_glimpse} @result),
2985 scalar @result, " items found\n",
2990 #-> sub CPAN::Shell::report_fh ;
2992 my $installation_report_fh;
2993 my $previously_noticed = 0;
2996 return $installation_report_fh if $installation_report_fh;
2997 if ($CPAN::META->has_usable("File::Temp")) {
2998 $installation_report_fh
3000 dir => File::Spec->tmpdir,
3001 template => 'cpan_install_XXXX',
3006 unless ( $installation_report_fh ) {
3007 warn("Couldn't open installation report file; " .
3008 "no report file will be generated."
3009 ) unless $previously_noticed++;
3015 # The only reason for this method is currently to have a reliable
3016 # debugging utility that reveals which output is going through which
3017 # channel. No, I don't like the colors ;-)
3019 # to turn colordebugging on, write
3020 # cpan> o conf colorize_output 1
3022 #-> sub CPAN::Shell::print_ornamented ;
3024 my $print_ornamented_have_warned = 0;
3025 sub colorize_output {
3026 my $colorize_output = $CPAN::Config->{colorize_output};
3027 if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
3028 unless ($print_ornamented_have_warned++) {
3029 # no myprint/mywarn within myprint/mywarn!
3030 warn "Colorize_output is set to true but Term::ANSIColor is not
3031 installed. To activate colorized output, please install Term::ANSIColor.\n\n";
3033 $colorize_output = 0;
3035 return $colorize_output;
3040 #-> sub CPAN::Shell::print_ornamented ;
3041 sub print_ornamented {
3042 my($self,$what,$ornament) = @_;
3043 return unless defined $what;
3045 local $| = 1; # Flush immediately
3046 if ( $CPAN::Be_Silent ) {
3047 print {report_fh()} $what;
3050 my $swhat = "$what"; # stringify if it is an object
3051 if ($CPAN::Config->{term_is_latin}) {
3052 # note: deprecated, need to switch to $LANG and $LC_*
3055 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
3057 if ($self->colorize_output) {
3058 if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) {
3059 # if you want to have this configurable, please file a bugreport
3060 $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan";
3062 my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
3064 print "Term::ANSIColor rejects color[$ornament]: $@\n
3065 Please choose a different color (Hint: try 'o conf init /color/')\n";
3067 # GGOLDBACH/Test-GreaterVersion-0.008 broke wthout this
3068 # $trailer construct. We want the newline be the last thing if
3069 # there is a newline at the end ensuring that the next line is
3070 # empty for other players
3072 $trailer = $1 if $swhat =~ s/([\r\n]+)\z//;
3075 Term::ANSIColor::color("reset"),
3082 #-> sub CPAN::Shell::myprint ;
3084 # where is myprint/mywarn/Frontend/etc. documented? Where to use what?
3085 # I think, we send everything to STDOUT and use print for normal/good
3086 # news and warn for news that need more attention. Yes, this is our
3087 # working contract for now.
3089 my($self,$what) = @_;
3090 $self->print_ornamented($what,
3091 $CPAN::Config->{colorize_print}||'bold blue on_white',
3096 my($self,$category,$what) = @_;
3097 my $vname = $category . "_verbosity";
3098 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
3099 if (!$CPAN::Config->{$vname}
3100 || $CPAN::Config->{$vname} =~ /^v/
3102 $CPAN::Frontend->myprint($what);
3106 #-> sub CPAN::Shell::myexit ;
3108 my($self,$what) = @_;
3109 $self->myprint($what);
3113 #-> sub CPAN::Shell::mywarn ;
3115 my($self,$what) = @_;
3116 $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
3119 # only to be used for shell commands
3120 #-> sub CPAN::Shell::mydie ;
3122 my($self,$what) = @_;
3123 $self->mywarn($what);
3125 # If it is the shell, we want the following die to be silent,
3126 # but if it is not the shell, we would need a 'die $what'. We need
3127 # to take care that only shell commands use mydie. Is this
3133 # sub CPAN::Shell::colorable_makemaker_prompt ;
3134 sub colorable_makemaker_prompt {
3136 if (CPAN::Shell->colorize_output) {
3137 my $ornament = $CPAN::Config->{colorize_print}||'bold blue on_white';
3138 my $color_on = eval { Term::ANSIColor::color($ornament); } || "";
3141 my $ans = ExtUtils::MakeMaker::prompt($foo,$bar);
3142 if (CPAN::Shell->colorize_output) {
3143 print Term::ANSIColor::color('reset');
3148 # use this only for unrecoverable errors!
3149 #-> sub CPAN::Shell::unrecoverable_error ;
3150 sub unrecoverable_error {
3151 my($self,$what) = @_;
3152 my @lines = split /\n/, $what;
3154 for my $l (@lines) {
3155 $longest = length $l if length $l > $longest;
3157 $longest = 62 if $longest > 62;
3158 for my $l (@lines) {
3159 if ($l =~ /^\s*$/) {
3164 if (length $l < 66) {
3165 $l = pack "A66 A*", $l, "<==";
3169 unshift @lines, "\n";
3170 $self->mydie(join "", @lines);
3173 #-> sub CPAN::Shell::mysleep ;
3175 my($self, $sleep) = @_;
3176 if (CPAN->has_inst("Time::HiRes")) {
3177 Time::HiRes::sleep($sleep);
3179 sleep($sleep < 1 ? 1 : int($sleep + 0.5));
3183 #-> sub CPAN::Shell::setup_output ;
3185 return if -t STDOUT;
3186 my $odef = select STDERR;
3193 #-> sub CPAN::Shell::rematein ;
3194 # RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here
3197 my($meth,@some) = @_;
3199 while($meth =~ /^(ff?orce|notest)$/) {
3200 push @pragma, $meth;
3201 $meth = shift @some or
3202 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
3206 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
3208 # Here is the place to set "test_count" on all involved parties to
3209 # 0. We then can pass this counter on to the involved
3210 # distributions and those can refuse to test if test_count > X. In
3211 # the first stab at it we could use a 1 for "X".
3213 # But when do I reset the distributions to start with 0 again?
3214 # Jost suggested to have a random or cycling interaction ID that
3215 # we pass through. But the ID is something that is just left lying
3216 # around in addition to the counter, so I'd prefer to set the
3217 # counter to 0 now, and repeat at the end of the loop. But what
3218 # about dependencies? They appear later and are not reset, they
3219 # enter the queue but not its copy. How do they get a sensible
3222 # With configure_requires, "get" is vulnerable in recursion.
3224 my $needs_recursion_protection = "get|make|test|install";
3226 # construct the queue
3228 STHING: foreach $s (@some) {
3231 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
3233 } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
3234 } elsif ($s =~ m|^/|) { # looks like a regexp
3235 if (substr($s,-1,1) eq ".") {
3236 $obj = CPAN::Shell->expandany($s);
3238 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
3239 "not supported.\nRejecting argument '$s'\n");
3240 $CPAN::Frontend->mysleep(2);
3243 } elsif ($meth eq "ls") {
3244 $self->globls($s,\@pragma);
3247 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
3248 $obj = CPAN::Shell->expandany($s);
3251 } elsif (ref $obj) {
3252 if ($meth =~ /^($needs_recursion_protection)$/) {
3253 # it would be silly to check for recursion for look or dump
3254 # (we are in CPAN::Shell::rematein)
3255 CPAN->debug("Going to test against recursion") if $CPAN::DEBUG;
3256 eval { $obj->color_cmd_tmps(0,1); };
3259 and $@->isa("CPAN::Exception::RecursiveDependency")) {
3260 $CPAN::Frontend->mywarn($@);
3264 Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@);
3270 CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c");
3272 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
3273 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
3274 if ($meth =~ /^(dump|ls|reports)$/) {
3277 $CPAN::Frontend->mywarn(
3279 "Don't be silly, you can't $meth ",
3283 $CPAN::Frontend->mysleep(2);
3285 } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") {
3286 CPAN::InfoObj->dump($s);
3289 ->mywarn(qq{Warning: Cannot $meth $s, }.
3290 qq{don't know what it is.
3295 to find objects with matching identifiers.
3297 $CPAN::Frontend->mysleep(2);
3301 # queuerunner (please be warned: when I started to change the
3302 # queue to hold objects instead of names, I made one or two
3303 # mistakes and never found which. I reverted back instead)
3304 while (my $q = CPAN::Queue->first) {
3306 my $s = $q->as_string;
3307 my $reqtype = $q->reqtype || "";
3308 $obj = CPAN::Shell->expandany($s);
3310 # don't know how this can happen, maybe we should panic,
3311 # but maybe we get a solution from the first user who hits
3312 # this unfortunate exception?
3313 $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
3314 "to an object. Skipping.\n");
3315 $CPAN::Frontend->mysleep(5);
3316 CPAN::Queue->delete_first($s);
3319 $obj->{reqtype} ||= "";
3321 # force debugging because CPAN::SQLite somehow delivers us
3324 # local $CPAN::DEBUG = 1024; # Shell; probably fixed now
3326 CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]".
3327 "q-reqtype[$reqtype]") if $CPAN::DEBUG;
3329 if ($obj->{reqtype}) {
3330 if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) {
3331 $obj->{reqtype} = $reqtype;
3333 exists $obj->{install}
3336 UNIVERSAL::can($obj->{install},"failed") ?
3337 $obj->{install}->failed :
3338 $obj->{install} =~ /^NO/
3341 delete $obj->{install};
3342 $CPAN::Frontend->mywarn
3343 ("Promoting $obj->{ID} from 'build_requires' to 'requires'");
3347 $obj->{reqtype} = $reqtype;
3350 for my $pragma (@pragma) {
3353 $obj->can($pragma)) {
3354 $obj->$pragma($meth);
3357 if (UNIVERSAL::can($obj, 'called_for')) {
3358 $obj->called_for($s);
3360 CPAN->debug(qq{pragma[@pragma]meth[$meth]}.
3361 qq{ID[$obj->{ID}]}) if $CPAN::DEBUG;
3364 if ($meth =~ /^(report)$/) { # they came here with a pragma?
3366 } elsif (! UNIVERSAL::can($obj,$meth)) {
3368 my $serialized = "";
3370 } elsif ($CPAN::META->has_inst("YAML::Syck")) {
3371 $serialized = YAML::Syck::Dump($obj);
3372 } elsif ($CPAN::META->has_inst("YAML")) {
3373 $serialized = YAML::Dump($obj);
3374 } elsif ($CPAN::META->has_inst("Data::Dumper")) {
3375 $serialized = Data::Dumper::Dumper($obj);
3378 $serialized = overload::StrVal($obj);
3380 CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
3381 $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
3382 } elsif ($obj->$meth()) {
3383 CPAN::Queue->delete($s);
3384 CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG;
3386 CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG;
3390 for my $pragma (@pragma) {
3391 my $unpragma = "un$pragma";
3392 if ($obj->can($unpragma)) {
3396 CPAN::Queue->delete_first($s);
3398 if ($meth =~ /^($needs_recursion_protection)$/) {
3399 for my $obj (@qcopy) {
3400 $obj->color_cmd_tmps(0,0);
3405 #-> sub CPAN::Shell::recent ;
3408 if ($CPAN::META->has_inst("XML::LibXML")) {
3409 my $url = $CPAN::Defaultrecent;
3410 $CPAN::Frontend->myprint("Going to fetch '$url'\n");
3411 unless ($CPAN::META->has_usable("LWP")) {
3412 $CPAN::Frontend->mydie("LWP not installed; cannot continue");
3414 CPAN::LWP::UserAgent->config;
3416 eval { $Ua = CPAN::LWP::UserAgent->new; };
3418 $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
3420 my $resp = $Ua->get($url);
3421 unless ($resp->is_success) {
3422 $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
3424 $CPAN::Frontend->myprint("DONE\n\n");
3425 my $xml = XML::LibXML->new->parse_string($resp->content);
3427 my $s = $xml->serialize(2);
3428 $s =~ s/\n\s*\n/\n/g;
3429 $CPAN::Frontend->myprint($s);
3433 if ($url =~ /winnipeg/) {
3434 my $pubdate = $xml->findvalue("/rss/channel/pubDate");
3435 $CPAN::Frontend->myprint(" pubDate: $pubdate\n\n");
3436 for my $eitem ($xml->findnodes("/rss/channel/item")) {
3437 my $distro = $eitem->findvalue("enclosure/\@url");
3438 $distro =~ s|.*?/authors/id/./../||;
3439 my $size = $eitem->findvalue("enclosure/\@length");
3440 my $desc = $eitem->findvalue("description");
3441 \0 $desc =~ s/.+? - //;
3442 $CPAN::Frontend->myprint("$distro [$size b]\n $desc\n");
3443 push @distros, $distro;
3445 } elsif ($url =~ /search.*uploads.rdf/) {
3446 # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
3447 # xmlns="http://purl.org/rss/1.0/"
3448 # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
3449 # xmlns:dc="http://purl.org/dc/elements/1.1/"
3450 # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
3451 # xmlns:admin="http://webns.net/mvcb/"
3454 my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']");
3455 $CPAN::Frontend->myprint(" dc:date: $dc_date\n\n");
3456 my $finish_eitem = 0;
3457 local $SIG{INT} = sub { $finish_eitem = 1 };
3458 EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) {
3459 my $distro = $eitem->findvalue("\@rdf:about");
3460 $distro =~ s|.*~||; # remove up to the tilde before the name
3461 $distro =~ s|/$||; # remove trailing slash
3462 $distro =~ s|([^/]+)|\U$1\E|; # upcase the name
3463 my $author = uc $1 or die "distro[$distro] without author, cannot continue";
3464 my $desc = $eitem->findvalue("*[local-name(.) = 'description']");
3466 SUBDIRTEST: while () {
3467 last SUBDIRTEST if ++$i >= 6; # half a dozen must do!
3468 if (my @ret = $self->globls("$distro*")) {
3469 @ret = grep {$_->[2] !~ /meta/} @ret;
3470 @ret = grep {length $_->[2]} @ret;
3472 $distro = "$author/$ret[0][2]";
3476 $distro =~ s|/|/*/|; # allow it to reside in a subdirectory
3479 next EITEM if $distro =~ m|\*|; # did not find the thing
3480 $CPAN::Frontend->myprint("____$desc\n");
3481 push @distros, $distro;
3482 last EITEM if $finish_eitem;
3487 # deprecated old version
3488 $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n");
3492 #-> sub CPAN::Shell::smoke ;
3495 my $distros = $self->recent;
3496 DISTRO: for my $distro (@$distros) {
3497 $CPAN::Frontend->myprint(sprintf "Going to download and test '$distro'\n");
3500 local $SIG{INT} = sub { $skip = 1 };
3502 $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_);
3505 $CPAN::Frontend->myprint(" skipped\n");
3510 $CPAN::Frontend->myprint("\r \n"); # leave the dirty line with a newline
3511 $self->test($distro);
3516 # set up the dispatching methods
3518 for my $command (qw(
3535 *$command = sub { shift->rematein($command, @_); };
3539 package CPAN::LWP::UserAgent;
3543 return if $SETUPDONE;
3544 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3545 require LWP::UserAgent;
3546 @ISA = qw(Exporter LWP::UserAgent);
3549 $CPAN::Frontend->mywarn(" LWP::UserAgent not available\n");
3553 sub get_basic_credentials {
3554 my($self, $realm, $uri, $proxy) = @_;
3555 if ($USER && $PASSWD) {
3556 return ($USER, $PASSWD);
3559 ($USER,$PASSWD) = $self->get_proxy_credentials();
3561 ($USER,$PASSWD) = $self->get_non_proxy_credentials();
3563 return($USER,$PASSWD);
3566 sub get_proxy_credentials {
3568 my ($user, $password);
3569 if ( defined $CPAN::Config->{proxy_user} &&
3570 defined $CPAN::Config->{proxy_pass}) {
3571 $user = $CPAN::Config->{proxy_user};
3572 $password = $CPAN::Config->{proxy_pass};
3573 return ($user, $password);
3575 my $username_prompt = "\nProxy authentication needed!
3576 (Note: to permanently configure username and password run
3577 o conf proxy_user your_username
3578 o conf proxy_pass your_password
3580 ($user, $password) =
3581 _get_username_and_password_from_user($username_prompt);
3582 return ($user,$password);
3585 sub get_non_proxy_credentials {
3587 my ($user,$password);
3588 if ( defined $CPAN::Config->{username} &&
3589 defined $CPAN::Config->{password}) {
3590 $user = $CPAN::Config->{username};
3591 $password = $CPAN::Config->{password};
3592 return ($user, $password);
3594 my $username_prompt = "\nAuthentication needed!
3595 (Note: to permanently configure username and password run
3596 o conf username your_username
3597 o conf password your_password
3600 ($user, $password) =
3601 _get_username_and_password_from_user($username_prompt);
3602 return ($user,$password);
3605 sub _get_username_and_password_from_user {
3606 my $username_message = shift;
3607 my ($username,$password);
3609 ExtUtils::MakeMaker->import(qw(prompt));
3610 $username = prompt($username_message);
3611 if ($CPAN::META->has_inst("Term::ReadKey")) {
3612 Term::ReadKey::ReadMode("noecho");
3615 $CPAN::Frontend->mywarn(
3616 "Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n"
3619 $password = prompt("Password:");
3621 if ($CPAN::META->has_inst("Term::ReadKey")) {
3622 Term::ReadKey::ReadMode("restore");
3624 $CPAN::Frontend->myprint("\n\n");
3625 return ($username,$password);
3628 # mirror(): Its purpose is to deal with proxy authentication. When we
3629 # call SUPER::mirror, we relly call the mirror method in
3630 # LWP::UserAgent. LWP::UserAgent will then call
3631 # $self->get_basic_credentials or some equivalent and this will be
3632 # $self->dispatched to our own get_basic_credentials method.
3634 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3636 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3637 # although we have gone through our get_basic_credentials, the proxy
3638 # server refuses to connect. This could be a case where the username or
3639 # password has changed in the meantime, so I'm trying once again without
3640 # $USER and $PASSWD to give the get_basic_credentials routine another
3641 # chance to set $USER and $PASSWD.
3643 # mirror(): Its purpose is to deal with proxy authentication. When we
3644 # call SUPER::mirror, we relly call the mirror method in
3645 # LWP::UserAgent. LWP::UserAgent will then call
3646 # $self->get_basic_credentials or some equivalent and this will be
3647 # $self->dispatched to our own get_basic_credentials method.
3649 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3651 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3652 # although we have gone through our get_basic_credentials, the proxy
3653 # server refuses to connect. This could be a case where the username or
3654 # password has changed in the meantime, so I'm trying once again without
3655 # $USER and $PASSWD to give the get_basic_credentials routine another
3656 # chance to set $USER and $PASSWD.
3659 my($self,$url,$aslocal) = @_;
3660 my $result = $self->SUPER::mirror($url,$aslocal);
3661 if ($result->code == 407) {
3664 $result = $self->SUPER::mirror($url,$aslocal);
3672 #-> sub CPAN::FTP::ftp_statistics
3673 # if they want to rewrite, they need to pass in a filehandle
3674 sub _ftp_statistics {
3676 my $locktype = $fh ? LOCK_EX : LOCK_SH;
3677 $fh ||= FileHandle->new;
3678 my $file = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3679 open $fh, "+>>$file" or $CPAN::Frontend->mydie("Could not open '$file': $!");
3682 while (!CPAN::_flock($fh, $locktype|LOCK_NB)) {
3683 $waitstart ||= localtime();
3685 $CPAN::Frontend->mywarn("Waiting for a read lock on '$file' (since $waitstart)\n");
3687 $CPAN::Frontend->mysleep($sleep);
3690 } elsif ($sleep <=6) {
3694 my $stats = eval { CPAN->_yaml_loadfile($file); };
3697 if (ref $@ eq "CPAN::Exception::yaml_not_installed") {
3698 $CPAN::Frontend->myprint("Warning (usually harmless): $@");
3700 } elsif (ref $@ eq "CPAN::Exception::yaml_process_error") {
3701 $CPAN::Frontend->mydie($@);
3704 $CPAN::Frontend->mydie($@);
3710 #-> sub CPAN::FTP::_mytime
3712 if (CPAN->has_inst("Time::HiRes")) {
3713 return Time::HiRes::time();
3719 #-> sub CPAN::FTP::_new_stats
3721 my($self,$file) = @_;
3730 #-> sub CPAN::FTP::_add_to_statistics
3731 sub _add_to_statistics {
3732 my($self,$stats) = @_;
3733 my $yaml_module = CPAN::_yaml_module;
3734 $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG;
3735 if ($CPAN::META->has_inst($yaml_module)) {
3736 $stats->{thesiteurl} = $ThesiteURL;
3737 if (CPAN->has_inst("Time::HiRes")) {
3738 $stats->{end} = Time::HiRes::time();
3740 $stats->{end} = time;
3742 my $fh = FileHandle->new;
3746 @debug = $time if $sdebug;
3747 my $fullstats = $self->_ftp_statistics($fh);
3749 $fullstats->{history} ||= [];
3750 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3751 push @debug, time if $sdebug;
3752 push @{$fullstats->{history}}, $stats;
3753 # arbitrary hardcoded constants until somebody demands to have
3754 # them settable; YAML.pm 0.62 is unacceptably slow with 999;
3755 # YAML::Syck 0.82 has no noticable performance problem with 999;
3757 @{$fullstats->{history}} > 99
3758 || $time - $fullstats->{history}[0]{start} > 14*86400
3760 shift @{$fullstats->{history}}
3762 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3763 push @debug, time if $sdebug;
3764 push @debug, scalar localtime($fullstats->{history}[0]{start}) if $sdebug;
3765 # need no eval because if this fails, it is serious
3766 my $sfile = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3767 CPAN->_yaml_dumpfile("$sfile.$$",$fullstats);
3769 local $CPAN::DEBUG = 512; # FTP
3771 CPAN->debug(sprintf("DEBUG history: before_read[%d]before[%d]at[%d]".
3772 "after[%d]at[%d]oldest[%s]dumped backat[%d]",
3776 # Win32 cannot rename a file to an existing filename
3777 unlink($sfile) if ($^O eq 'MSWin32');
3778 rename "$sfile.$$", $sfile
3779 or $CPAN::Frontend->mydie("Could not rename '$sfile.$$' to '$sfile': $!\n");
3783 # if file is CHECKSUMS, suggest the place where we got the file to be
3784 # checked from, maybe only for young files?
3785 #-> sub CPAN::FTP::_recommend_url_for
3786 sub _recommend_url_for {
3787 my($self, $file) = @_;
3788 my $urllist = $self->_get_urllist;
3789 if ($file =~ s|/CHECKSUMS(.gz)?$||) {
3790 my $fullstats = $self->_ftp_statistics();
3791 my $history = $fullstats->{history} || [];
3792 while (my $last = pop @$history) {
3793 last if $last->{end} - time > 3600; # only young results are interesting
3794 next unless $last->{file}; # dirname of nothing dies!
3795 next unless $file eq File::Basename::dirname($last->{file});
3796 return $last->{thesiteurl};
3799 if ($CPAN::Config->{randomize_urllist}
3801 rand(1) < $CPAN::Config->{randomize_urllist}
3803 $urllist->[int rand scalar @$urllist];
3809 #-> sub CPAN::FTP::_get_urllist
3812 $CPAN::Config->{urllist} ||= [];
3813 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
3814 $CPAN::Frontend->mywarn("Malformed urllist; ignoring. Configuration file corrupt?\n");
3815 $CPAN::Config->{urllist} = [];
3817 my @urllist = grep { defined $_ and length $_ } @{$CPAN::Config->{urllist}};
3818 for my $u (@urllist) {
3819 CPAN->debug("u[$u]") if $CPAN::DEBUG;
3820 if (UNIVERSAL::can($u,"text")) {
3821 $u->{TEXT} .= "/" unless substr($u->{TEXT},-1) eq "/";
3823 $u .= "/" unless substr($u,-1) eq "/";
3824 $u = CPAN::URL->new(TEXT => $u, FROM => "USER");
3830 #-> sub CPAN::FTP::ftp_get ;
3832 my($class,$host,$dir,$file,$target) = @_;
3834 qq[Going to fetch file [$file] from dir [$dir]
3835 on host [$host] as local [$target]\n]
3837 my $ftp = Net::FTP->new($host);
3839 $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
3842 return 0 unless defined $ftp;
3843 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
3844 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
3845 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ) {
3846 my $msg = $ftp->message;
3847 $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
3850 unless ( $ftp->cwd($dir) ) {
3851 my $msg = $ftp->message;
3852 $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
3856 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
3857 unless ( $ftp->get($file,$target) ) {
3858 my $msg = $ftp->message;
3859 $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
3862 $ftp->quit; # it's ok if this fails
3866 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
3868 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
3869 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
3871 # > *** 1562,1567 ****
3872 # > --- 1562,1580 ----
3873 # > return 1 if substr($url,0,4) eq "file";
3874 # > return 1 unless $url =~ m|://([^/]+)|;
3876 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
3878 # > + $proxy =~ m|://([^/:]+)|;
3880 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
3881 # > + if ($noproxy) {
3882 # > + if ($host !~ /$noproxy$/) {
3883 # > + $host = $proxy;
3886 # > + $host = $proxy;
3889 # > require Net::Ping;
3890 # > return 1 unless $Net::Ping::VERSION >= 2;
3894 #-> sub CPAN::FTP::localize ;
3896 my($self,$file,$aslocal,$force) = @_;
3898 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
3899 unless defined $aslocal;
3900 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
3903 if ($^O eq 'MacOS') {
3904 # Comment by AK on 2000-09-03: Uniq short filenames would be
3905 # available in CHECKSUMS file
3906 my($name, $path) = File::Basename::fileparse($aslocal, '');
3907 if (length($name) > 31) {
3918 my $size = 31 - length($suf);
3919 while (length($name) > $size) {
3923 $aslocal = File::Spec->catfile($path, $name);
3927 if (-f $aslocal && -r _ && !($force & 1)) {
3929 if ($size = -s $aslocal) {
3930 $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG;
3933 # empty file from a previous unsuccessful attempt to download it
3935 $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I ".
3936 "could not remove.");
3939 my($maybe_restore) = 0;
3941 rename $aslocal, "$aslocal.bak$$";
3945 my($aslocal_dir) = File::Basename::dirname($aslocal);
3946 $self->mymkpath($aslocal_dir); # too early for file URLs / RT #28438
3947 # Inheritance is not easier to manage than a few if/else branches
3948 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3950 CPAN::LWP::UserAgent->config;
3951 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
3953 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
3957 $Ua->proxy('ftp', $var)
3958 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
3959 $Ua->proxy('http', $var)
3960 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
3962 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
3966 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
3967 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
3970 # Try the list of urls for each single object. We keep a record
3971 # where we did get a file from
3972 my(@reordered,$last);
3973 my $ccurllist = $self->_get_urllist;
3974 $last = $#$ccurllist;
3975 if ($force & 2) { # local cpans probably out of date, don't reorder
3976 @reordered = (0..$last);
3980 (substr($ccurllist->[$b],0,4) eq "file")
3982 (substr($ccurllist->[$a],0,4) eq "file")
3984 defined($ThesiteURL)
3986 ($ccurllist->[$b] eq $ThesiteURL)
3988 ($ccurllist->[$a] eq $ThesiteURL)
3993 $self->debug("Themethod[$Themethod]reordered[@reordered]") if $CPAN::DEBUG;
3999 ["dleasy", "http","defaultsites"],
4000 ["dlhard", "http","defaultsites"],
4001 ["dleasy", "ftp", "defaultsites"],
4002 ["dlhard", "ftp", "defaultsites"],
4003 ["dlhardest","", "defaultsites"],
4006 @levels = grep {$_->[0] eq $Themethod} @all_levels;
4007 push @levels, grep {$_->[0] ne $Themethod} @all_levels;
4009 @levels = @all_levels;
4011 @levels = qw/dleasy/ if $^O eq 'MacOS';
4013 local $ENV{FTP_PASSIVE} =
4014 exists $CPAN::Config->{ftp_passive} ?
4015 $CPAN::Config->{ftp_passive} : 1;
4017 my $stats = $self->_new_stats($file);
4018 LEVEL: for $levelno (0..$#levels) {
4019 my $level_tuple = $levels[$levelno];
4020 my($level,$scheme,$sitetag) = @$level_tuple;
4021 my $defaultsites = $sitetag && $sitetag eq "defaultsites";
4023 if ($defaultsites) {
4024 unless (defined $connect_to_internet_ok) {
4025 $CPAN::Frontend->myprint(sprintf qq{
4026 I would like to connect to one of the following sites to get '%s':
4031 join("",map { " ".$_->text."\n" } @CPAN::Defaultsites),
4033 my $answer = CPAN::Shell::colorable_makemaker_prompt("Is it OK to try to connect to the Internet?", "yes");
4034 if ($answer =~ /^y/i) {
4035 $connect_to_internet_ok = 1;
4037 $connect_to_internet_ok = 0;
4040 if ($connect_to_internet_ok) {
4041 @urllist = @CPAN::Defaultsites;
4046 my @host_seq = $level =~ /dleasy/ ?
4047 @reordered : 0..$last; # reordered has file and $Thesiteurl first
4048 @urllist = map { $ccurllist->[$_] } @host_seq;
4050 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4051 my $aslocal_tempfile = $aslocal . ".tmp" . $$;
4052 if (my $recommend = $self->_recommend_url_for($file)) {
4053 @urllist = grep { $_ ne $recommend } @urllist;
4054 unshift @urllist, $recommend;
4056 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4057 $ret = $self->hostdlxxx($level,$scheme,\@urllist,$file,$aslocal_tempfile,$stats);
4059 CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG;
4060 if ($ret eq $aslocal_tempfile) {
4061 # if we got it exactly as we asked for, only then we
4063 rename $aslocal_tempfile, $aslocal
4064 or $CPAN::Frontend->mydie("Error while trying to rename ".
4065 "'$ret' to '$aslocal': $!");
4068 $Themethod = $level;
4070 # utime $now, $now, $aslocal; # too bad, if we do that, we
4071 # might alter a local mirror
4072 $self->debug("level[$level]") if $CPAN::DEBUG;
4075 unlink $aslocal_tempfile;
4076 last if $CPAN::Signal; # need to cleanup
4080 $stats->{filesize} = -s $ret;
4082 $self->debug("before _add_to_statistics") if $CPAN::DEBUG;
4083 $self->_add_to_statistics($stats);
4084 $self->debug("after _add_to_statistics") if $CPAN::DEBUG;
4086 unlink "$aslocal.bak$$";
4089 unless ($CPAN::Signal) {
4092 if (@{$CPAN::Config->{urllist}}) {
4094 qq{Please check, if the URLs I found in your configuration file \(}.
4095 join(", ", @{$CPAN::Config->{urllist}}).
4098 push @mess, qq{Your urllist is empty!};
4100 push @mess, qq{The urllist can be edited.},
4101 qq{E.g. with 'o conf urllist push ftp://myurl/'};
4102 $CPAN::Frontend->mywarn(Text::Wrap::wrap("","","@mess"). "\n\n");
4103 $CPAN::Frontend->mywarn("Could not fetch $file\n");
4104 $CPAN::Frontend->mysleep(2);
4106 if ($maybe_restore) {
4107 rename "$aslocal.bak$$", $aslocal;
4108 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
4109 $self->ls($aslocal));
4116 my($self, $aslocal_dir) = @_;
4117 File::Path::mkpath($aslocal_dir);
4118 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
4119 qq{directory "$aslocal_dir".
4120 I\'ll continue, but if you encounter problems, they may be due
4121 to insufficient permissions.\n}) unless -w $aslocal_dir;
4129 $h = [ grep /^\Q$scheme\E:/, @$h ] if $scheme;
4130 my $method = "host$level";
4131 $self->$method($h, @_);
4135 my($self,$stats,$method,$url) = @_;
4136 push @{$stats->{attempts}}, {
4143 # package CPAN::FTP;
4145 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4147 HOSTEASY: for $ro_url (@$host_seq) {
4148 $self->_set_attempt($stats,"dleasy",$ro_url);
4149 my $url .= "$ro_url$file";
4150 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
4151 if ($url =~ /^file:/) {
4153 if ($CPAN::META->has_inst('URI::URL')) {
4154 my $u = URI::URL->new($url);
4156 } else { # works only on Unix, is poorly constructed, but
4157 # hopefully better than nothing.
4158 # RFC 1738 says fileurl BNF is
4159 # fileurl = "file://" [ host | "localhost" ] "/" fpath
4160 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
4162 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
4163 $l =~ s|^file:||; # assume they
4167 if ! -f $l && $l =~ m|^/\w:|; # e.g. /P:
4169 $self->debug("local file[$l]") if $CPAN::DEBUG;
4170 if ( -f $l && -r _) {
4171 $ThesiteURL = $ro_url;
4174 if ($l =~ /(.+)\.gz$/) {
4176 if ( -f $ungz && -r _) {
4177 $ThesiteURL = $ro_url;
4181 # Maybe mirror has compressed it?
4183 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
4184 eval { CPAN::Tarzip->new("$l.gz")->gunzip($aslocal) };
4186 $ThesiteURL = $ro_url;
4190 $CPAN::Frontend->mywarn("Could not find '$l'\n");
4192 $self->debug("it was not a file URL") if $CPAN::DEBUG;
4193 if ($CPAN::META->has_usable('LWP')) {
4194 $CPAN::Frontend->myprint("Fetching with LWP:
4198 CPAN::LWP::UserAgent->config;
4199 eval { $Ua = CPAN::LWP::UserAgent->new; };
4201 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
4204 my $res = $Ua->mirror($url, $aslocal);
4205 if ($res->is_success) {
4206 $ThesiteURL = $ro_url;
4208 utime $now, $now, $aslocal; # download time is more
4209 # important than upload
4212 } elsif ($url !~ /\.gz(?!\n)\Z/) {
4213 my $gzurl = "$url.gz";
4214 $CPAN::Frontend->myprint("Fetching with LWP:
4217 $res = $Ua->mirror($gzurl, "$aslocal.gz");
4218 if ($res->is_success) {
4219 if (eval {CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)}) {
4220 $ThesiteURL = $ro_url;
4225 $CPAN::Frontend->myprint(sprintf(
4226 "LWP failed with code[%s] message[%s]\n",
4230 # Alan Burlison informed me that in firewall environments
4231 # Net::FTP can still succeed where LWP fails. So we do not
4232 # skip Net::FTP anymore when LWP is available.
4235 $CPAN::Frontend->mywarn(" LWP not available\n");
4237 return if $CPAN::Signal;
4238 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4239 # that's the nice and easy way thanks to Graham
4240 $self->debug("recognized ftp") if $CPAN::DEBUG;
4241 my($host,$dir,$getfile) = ($1,$2,$3);
4242 if ($CPAN::META->has_usable('Net::FTP')) {
4244 $CPAN::Frontend->myprint("Fetching with Net::FTP:
4247 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
4248 "aslocal[$aslocal]") if $CPAN::DEBUG;
4249 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
4250 $ThesiteURL = $ro_url;
4253 if ($aslocal !~ /\.gz(?!\n)\Z/) {
4254 my $gz = "$aslocal.gz";
4255 $CPAN::Frontend->myprint("Fetching with Net::FTP
4258 if (CPAN::FTP->ftp_get($host,
4262 eval{CPAN::Tarzip->new($gz)->gunzip($aslocal)}
4264 $ThesiteURL = $ro_url;
4270 CPAN->debug("Net::FTP does not count as usable atm") if $CPAN::DEBUG;
4274 UNIVERSAL::can($ro_url,"text")
4276 $ro_url->{FROM} eq "USER"
4278 ##address #17973: default URLs should not try to override
4279 ##user-defined URLs just because LWP is not available
4280 my $ret = $self->hostdlhard([$ro_url],$file,$aslocal,$stats);
4281 return $ret if $ret;
4283 return if $CPAN::Signal;
4287 # package CPAN::FTP;
4289 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4291 # Came back if Net::FTP couldn't establish connection (or
4292 # failed otherwise) Maybe they are behind a firewall, but they
4293 # gave us a socksified (or other) ftp program...
4296 my($devnull) = $CPAN::Config->{devnull} || "";
4298 my($aslocal_dir) = File::Basename::dirname($aslocal);
4299 File::Path::mkpath($aslocal_dir);
4300 HOSTHARD: for $ro_url (@$host_seq) {
4301 $self->_set_attempt($stats,"dlhard",$ro_url);
4302 my $url = "$ro_url$file";
4303 my($proto,$host,$dir,$getfile);
4305 # Courtesy Mark Conty mark_conty@cargill.com change from
4306 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4308 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
4309 # proto not yet used
4310 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
4312 next HOSTHARD; # who said, we could ftp anything except ftp?
4314 next HOSTHARD if $proto eq "file"; # file URLs would have had
4315 # success above. Likely a bogus URL
4317 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
4319 # Try the most capable first and leave ncftp* for last as it only
4321 DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) {
4322 my $funkyftp = CPAN::HandleConfig->safe_quote($CPAN::Config->{$f});
4323 next unless defined $funkyftp;
4324 next if $funkyftp =~ /^\s*$/;
4326 my($asl_ungz, $asl_gz);
4327 ($asl_ungz = $aslocal) =~ s/\.gz//;
4328 $asl_gz = "$asl_ungz.gz";
4330 my($src_switch) = "";
4332 my($stdout_redir) = " > $asl_ungz";
4334 $src_switch = " -source";
4335 } elsif ($f eq "ncftp") {
4336 $src_switch = " -c";
4337 } elsif ($f eq "wget") {
4338 $src_switch = " -O $asl_ungz";
4340 } elsif ($f eq 'curl') {
4341 $src_switch = ' -L -f -s -S --netrc-optional';
4344 if ($f eq "ncftpget") {
4345 $chdir = "cd $aslocal_dir && ";
4348 $CPAN::Frontend->myprint(