1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $CPAN::VERSION = '1.9203';
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 ();
33 # we need to run chdir all over and we would get at wrong libraries
36 if (File::Spec->can("rel2abs")) {
38 $inc = File::Spec->rel2abs($inc) unless ref $inc;
44 require Mac::BuildTools if $^O eq 'MacOS';
45 $ENV{PERL5_CPAN_IS_RUNNING}=$$;
46 $ENV{PERL5_CPANPLUS_IS_RUNNING}=$$; # https://rt.cpan.org/Ticket/Display.html?id=23735
48 END { $CPAN::End++; &cleanup; }
51 $CPAN::Frontend ||= "CPAN::Shell";
52 unless (@CPAN::Defaultsites) {
53 @CPAN::Defaultsites = map {
54 CPAN::URL->new(TEXT => $_, FROM => "DEF")
56 "http://www.perl.org/CPAN/",
57 "ftp://ftp.perl.org/pub/CPAN/";
59 # $CPAN::iCwd (i for initial) is going to be initialized during find_perl
60 $CPAN::Perl ||= CPAN::find_perl();
61 $CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
62 $CPAN::Defaultrecent ||= "http://search.cpan.org/uploads.rdf";
63 $CPAN::Defaultrecent ||= "http://cpan.uwinnipeg.ca/htdocs/cpan.xml";
65 # our globals are getting a mess
91 @CPAN::ISA = qw(CPAN::Debug Exporter);
93 # note that these functions live in CPAN::Shell and get executed via
94 # AUTOLOAD when called directly
121 sub soft_chdir_with_alternatives ($);
124 $autoload_recursion ||= 0;
126 #-> sub CPAN::AUTOLOAD ;
128 $autoload_recursion++;
132 warn "Refusing to autoload '$l' while signal pending";
133 $autoload_recursion--;
136 if ($autoload_recursion > 1) {
137 my $fullcommand = join " ", map { "'$_'" } $l, @_;
138 warn "Refusing to autoload $fullcommand in recursion\n";
139 $autoload_recursion--;
143 @export{@EXPORT} = '';
144 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
145 if (exists $export{$l}) {
148 die(qq{Unknown CPAN command "$AUTOLOAD". }.
149 qq{Type ? for help.\n});
151 $autoload_recursion--;
155 #-> sub CPAN::shell ;
158 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
159 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
161 my $oprompt = shift || CPAN::Prompt->new;
162 my $prompt = $oprompt;
163 my $commandline = shift || "";
164 $CPAN::CurrentCommandId ||= 1;
167 unless ($Suppress_readline) {
168 require Term::ReadLine;
171 $term->ReadLine eq "Term::ReadLine::Stub"
173 $term = Term::ReadLine->new('CPAN Monitor');
175 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
176 my $attribs = $term->Attribs;
177 $attribs->{attempted_completion_function} = sub {
178 &CPAN::Complete::gnu_cpl;
181 $readline::rl_completion_function =
182 $readline::rl_completion_function = 'CPAN::Complete::cpl';
184 if (my $histfile = $CPAN::Config->{'histfile'}) {{
185 unless ($term->can("AddHistory")) {
186 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
189 $META->readhist($term,$histfile);
191 for ($CPAN::Config->{term_ornaments}) { # alias
192 local $Term::ReadLine::termcap_nowarn = 1;
193 $term->ornaments($_) if defined;
195 # $term->OUT is autoflushed anyway
196 my $odef = select STDERR;
204 my @cwd = grep { defined $_ and length $_ }
206 File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
207 File::Spec->rootdir();
208 my $try_detect_readline;
209 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
210 unless ($CPAN::Config->{inhibit_startup_message}) {
211 my $rl_avail = $Suppress_readline ? "suppressed" :
212 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
213 "available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
214 $CPAN::Frontend->myprint(
216 cpan shell -- CPAN exploration and modules installation (v%s)
224 my($continuation) = "";
225 my $last_term_ornaments;
226 SHELLCOMMAND: while () {
227 if ($Suppress_readline) {
228 if ($Echo_readline) {
232 last SHELLCOMMAND unless defined ($_ = <> );
233 if ($Echo_readline) {
234 # backdoor: I could not find a way to record sessions
239 last SHELLCOMMAND unless
240 defined ($_ = $term->readline($prompt, $commandline));
242 $_ = "$continuation$_" if $continuation;
244 next SHELLCOMMAND if /^$/;
246 if (/^(?:q(?:uit)?|bye|exit)$/i) {
257 use vars qw($import_done);
258 CPAN->import(':DEFAULT') unless $import_done++;
259 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
266 eval { @line = Text::ParseWords::shellwords($_) };
267 warn($@), next SHELLCOMMAND if $@;
268 warn("Text::Parsewords could not parse the line [$_]"),
269 next SHELLCOMMAND unless @line;
270 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
271 my $command = shift @line;
272 eval { CPAN::Shell->$command(@line) };
278 my $dv = Dumpvalue->new();
279 Carp::cluck(sprintf "Catching error: %s", $dv->stringify($err));
289 # pragmas for classic commands
298 # only commands that tell us something about failed distros
299 CPAN::Shell->failed($CPAN::CurrentCommandId,1);
301 soft_chdir_with_alternatives(\@cwd);
302 $CPAN::Frontend->myprint("\n");
304 $CPAN::CurrentCommandId++;
308 $commandline = ""; # I do want to be able to pass a default to
309 # shell, but on the second command I see no
312 CPAN::Queue->nullify_queue;
313 if ($try_detect_readline) {
314 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
316 $CPAN::META->has_inst("Term::ReadLine::Perl")
318 delete $INC{"Term/ReadLine.pm"};
320 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
321 require Term::ReadLine;
322 $CPAN::Frontend->myprint("\n$redef subroutines in ".
323 "Term::ReadLine redefined\n");
327 if ($term and $term->can("ornaments")) {
328 for ($CPAN::Config->{term_ornaments}) { # alias
330 if (not defined $last_term_ornaments
331 or $_ != $last_term_ornaments
333 local $Term::ReadLine::termcap_nowarn = 1;
334 $term->ornaments($_);
335 $last_term_ornaments = $_;
338 undef $last_term_ornaments;
342 for my $class (qw(Module Distribution)) {
343 # again unsafe meta access?
344 for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
345 next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
346 CPAN->debug("BUG: $class '$dm' was in command state, resetting");
347 delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
351 $GOTOSHELL = 0; # not too often
352 $META->savehist if $CPAN::term && $CPAN::term->can("GetHistory");
357 soft_chdir_with_alternatives(\@cwd);
360 sub soft_chdir_with_alternatives ($) {
363 my $root = File::Spec->rootdir();
364 $CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
365 Trying '$root' as temporary haven.
370 if (chdir $cwd->[0]) {
374 $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
375 Trying to chdir to "$cwd->[1]" instead.
379 $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
387 if ($Config::Config{d_flock}) {
388 return flock $fh, $mode;
389 } elsif (!$Have_warned->{"d_flock"}++) {
390 $CPAN::Frontend->mywarn("Your OS does not support locking; continuing and ignoring all locking issues\n");
391 $CPAN::Frontend->mysleep(5);
398 sub _yaml_module () {
399 my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
401 $yaml_module ne "YAML"
403 !$CPAN::META->has_inst($yaml_module)
405 # $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
406 $yaml_module = "YAML";
408 if ($yaml_module eq "YAML"
410 $CPAN::META->has_inst($yaml_module)
412 $YAML::VERSION < 0.60
414 !$Have_warned->{"YAML"}++
416 $CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
417 "I'll continue but problems are *very* likely to happen.\n"
419 $CPAN::Frontend->mysleep(5);
424 # CPAN::_yaml_loadfile
426 my($self,$local_file) = @_;
427 return +[] unless -s $local_file;
428 my $yaml_module = _yaml_module;
429 if ($CPAN::META->has_inst($yaml_module)) {
430 # temporarly enable yaml code deserialisation
432 # 5.6.2 could not do the local() with the reference
433 local $YAML::LoadCode;
434 local $YAML::Syck::LoadCode;
435 ${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
438 if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
440 eval { @yaml = $code->($local_file); };
442 # this shall not be done by the frontend
443 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
446 } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
448 open FH, $local_file or die "Could not open '$local_file': $!";
452 eval { @yaml = $code->($ystream); };
454 # this shall not be done by the frontend
455 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
460 # this shall not be done by the frontend
461 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
466 # CPAN::_yaml_dumpfile
468 my($self,$local_file,@what) = @_;
469 my $yaml_module = _yaml_module;
470 if ($CPAN::META->has_inst($yaml_module)) {
472 if (UNIVERSAL::isa($local_file, "FileHandle")) {
473 $code = UNIVERSAL::can($yaml_module, "Dump");
474 eval { print $local_file $code->(@what) };
475 } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
476 eval { $code->($local_file,@what); };
477 } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
479 open FH, ">$local_file" or die "Could not open '$local_file': $!";
480 print FH $code->(@what);
483 die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
486 if (UNIVERSAL::isa($local_file, "FileHandle")) {
487 # I think this case does not justify a warning at all
489 die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
494 sub _init_sqlite () {
495 unless ($CPAN::META->has_inst("CPAN::SQLite")) {
496 $CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
497 unless $Have_warned->{"CPAN::SQLite"}++;
500 require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
501 $CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
505 my $negative_cache = {};
506 sub _sqlite_running {
507 if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
508 # need to cache the result, otherwise too slow
509 return $negative_cache->{fact};
511 $negative_cache = {}; # reset
513 my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
514 return $ret if $ret; # fast anyway
515 $negative_cache->{time} = time;
516 return $negative_cache->{fact} = $ret;
520 package CPAN::CacheMgr;
522 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
527 use Fcntl qw(:flock);
528 use vars qw($connect_to_internet_ok $Ua $Thesite $ThesiteURL $Themethod);
529 @CPAN::FTP::ISA = qw(CPAN::Debug);
531 package CPAN::LWP::UserAgent;
533 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
534 # we delay requiring LWP::UserAgent and setting up inheritance until we need it
536 package CPAN::Complete;
538 @CPAN::Complete::ISA = qw(CPAN::Debug);
539 # Q: where is the "How do I add a new command" HOWTO?
540 # A: svn diff -r 1048:1049 where andk added the report command
541 @CPAN::Complete::COMMANDS = sort qw(
542 ? ! a b d h i m o q r u
577 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $HAVE_REANIMATED);
578 @CPAN::Index::ISA = qw(CPAN::Debug);
581 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
584 package CPAN::InfoObj;
586 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
588 package CPAN::Author;
590 @CPAN::Author::ISA = qw(CPAN::InfoObj);
592 package CPAN::Distribution;
594 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
596 package CPAN::Bundle;
598 @CPAN::Bundle::ISA = qw(CPAN::Module);
600 package CPAN::Module;
602 @CPAN::Module::ISA = qw(CPAN::InfoObj);
604 package CPAN::Exception::RecursiveDependency;
606 use overload '""' => "as_string";
608 # a module sees its distribution (no version)
609 # a distribution sees its prereqs (which are module names) (usually with versions)
610 # a bundle sees its module names and/or its distributions (no version)
615 my (@deps,%seen,$loop_starts_with);
616 DCHAIN: for my $dep (@$deps) {
617 push @deps, {name => $dep, display_as => $dep};
619 $loop_starts_with = $dep;
624 for my $i (0..$#deps) {
625 my $x = $deps[$i]{name};
626 $in_loop ||= $x eq $loop_starts_with;
627 my $xo = CPAN::Shell->expandany($x) or next;
628 if ($xo->isa("CPAN::Module")) {
629 my $have = $xo->inst_version || "N/A";
630 my($want,$d,$want_type);
631 if ($i>0 and $d = $deps[$i-1]{name}) {
632 my $do = CPAN::Shell->expandany($d);
633 $want = $do->{prereq_pm}{requires}{$x};
635 $want_type = "requires: ";
637 $want = $do->{prereq_pm}{build_requires}{$x};
639 $want_type = "build_requires: ";
641 $want_type = "unknown status";
646 $want = $xo->cpan_version;
647 $want_type = "want: ";
649 $deps[$i]{have} = $have;
650 $deps[$i]{want_type} = $want_type;
651 $deps[$i]{want} = $want;
652 $deps[$i]{display_as} = "$x (have: $have; $want_type$want)";
653 } elsif ($xo->isa("CPAN::Distribution")) {
654 $deps[$i]{display_as} = $xo->pretty_id;
656 $xo->{make} = CPAN::Distrostatus->new("NO cannot resolve circular dependency");
658 $xo->{make} = CPAN::Distrostatus->new("NO one dependency ($loop_starts_with) is a circular dependency");
660 $xo->store_persistent_state; # otherwise I will not reach
661 # all involved parties for
665 bless { deps => \@deps }, $class;
670 my $ret = "\nRecursive dependency detected:\n ";
671 $ret .= join("\n => ", map {$_->{display_as}} @{$self->{deps}});
672 $ret .= ".\nCannot resolve.\n";
676 package CPAN::Exception::yaml_not_installed;
678 use overload '""' => "as_string";
681 my($class,$module,$file,$during) = @_;
682 bless { module => $module, file => $file, during => $during }, $class;
687 "'$self->{module}' not installed, cannot $self->{during} '$self->{file}'\n";
690 package CPAN::Exception::yaml_process_error;
692 use overload '""' => "as_string";
695 my($class,$module,$file,$during,$error) = @_;
696 bless { module => $module,
699 error => $error }, $class;
704 if ($self->{during}) {
706 if ($self->{module}) {
707 if ($self->{error}) {
708 return "Alert: While trying to '$self->{during}' YAML file\n".
709 " '$self->{file}'\n".
710 "with '$self->{module}' the following error was encountered:\n".
713 return "Alert: While trying to '$self->{during}' YAML file\n".
714 " '$self->{file}'\n".
715 "with '$self->{module}' some unknown error was encountered\n";
718 return "Alert: While trying to '$self->{during}' YAML file\n".
719 " '$self->{file}'\n".
720 "some unknown error was encountered\n";
723 return "Alert: While trying to '$self->{during}' some YAML file\n".
724 "some unknown error was encountered\n";
727 return "Alert: unknown error encountered\n";
731 package CPAN::Prompt; use overload '""' => "as_string";
732 use vars qw($prompt);
734 $CPAN::CurrentCommandId ||= 0;
740 unless ($CPAN::META->{LOCK}) {
741 $word = "nolock_cpan";
743 if ($CPAN::Config->{commandnumber_in_prompt}) {
744 sprintf "$word\[%d]> ", $CPAN::CurrentCommandId;
750 package CPAN::URL; use overload '""' => "as_string", fallback => 1;
751 # accessors: TEXT(the url string), FROM(DEF=>defaultlist,USER=>urllist),
752 # planned are things like age or quality
754 my($class,%args) = @_;
766 $self->{TEXT} = $set;
771 package CPAN::Distrostatus;
772 use overload '""' => "as_string",
775 my($class,$arg) = @_;
778 FAILED => substr($arg,0,2) eq "NO",
779 COMMANDID => $CPAN::CurrentCommandId,
783 sub commandid { shift->{COMMANDID} }
784 sub failed { shift->{FAILED} }
788 $self->{TEXT} = $set;
808 @CPAN::Shell::ISA = qw(CPAN::Debug);
809 $COLOR_REGISTERED ||= 0;
812 '!' => "eval the rest of the line as perl",
814 autobundle => "wtite inventory into a bundle file",
815 b => "info about bundle",
817 clean => "clean up a distribution's build directory",
819 d => "info about a distribution",
822 failed => "list all failed actions within current session",
823 fforce => "redo a command from scratch",
824 force => "redo a command",
826 help => "overview over commands; 'help ...' explains specific commands",
827 hosts => "statistics about recently used hosts",
828 i => "info about authors/bundles/distributions/modules",
829 install => "install a distribution",
830 install_tested => "install all distributions tested OK",
831 is_tested => "list all distributions tested OK",
832 look => "open a subshell in a distribution's directory",
833 ls => "list distributions according to a glob",
834 m => "info about a module",
835 make => "make/build a distribution",
836 mkmyconfig => "write current config into a CPAN/MyConfig.pm file",
837 notest => "run a (usually install) command but leave out the test phase",
838 o => "'o conf ...' for config stuff; 'o debug ...' for debugging",
839 perldoc => "try to get a manpage for a module",
841 quit => "leave the cpan shell",
842 r => "review over upgradeable modules",
843 readme => "display the README of a distro woth a pager",
844 recent => "show recent uploads to the CPAN",
846 reload => "'reload cpan' or 'reload index'",
847 report => "test a distribution and send a test report to cpantesters",
848 reports => "info about reported tests from cpantesters",
851 test => "test a distribution",
852 u => "display uninstalled modules",
853 upgrade => "combine 'r' command with immediate installation",
856 $autoload_recursion ||= 0;
858 #-> sub CPAN::Shell::AUTOLOAD ;
860 $autoload_recursion++;
862 my $class = shift(@_);
863 # warn "autoload[$l] class[$class]";
866 warn "Refusing to autoload '$l' while signal pending";
867 $autoload_recursion--;
870 if ($autoload_recursion > 1) {
871 my $fullcommand = join " ", map { "'$_'" } $l, @_;
872 warn "Refusing to autoload $fullcommand in recursion\n";
873 $autoload_recursion--;
877 # XXX needs to be reconsidered
878 if ($CPAN::META->has_inst('CPAN::WAIT')) {
881 $CPAN::Frontend->mywarn(qq{
882 Commands starting with "w" require CPAN::WAIT to be installed.
883 Please consider installing CPAN::WAIT to use the fulltext index.
884 For this you just need to type
889 $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }.
893 $autoload_recursion--;
900 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
902 # from here on only subs.
903 ################################################################################
905 sub _perl_fingerprint {
906 my($self,$other_fingerprint) = @_;
907 my $dll = eval {OS2::DLLname()};
910 $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
912 my $mtime_perl = (-f $^X ? (stat(_))[9] : '-1');
913 my $this_fingerprint = {
915 sitearchexp => $Config::Config{sitearchexp},
916 'mtime_$^X' => $mtime_perl,
917 'mtime_dll' => $mtime_dll,
919 if ($other_fingerprint) {
920 if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
921 $other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
923 # mandatory keys since 1.88_57
924 for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
925 return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
929 return $this_fingerprint;
933 sub suggest_myconfig () {
934 SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
935 $CPAN::Frontend->myprint("You don't seem to have a user ".
936 "configuration (MyConfig.pm) yet.\n");
937 my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
938 "user configuration now? (Y/n)",
941 CPAN::Shell->mkmyconfig();
944 $CPAN::Frontend->mydie("OK, giving up.");
949 #-> sub CPAN::all_objects ;
951 my($mgr,$class) = @_;
952 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
953 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
955 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
958 # Called by shell, not in batch mode. In batch mode I see no risk in
959 # having many processes updating something as installations are
960 # continually checked at runtime. In shell mode I suspect it is
961 # unintentional to open more than one shell at a time
963 #-> sub CPAN::checklock ;
966 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
967 if (-f $lockfile && -M _ > 0) {
968 my $fh = FileHandle->new($lockfile) or
969 $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
970 my $otherpid = <$fh>;
971 my $otherhost = <$fh>;
973 if (defined $otherpid && $otherpid) {
976 if (defined $otherhost && $otherhost) {
979 my $thishost = hostname();
980 if (defined $otherhost && defined $thishost &&
981 $otherhost ne '' && $thishost ne '' &&
982 $otherhost ne $thishost) {
983 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
984 "reports other host $otherhost and other ".
985 "process $otherpid.\n".
986 "Cannot proceed.\n"));
987 } elsif ($RUN_DEGRADED) {
988 $CPAN::Frontend->mywarn("Running in degraded mode (experimental)\n");
989 } elsif (defined $otherpid && $otherpid) {
990 return if $$ == $otherpid; # should never happen
991 $CPAN::Frontend->mywarn(
993 There seems to be running another CPAN process (pid $otherpid). Contacting...
995 if (kill 0, $otherpid) {
996 $CPAN::Frontend->mywarn(qq{Other job is running.\n});
998 CPAN::Shell::colorable_makemaker_prompt
999 (qq{Shall I try to run in degraded }.
1000 qq{mode? (Y/n)},"y");
1001 if ($ans =~ /^y/i) {
1002 $CPAN::Frontend->mywarn("Running in degraded mode (experimental).
1003 Please report if something unexpected happens\n");
1005 for ($CPAN::Config) {
1007 # $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
1008 $_->{commandnumber_in_prompt} = 0; # visibility
1009 $_->{histfile} = ""; # who should win otherwise?
1010 $_->{cache_metadata} = 0; # better would be a lock?
1011 $_->{use_sqlite} = 0; # better would be a write lock!
1014 $CPAN::Frontend->mydie("
1015 You may want to kill the other job and delete the lockfile. On UNIX try:
1020 } elsif (-w $lockfile) {
1022 CPAN::Shell::colorable_makemaker_prompt
1023 (qq{Other job not responding. Shall I overwrite }.
1024 qq{the lockfile '$lockfile'? (Y/n)},"y");
1025 $CPAN::Frontend->myexit("Ok, bye\n")
1026 unless $ans =~ /^y/i;
1029 qq{Lockfile '$lockfile' not writeable by you. }.
1030 qq{Cannot proceed.\n}.
1031 qq{ On UNIX try:\n}.
1032 qq{ rm '$lockfile'\n}.
1033 qq{ and then rerun us.\n}
1037 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
1038 "'$lockfile', please remove. Cannot proceed.\n"));
1041 my $dotcpan = $CPAN::Config->{cpan_home};
1042 eval { File::Path::mkpath($dotcpan);};
1044 # A special case at least for Jarkko.
1045 my $firsterror = $@;
1049 $symlinkcpan = readlink $dotcpan;
1050 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
1051 eval { File::Path::mkpath($symlinkcpan); };
1055 $CPAN::Frontend->mywarn(qq{
1056 Working directory $symlinkcpan created.
1060 unless (-d $dotcpan) {
1062 Your configuration suggests "$dotcpan" as your
1063 CPAN.pm working directory. I could not create this directory due
1064 to this error: $firsterror\n};
1066 As "$dotcpan" is a symlink to "$symlinkcpan",
1067 I tried to create that, but I failed with this error: $seconderror
1070 Please make sure the directory exists and is writable.
1072 $CPAN::Frontend->mywarn($mess);
1073 return suggest_myconfig;
1075 } # $@ after eval mkpath $dotcpan
1076 if (0) { # to test what happens when a race condition occurs
1077 for (reverse 1..10) {
1083 if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
1085 unless ($fh = FileHandle->new("+>>$lockfile")) {
1086 if ($! =~ /Permission/) {
1087 $CPAN::Frontend->mywarn(qq{
1089 Your configuration suggests that CPAN.pm should use a working
1091 $CPAN::Config->{cpan_home}
1092 Unfortunately we could not create the lock file
1094 due to permission problems.
1096 Please make sure that the configuration variable
1097 \$CPAN::Config->{cpan_home}
1098 points to a directory where you can write a .lock file. You can set
1099 this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
1102 return suggest_myconfig;
1106 while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
1108 $CPAN::Frontend->mydie("Giving up\n");
1110 $CPAN::Frontend->mysleep($sleep++);
1111 $CPAN::Frontend->mywarn("Could not lock lockfile with flock: $!; retrying\n");
1116 $fh->print($$, "\n");
1117 $fh->print(hostname(), "\n");
1118 $self->{LOCK} = $lockfile;
1119 $self->{LOCKFH} = $fh;
1124 $CPAN::Frontend->mydie("Got SIG$sig, leaving");
1129 &cleanup if $Signal;
1130 die "Got yet another signal" if $Signal > 1;
1131 $CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
1132 $CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
1136 # From: Larry Wall <larry@wall.org>
1137 # Subject: Re: deprecating SIGDIE
1138 # To: perl5-porters@perl.org
1139 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
1141 # The original intent of __DIE__ was only to allow you to substitute one
1142 # kind of death for another on an application-wide basis without respect
1143 # to whether you were in an eval or not. As a global backstop, it should
1144 # not be used any more lightly (or any more heavily :-) than class
1145 # UNIVERSAL. Any attempt to build a general exception model on it should
1146 # be politely squashed. Any bug that causes every eval {} to have to be
1147 # modified should be not so politely squashed.
1149 # Those are my current opinions. It is also my optinion that polite
1150 # arguments degenerate to personal arguments far too frequently, and that
1151 # when they do, it's because both people wanted it to, or at least didn't
1152 # sufficiently want it not to.
1156 # global backstop to cleanup if we should really die
1157 $SIG{__DIE__} = \&cleanup;
1158 $self->debug("Signal handler set.") if $CPAN::DEBUG;
1161 #-> sub CPAN::DESTROY ;
1163 &cleanup; # need an eval?
1166 #-> sub CPAN::anycwd ;
1169 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
1174 sub cwd {Cwd::cwd();}
1176 #-> sub CPAN::getcwd ;
1177 sub getcwd {Cwd::getcwd();}
1179 #-> sub CPAN::fastcwd ;
1180 sub fastcwd {Cwd::fastcwd();}
1182 #-> sub CPAN::backtickcwd ;
1183 sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
1185 #-> sub CPAN::find_perl ;
1187 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
1188 my $pwd = $CPAN::iCwd = CPAN::anycwd();
1189 my $candidate = File::Spec->catfile($pwd,$^X);
1190 $perl ||= $candidate if MM->maybe_command($candidate);
1193 my ($component,$perl_name);
1194 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
1195 PATH_COMPONENT: foreach $component (File::Spec->path(),
1196 $Config::Config{'binexp'}) {
1197 next unless defined($component) && $component;
1198 my($abs) = File::Spec->catfile($component,$perl_name);
1199 if (MM->maybe_command($abs)) {
1211 #-> sub CPAN::exists ;
1213 my($mgr,$class,$id) = @_;
1214 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1215 CPAN::Index->reload;
1216 ### Carp::croak "exists called without class argument" unless $class;
1218 $id =~ s/:+/::/g if $class eq "CPAN::Module";
1220 if (CPAN::_sqlite_running) {
1221 $exists = (exists $META->{readonly}{$class}{$id} or
1222 $CPAN::SQLite->set($class, $id));
1224 $exists = exists $META->{readonly}{$class}{$id};
1226 $exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1229 #-> sub CPAN::delete ;
1231 my($mgr,$class,$id) = @_;
1232 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
1233 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
1236 #-> sub CPAN::has_usable
1237 # has_inst is sometimes too optimistic, we should replace it with this
1238 # has_usable whenever a case is given
1240 my($self,$mod,$message) = @_;
1241 return 1 if $HAS_USABLE->{$mod};
1242 my $has_inst = $self->has_inst($mod,$message);
1243 return unless $has_inst;
1246 LWP => [ # we frequently had "Can't locate object
1247 # method "new" via package "LWP::UserAgent" at
1248 # (eval 69) line 2006
1250 sub {require LWP::UserAgent},
1251 sub {require HTTP::Request},
1252 sub {require URI::URL},
1255 sub {require Net::FTP},
1256 sub {require Net::Config},
1258 'File::HomeDir' => [
1259 sub {require File::HomeDir;
1260 unless (File::HomeDir::->VERSION >= 0.52) {
1261 for ("Will not use File::HomeDir, need 0.52\n") {
1262 $CPAN::Frontend->mywarn($_);
1269 sub {require Archive::Tar;
1270 unless (Archive::Tar::->VERSION >= 1.00) {
1271 for ("Will not use Archive::Tar, need 1.00\n") {
1272 $CPAN::Frontend->mywarn($_);
1279 if ($usable->{$mod}) {
1280 for my $c (0..$#{$usable->{$mod}}) {
1281 my $code = $usable->{$mod}[$c];
1282 my $ret = eval { &$code() };
1283 $ret = "" unless defined $ret;
1285 # warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
1290 return $HAS_USABLE->{$mod} = 1;
1293 #-> sub CPAN::has_inst
1295 my($self,$mod,$message) = @_;
1296 Carp::croak("CPAN->has_inst() called without an argument")
1297 unless defined $mod;
1298 my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
1299 keys %{$CPAN::Config->{dontload_hash}||{}},
1300 @{$CPAN::Config->{dontload_list}||[]};
1301 if (defined $message && $message eq "no" # afair only used by Nox
1305 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
1313 # checking %INC is wrong, because $INC{LWP} may be true
1314 # although $INC{"URI/URL.pm"} may have failed. But as
1315 # I really want to say "bla loaded OK", I have to somehow
1317 ### warn "$file in %INC"; #debug
1319 } elsif (eval { require $file }) {
1320 # eval is good: if we haven't yet read the database it's
1321 # perfect and if we have installed the module in the meantime,
1322 # it tries again. The second require is only a NOOP returning
1323 # 1 if we had success, otherwise it's retrying
1325 my $mtime = (stat $INC{$file})[9];
1326 # privileged files loaded by has_inst; Note: we use $mtime
1327 # as a proxy for a checksum.
1328 $CPAN::Shell::reload->{$file} = $mtime;
1329 my $v = eval "\$$mod\::VERSION";
1330 $v = $v ? " (v$v)" : "";
1331 CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
1332 if ($mod eq "CPAN::WAIT") {
1333 push @CPAN::Shell::ISA, 'CPAN::WAIT';
1336 } elsif ($mod eq "Net::FTP") {
1337 $CPAN::Frontend->mywarn(qq{
1338 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
1340 install Bundle::libnet
1342 }) unless $Have_warned->{"Net::FTP"}++;
1343 $CPAN::Frontend->mysleep(3);
1344 } elsif ($mod eq "Digest::SHA") {
1345 if ($Have_warned->{"Digest::SHA"}++) {
1346 $CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
1347 qq{because Digest::SHA not installed.\n});
1349 $CPAN::Frontend->mywarn(qq{
1350 CPAN: checksum security checks disabled because Digest::SHA not installed.
1351 Please consider installing the Digest::SHA module.
1354 $CPAN::Frontend->mysleep(2);
1356 } elsif ($mod eq "Module::Signature") {
1357 # NOT prefs_lookup, we are not a distro
1358 my $check_sigs = $CPAN::Config->{check_sigs};
1359 if (not $check_sigs) {
1360 # they do not want us:-(
1361 } elsif (not $Have_warned->{"Module::Signature"}++) {
1362 # No point in complaining unless the user can
1363 # reasonably install and use it.
1364 if (eval { require Crypt::OpenPGP; 1 } ||
1366 defined $CPAN::Config->{'gpg'}
1368 $CPAN::Config->{'gpg'} =~ /\S/
1371 $CPAN::Frontend->mywarn(qq{
1372 CPAN: Module::Signature security checks disabled because Module::Signature
1373 not installed. Please consider installing the Module::Signature module.
1374 You may also need to be able to connect over the Internet to the public
1375 keyservers like pgp.mit.edu (port 11371).
1378 $CPAN::Frontend->mysleep(2);
1382 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
1387 #-> sub CPAN::instance ;
1389 my($mgr,$class,$id) = @_;
1390 CPAN::Index->reload;
1392 # unsafe meta access, ok?
1393 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
1394 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
1402 #-> sub CPAN::cleanup ;
1404 # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
1405 local $SIG{__DIE__} = '';
1410 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
1411 $ineval = 1, last if
1412 $subroutine eq '(eval)';
1414 return if $ineval && !$CPAN::End;
1415 return unless defined $META->{LOCK};
1416 return unless -f $META->{LOCK};
1418 close $META->{LOCKFH};
1419 unlink $META->{LOCK};
1421 # Carp::cluck("DEBUGGING");
1422 if ( $CPAN::CONFIG_DIRTY ) {
1423 $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
1425 $CPAN::Frontend->myprint("Lockfile removed.\n");
1428 #-> sub CPAN::readhist
1430 my($self,$term,$histfile) = @_;
1431 my($fh) = FileHandle->new;
1432 open $fh, "<$histfile" or last;
1436 $term->AddHistory($_);
1441 #-> sub CPAN::savehist
1444 my($histfile,$histsize);
1445 unless ($histfile = $CPAN::Config->{'histfile'}) {
1446 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
1449 $histsize = $CPAN::Config->{'histsize'} || 100;
1451 unless ($CPAN::term->can("GetHistory")) {
1452 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
1458 my @h = $CPAN::term->GetHistory;
1459 splice @h, 0, @h-$histsize if @h>$histsize;
1460 my($fh) = FileHandle->new;
1461 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
1462 local $\ = local $, = "\n";
1467 #-> sub CPAN::is_tested
1469 my($self,$what,$when) = @_;
1471 Carp::cluck("DEBUG: empty what");
1474 $self->{is_tested}{$what} = $when;
1477 #-> sub CPAN::is_installed
1478 # unsets the is_tested flag: as soon as the thing is installed, it is
1479 # not needed in set_perl5lib anymore
1481 my($self,$what) = @_;
1482 delete $self->{is_tested}{$what};
1485 sub _list_sorted_descending_is_tested {
1488 { ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
1489 keys %{$self->{is_tested}}
1492 #-> sub CPAN::set_perl5lib
1494 my($self,$for) = @_;
1496 (undef,undef,undef,$for) = caller(1);
1499 $self->{is_tested} ||= {};
1500 return unless %{$self->{is_tested}};
1501 my $env = $ENV{PERL5LIB};
1502 $env = $ENV{PERLLIB} unless defined $env;
1504 push @env, $env if defined $env and length $env;
1505 #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
1506 #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
1508 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
1510 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB for '$for'\n");
1511 } elsif (@dirs < 24) {
1512 my @d = map {my $cp = $_;
1513 $cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
1516 $CPAN::Frontend->myprint("Prepending @d to PERL5LIB; ".
1517 "%BUILDDIR%=$CPAN::Config->{build_dir} ".
1521 my $cnt = keys %{$self->{is_tested}};
1522 $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib of ".
1523 "$cnt build dirs to PERL5LIB; ".
1528 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
1531 package CPAN::CacheMgr;
1534 #-> sub CPAN::CacheMgr::as_string ;
1536 eval { require Data::Dumper };
1538 return shift->SUPER::as_string;
1540 return Data::Dumper::Dumper(shift);
1544 #-> sub CPAN::CacheMgr::cachesize ;
1549 #-> sub CPAN::CacheMgr::tidyup ;
1552 return unless $CPAN::META->{LOCK};
1553 return unless -d $self->{ID};
1554 my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
1555 for my $current (0..$#toremove) {
1556 my $toremove = $toremove[$current];
1557 $CPAN::Frontend->myprint(sprintf(
1558 "DEL(%d/%d): %s \n",
1564 return if $CPAN::Signal;
1565 $self->_clean_cache($toremove);
1566 return if $CPAN::Signal;
1570 #-> sub CPAN::CacheMgr::dir ;
1575 #-> sub CPAN::CacheMgr::entries ;
1577 my($self,$dir) = @_;
1578 return unless defined $dir;
1579 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
1580 $dir ||= $self->{ID};
1581 my($cwd) = CPAN::anycwd();
1582 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
1583 my $dh = DirHandle->new(File::Spec->curdir)
1584 or Carp::croak("Couldn't opendir $dir: $!");
1587 next if $_ eq "." || $_ eq "..";
1589 push @entries, File::Spec->catfile($dir,$_);
1591 push @entries, File::Spec->catdir($dir,$_);
1593 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
1596 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
1597 sort { -M $a <=> -M $b} @entries;
1600 #-> sub CPAN::CacheMgr::disk_usage ;
1602 my($self,$dir,$fast) = @_;
1603 return if exists $self->{SIZE}{$dir};
1604 return if $CPAN::Signal;
1609 unless (chmod 0755, $dir) {
1610 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
1611 "permission to change the permission; cannot ".
1612 "estimate disk usage of '$dir'\n");
1613 $CPAN::Frontend->mysleep(5);
1618 # nothing to say, no matter what the permissions
1621 $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
1625 $Du = 0; # placeholder
1629 $File::Find::prune++ if $CPAN::Signal;
1631 if ($^O eq 'MacOS') {
1633 my $cat = Mac::Files::FSpGetCatInfo($_);
1634 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
1638 unless (chmod 0755, $_) {
1639 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
1640 "the permission to change the permission; ".
1641 "can only partially estimate disk usage ".
1643 $CPAN::Frontend->mysleep(5);
1655 return if $CPAN::Signal;
1656 $self->{SIZE}{$dir} = $Du/1024/1024;
1657 unshift @{$self->{FIFO}}, $dir;
1658 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
1659 $self->{DU} += $Du/1024/1024;
1663 #-> sub CPAN::CacheMgr::_clean_cache ;
1665 my($self,$dir) = @_;
1666 return unless -e $dir;
1667 unless (File::Spec->canonpath(File::Basename::dirname($dir))
1668 eq File::Spec->canonpath($CPAN::Config->{build_dir})) {
1669 $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
1670 "will not remove\n");
1671 $CPAN::Frontend->mysleep(5);
1674 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
1676 File::Path::rmtree($dir);
1678 if ($dir !~ /\.yml$/ && -f "$dir.yml") {
1679 my $yaml_module = CPAN::_yaml_module;
1680 if ($CPAN::META->has_inst($yaml_module)) {
1681 my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
1683 $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
1684 unlink "$dir.yml" or
1685 $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
1687 } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
1688 $CPAN::META->delete("CPAN::Distribution", $id);
1690 # XXX we should restore the state NOW, otherise this
1691 # distro does not exist until we read an index. BUG ALERT(?)
1693 # $CPAN::Frontend->mywarn (" +++\n");
1697 unlink "$dir.yml"; # may fail
1698 unless ($id_deleted) {
1699 CPAN->debug("no distro found associated with '$dir'");
1702 $self->{DU} -= $self->{SIZE}{$dir};
1703 delete $self->{SIZE}{$dir};
1706 #-> sub CPAN::CacheMgr::new ;
1713 ID => $CPAN::Config->{build_dir},
1714 MAX => $CPAN::Config->{'build_cache'},
1715 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
1718 File::Path::mkpath($self->{ID});
1719 my $dh = DirHandle->new($self->{ID});
1720 bless $self, $class;
1723 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
1725 CPAN->debug($debug) if $CPAN::DEBUG;
1729 #-> sub CPAN::CacheMgr::scan_cache ;
1732 return if $self->{SCAN} eq 'never';
1733 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1734 unless $self->{SCAN} eq 'atstart';
1735 return unless $CPAN::META->{LOCK};
1736 $CPAN::Frontend->myprint(
1737 sprintf("Scanning cache %s for sizes\n",
1740 my @entries = $self->entries($self->{ID});
1745 if ($self->{DU} > $self->{MAX}) {
1747 $self->disk_usage($e,1);
1749 $self->disk_usage($e);
1752 while (($painted/76) < ($i/@entries)) {
1753 $CPAN::Frontend->myprint($symbol);
1756 return if $CPAN::Signal;
1758 $CPAN::Frontend->myprint("DONE\n");
1762 package CPAN::Shell;
1765 #-> sub CPAN::Shell::h ;
1767 my($class,$about) = @_;
1768 if (defined $about) {
1770 if (exists $Help->{$about}) {
1771 if (ref $Help->{$about}) { # aliases
1772 $about = ${$Help->{$about}};
1774 $help = $Help->{$about};
1776 $help = "No help available";
1778 $CPAN::Frontend->myprint("$about\: $help\n");
1780 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
1781 $CPAN::Frontend->myprint(qq{
1782 Display Information $filler (ver $CPAN::VERSION)
1783 command argument description
1784 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1785 i WORD or /REGEXP/ about any of the above
1786 ls AUTHOR or GLOB about files in the author's directory
1787 (with WORD being a module, bundle or author name or a distribution
1788 name of the form AUTHOR/DISTRIBUTION)
1790 Download, Test, Make, Install...
1791 get download clean make clean
1792 make make (implies get) look open subshell in dist directory
1793 test make test (implies make) readme display these README files
1794 install make install (implies test) perldoc display POD documentation
1797 r WORDs or /REGEXP/ or NONE report updates for some/matching/all modules
1798 upgrade WORDs or /REGEXP/ or NONE upgrade some/matching/all modules
1801 force CMD try hard to do command fforce CMD try harder
1802 notest CMD skip testing
1805 h,? display this menu ! perl-code eval a perl command
1806 o conf [opt] set and query options q quit the cpan shell
1807 reload cpan load CPAN.pm again reload index load newer indices
1808 autobundle Snapshot recent latest CPAN uploads});
1814 #-> sub CPAN::Shell::a ;
1816 my($self,@arg) = @_;
1817 # authors are always UPPERCASE
1819 $_ = uc $_ unless /=/;
1821 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1824 #-> sub CPAN::Shell::globls ;
1826 my($self,$s,$pragmas) = @_;
1827 # ls is really very different, but we had it once as an ordinary
1828 # command in the Shell (upto rev. 321) and we could not handle
1830 my(@accept,@preexpand);
1831 if ($s =~ /[\*\?\/]/) {
1832 if ($CPAN::META->has_inst("Text::Glob")) {
1833 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
1834 my $rau = Text::Glob::glob_to_regex(uc $au);
1835 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
1837 push @preexpand, map { $_->id . "/" . $pathglob }
1838 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
1840 my $rau = Text::Glob::glob_to_regex(uc $s);
1841 push @preexpand, map { $_->id }
1842 CPAN::Shell->expand_by_method('CPAN::Author',
1847 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
1850 push @preexpand, uc $s;
1853 unless (/^[A-Z0-9\-]+(\/|$)/i) {
1854 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1859 my $silent = @accept>1;
1860 my $last_alpha = "";
1862 for my $a (@accept) {
1863 my($author,$pathglob);
1864 if ($a =~ m|(.*?)/(.*)|) {
1867 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1870 or $CPAN::Frontend->mydie("No author found for $a2\n");
1872 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1875 or $CPAN::Frontend->mydie("No author found for $a\n");
1878 my $alpha = substr $author->id, 0, 1;
1880 if ($alpha eq $last_alpha) {
1884 $last_alpha = $alpha;
1886 $CPAN::Frontend->myprint($ad);
1888 for my $pragma (@$pragmas) {
1889 if ($author->can($pragma)) {
1893 push @results, $author->ls($pathglob,$silent); # silent if
1896 for my $pragma (@$pragmas) {
1897 my $unpragma = "un$pragma";
1898 if ($author->can($unpragma)) {
1899 $author->$unpragma();
1906 #-> sub CPAN::Shell::local_bundles ;
1908 my($self,@which) = @_;
1909 my($incdir,$bdir,$dh);
1910 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1911 my @bbase = "Bundle";
1912 while (my $bbase = shift @bbase) {
1913 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1914 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1915 if ($dh = DirHandle->new($bdir)) { # may fail
1917 for $entry ($dh->read) {
1918 next if $entry =~ /^\./;
1919 next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
1920 if (-d File::Spec->catdir($bdir,$entry)) {
1921 push @bbase, "$bbase\::$entry";
1923 next unless $entry =~ s/\.pm(?!\n)\Z//;
1924 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1932 #-> sub CPAN::Shell::b ;
1934 my($self,@which) = @_;
1935 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1936 $self->local_bundles;
1937 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1940 #-> sub CPAN::Shell::d ;
1941 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1943 #-> sub CPAN::Shell::m ;
1944 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1946 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1949 #-> sub CPAN::Shell::i ;
1953 @args = '/./' unless @args;
1955 for my $type (qw/Bundle Distribution Module/) {
1956 push @result, $self->expand($type,@args);
1958 # Authors are always uppercase.
1959 push @result, $self->expand("Author", map { uc $_ } @args);
1961 my $result = @result == 1 ?
1962 $result[0]->as_string :
1964 "No objects found of any type for argument @args\n" :
1966 (map {$_->as_glimpse} @result),
1967 scalar @result, " items found\n",
1969 $CPAN::Frontend->myprint($result);
1972 #-> sub CPAN::Shell::o ;
1974 # CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o
1975 # conf' calls through to CPAN::HandleConfig::edit. 'o conf' should
1976 # probably have been called 'set' and 'o debug' maybe 'set debug' or
1977 # 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
1979 my($self,$o_type,@o_what) = @_;
1981 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1982 if ($o_type eq 'conf') {
1983 my($cfilter) = $o_what[0] =~ m|^/(.*)/$|;
1984 if (!@o_what or $cfilter) { # print all things, "o conf"
1986 my $qrfilter = eval 'qr/$cfilter/';
1988 $CPAN::Frontend->myprint("\$CPAN::Config options from ");
1990 if (exists $INC{'CPAN/Config.pm'}) {
1991 push @from, $INC{'CPAN/Config.pm'};
1993 if (exists $INC{'CPAN/MyConfig.pm'}) {
1994 push @from, $INC{'CPAN/MyConfig.pm'};
1996 $CPAN::Frontend->myprint(join " and ", map {"'$_'"} @from);
1997 $CPAN::Frontend->myprint(":\n");
1998 for $k (sort keys %CPAN::HandleConfig::can) {
1999 next unless $k =~ /$qrfilter/;
2000 $v = $CPAN::HandleConfig::can{$k};
2001 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
2003 $CPAN::Frontend->myprint("\n");
2004 for $k (sort keys %CPAN::HandleConfig::keys) {
2005 next unless $k =~ /$qrfilter/;
2006 CPAN::HandleConfig->prettyprint($k);
2008 $CPAN::Frontend->myprint("\n");
2010 if (CPAN::HandleConfig->edit(@o_what)) {
2012 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
2016 } elsif ($o_type eq 'debug') {
2018 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
2021 my($what) = shift @o_what;
2022 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
2023 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
2026 if ( exists $CPAN::DEBUG{$what} ) {
2027 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
2028 } elsif ($what =~ /^\d/) {
2029 $CPAN::DEBUG = $what;
2030 } elsif (lc $what eq 'all') {
2032 for (values %CPAN::DEBUG) {
2035 $CPAN::DEBUG = $max;
2038 for (keys %CPAN::DEBUG) {
2039 next unless lc($_) eq lc($what);
2040 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
2043 $CPAN::Frontend->myprint("unknown argument [$what]\n")
2048 my $raw = "Valid options for debug are ".
2049 join(", ",sort(keys %CPAN::DEBUG), 'all').
2050 qq{ or a number. Completion works on the options. }.
2051 qq{Case is ignored.};
2053 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
2054 $CPAN::Frontend->myprint("\n\n");
2057 $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n");
2059 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
2060 $v = $CPAN::DEBUG{$k};
2061 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
2062 if $v & $CPAN::DEBUG;
2065 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
2068 $CPAN::Frontend->myprint(qq{
2070 conf set or get configuration variables
2071 debug set or get debugging options
2076 # CPAN::Shell::paintdots_onreload
2077 sub paintdots_onreload {
2080 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
2084 # $CPAN::Frontend->myprint(".($subr)");
2085 $CPAN::Frontend->myprint(".");
2086 if ($subr =~ /\bshell\b/i) {
2087 # warn "debug[$_[0]]";
2089 # It would be nice if we could detect that a
2090 # subroutine has actually changed, but for now we
2091 # practically always set the GOTOSHELL global
2101 #-> sub CPAN::Shell::hosts ;
2104 my $fullstats = CPAN::FTP->_ftp_statistics();
2105 my $history = $fullstats->{history} || [];
2107 while (my $last = pop @$history) {
2108 my $attempts = $last->{attempts} or next;
2111 $start = $attempts->[-1]{start};
2112 if ($#$attempts > 0) {
2113 for my $i (0..$#$attempts-1) {
2114 my $url = $attempts->[$i]{url} or next;
2119 $start = $last->{start};
2121 next unless $last->{thesiteurl}; # C-C? bad filenames?
2123 $S{end} ||= $last->{end};
2124 my $dltime = $last->{end} - $start;
2125 my $dlsize = $last->{filesize} || 0;
2126 my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
2127 my $s = $S{ok}{$url} ||= {};
2130 $s->{dlsize} += $dlsize/1024;
2132 $s->{dltime} += $dltime;
2135 for my $url (keys %{$S{ok}}) {
2136 next if $S{ok}{$url}{dltime} == 0; # div by zero
2137 push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)},
2138 $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime},
2142 for my $url (keys %{$S{no}}) {
2143 push @{$res->{no}}, [$S{no}{$url},
2147 my $R = ""; # report
2148 if ($S{start} && $S{end}) {
2149 $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown";
2150 $R .= sprintf "Log ends : %s\n", $S{end} ? scalar(localtime $S{end}) : "unknown";
2152 if ($res->{ok} && @{$res->{ok}}) {
2153 $R .= sprintf "\nSuccessful downloads:
2154 N kB secs kB/s url\n";
2156 for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) {
2157 $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_;
2161 if ($res->{no} && @{$res->{no}}) {
2162 $R .= sprintf "\nUnsuccessful downloads:\n";
2164 for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) {
2165 $R .= sprintf "%4d %s\n", @$_;
2169 $CPAN::Frontend->myprint($R);
2172 #-> sub CPAN::Shell::reload ;
2174 my($self,$command,@arg) = @_;
2176 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
2177 if ($command =~ /^cpan$/i) {
2179 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
2184 "CPAN/FirstTime.pm",
2185 "CPAN/HandleConfig.pm",
2188 "CPAN/Reporter/Config.pm",
2189 "CPAN/Reporter/History.pm",
2195 MFILE: for my $f (@relo) {
2196 next unless exists $INC{$f};
2200 $CPAN::Frontend->myprint("($p");
2201 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
2202 $self->_reload_this($f) or $failed++;
2203 my $v = eval "$p\::->VERSION";
2204 $CPAN::Frontend->myprint("v$v)");
2206 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
2208 my $errors = $failed == 1 ? "error" : "errors";
2209 $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ".
2212 } elsif ($command =~ /^index$/i) {
2213 CPAN::Index->force_reload;
2215 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN modules
2216 index re-reads the index files\n});
2220 # reload means only load again what we have loaded before
2221 #-> sub CPAN::Shell::_reload_this ;
2223 my($self,$f,$args) = @_;
2224 CPAN->debug("f[$f]") if $CPAN::DEBUG;
2225 return 1 unless $INC{$f}; # we never loaded this, so we do not
2227 my $pwd = CPAN::anycwd();
2228 CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG;
2230 for my $inc (@INC) {
2231 $file = File::Spec->catfile($inc,split /\//, $f);
2235 CPAN->debug("file[$file]") if $CPAN::DEBUG;
2237 unless ($file && -f $file) {
2238 # this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
2240 unless (CPAN->has_inst("File::Basename")) {
2241 @inc = File::Basename::dirname($file);
2243 # do we ever need this?
2244 @inc = substr($file,0,-length($f)-1); # bring in back to me!
2247 CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
2249 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
2252 my $mtime = (stat $file)[9];
2253 if ($reload->{$f}) {
2254 } elsif ($^T < $mtime) {
2255 # since we started the file has changed, force it to be reloaded
2258 $reload->{$f} = $mtime;
2260 my $must_reload = $mtime != $reload->{$f};
2262 $must_reload ||= $args->{reloforce}; # o conf defaults needs this
2264 my $fh = FileHandle->new($file) or
2265 $CPAN::Frontend->mydie("Could not open $file: $!");
2268 my $content = <$fh>;
2269 CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128)))
2273 eval "require '$f'";
2278 $reload->{$f} = $mtime;
2280 $CPAN::Frontend->myprint("__unchanged__");
2285 #-> sub CPAN::Shell::mkmyconfig ;
2287 my($self, $cpanpm, %args) = @_;
2288 require CPAN::FirstTime;
2289 my $home = CPAN::HandleConfig::home;
2290 $cpanpm = $INC{'CPAN/MyConfig.pm'} ||
2291 File::Spec->catfile(split /\//, "$home/.cpan/CPAN/MyConfig.pm");
2292 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
2293 CPAN::HandleConfig::require_myconfig_or_config;
2294 $CPAN::Config ||= {};
2299 keep_source_where => undef,
2302 CPAN::FirstTime::init($cpanpm, %args);
2305 #-> sub CPAN::Shell::_binary_extensions ;
2306 sub _binary_extensions {
2307 my($self) = shift @_;
2308 my(@result,$module,%seen,%need,$headerdone);
2309 for $module ($self->expand('Module','/./')) {
2310 my $file = $module->cpan_file;
2311 next if $file eq "N/A";
2312 next if $file =~ /^Contact Author/;
2313 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
2314 next if $dist->isa_perl;
2315 next unless $module->xs_file;
2317 $CPAN::Frontend->myprint(".");
2318 push @result, $module;
2320 # print join " | ", @result;
2321 $CPAN::Frontend->myprint("\n");
2325 #-> sub CPAN::Shell::recompile ;
2327 my($self) = shift @_;
2328 my($module,@module,$cpan_file,%dist);
2329 @module = $self->_binary_extensions();
2330 for $module (@module) { # we force now and compile later, so we
2332 $cpan_file = $module->cpan_file;
2333 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2335 $dist{$cpan_file}++;
2337 for $cpan_file (sort keys %dist) {
2338 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
2339 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
2341 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
2342 # stop a package from recompiling,
2343 # e.g. IO-1.12 when we have perl5.003_10
2347 #-> sub CPAN::Shell::scripts ;
2349 my($self, $arg) = @_;
2350 $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n");
2352 for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) {
2353 unless ($CPAN::META->has_inst($req)) {
2354 $CPAN::Frontend->mywarn(" $req not available\n");
2357 my $p = HTML::LinkExtor->new();
2358 my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html";
2359 unless (-f $indexfile) {
2360 $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n");
2362 $p->parse_file($indexfile);
2365 if ($arg =~ s|^/(.+)/$|$1|) {
2366 $qrarg = eval 'qr/$arg/'; # hide construct from 5.004
2368 for my $l ($p->links) {
2369 my $tag = shift @$l;
2370 next unless $tag eq "a";
2372 my $href = $att{href};
2373 next unless $href =~ s|^\.\./authors/id/./../||;
2376 if ($href =~ $qrarg) {
2380 if ($href =~ /\Q$arg\E/) {
2388 # now filter for the latest version if there is more than one of a name
2394 $stems{$stem} ||= [];
2395 push @{$stems{$stem}}, $href;
2397 for (sort keys %stems) {
2399 if (@{$stems{$_}} > 1) {
2400 $highest = List::Util::reduce {
2401 Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b
2404 $highest = $stems{$_}[0];
2406 $CPAN::Frontend->myprint("$highest\n");
2410 #-> sub CPAN::Shell::report ;
2412 my($self,@args) = @_;
2413 unless ($CPAN::META->has_inst("CPAN::Reporter")) {
2414 $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
2416 local $CPAN::Config->{test_report} = 1;
2417 $self->force("test",@args); # force is there so that the test be
2418 # re-run (as documented)
2421 # compare with is_tested
2422 #-> sub CPAN::Shell::install_tested
2423 sub install_tested {
2424 my($self,@some) = @_;
2425 $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"),
2427 CPAN::Index->reload;
2429 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2430 my $yaml = "$b.yml";
2432 $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
2435 my $yaml_content = CPAN->_yaml_loadfile($yaml);
2436 my $id = $yaml_content->[0]{distribution}{ID};
2438 $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
2441 my $do = CPAN::Shell->expandany($id);
2443 $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n");
2446 unless ($do->{build_dir}) {
2447 $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n");
2450 unless ($do->{build_dir} eq $b) {
2451 $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n");
2457 $CPAN::Frontend->mywarn("No tested distributions found.\n"),
2458 return unless @some;
2460 @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some;
2461 $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"),
2462 return unless @some;
2464 # @some = grep { not $_->uptodate } @some;
2465 # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"),
2466 # return unless @some;
2468 CPAN->debug("some[@some]");
2470 my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id;
2471 $CPAN::Frontend->myprint("install_tested: Running for $id\n");
2472 $CPAN::Frontend->mysleep(1);
2477 #-> sub CPAN::Shell::upgrade ;
2479 my($self,@args) = @_;
2480 $self->install($self->r(@args));
2483 #-> sub CPAN::Shell::_u_r_common ;
2485 my($self) = shift @_;
2486 my($what) = shift @_;
2487 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
2488 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
2489 $what && $what =~ /^[aru]$/;
2491 @args = '/./' unless @args;
2492 my(@result,$module,%seen,%need,$headerdone,
2493 $version_undefs,$version_zeroes,
2494 @version_undefs,@version_zeroes);
2495 $version_undefs = $version_zeroes = 0;
2496 my $sprintf = "%s%-25s%s %9s %9s %s\n";
2497 my @expand = $self->expand('Module',@args);
2498 my $expand = scalar @expand;
2499 if (0) { # Looks like noise to me, was very useful for debugging
2500 # for metadata cache
2501 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
2503 MODULE: for $module (@expand) {
2504 my $file = $module->cpan_file;
2505 next MODULE unless defined $file; # ??
2506 $file =~ s!^./../!!;
2507 my($latest) = $module->cpan_version;
2508 my($inst_file) = $module->inst_file;
2510 return if $CPAN::Signal;
2513 $have = $module->inst_version;
2514 } elsif ($what eq "r") {
2515 $have = $module->inst_version;
2517 if ($have eq "undef") {
2519 push @version_undefs, $module->as_glimpse;
2520 } elsif (CPAN::Version->vcmp($have,0)==0) {
2522 push @version_zeroes, $module->as_glimpse;
2524 next MODULE unless CPAN::Version->vgt($latest, $have);
2525 # to be pedantic we should probably say:
2526 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
2527 # to catch the case where CPAN has a version 0 and we have a version undef
2528 } elsif ($what eq "u") {
2534 } elsif ($what eq "r") {
2536 } elsif ($what eq "u") {
2540 return if $CPAN::Signal; # this is sometimes lengthy
2543 push @result, sprintf "%s %s\n", $module->id, $have;
2544 } elsif ($what eq "r") {
2545 push @result, $module->id;
2546 next MODULE if $seen{$file}++;
2547 } elsif ($what eq "u") {
2548 push @result, $module->id;
2549 next MODULE if $seen{$file}++;
2550 next MODULE if $file =~ /^Contact/;
2552 unless ($headerdone++) {
2553 $CPAN::Frontend->myprint("\n");
2554 $CPAN::Frontend->myprint(sprintf(
2557 "Package namespace",
2569 $CPAN::META->has_inst("Term::ANSIColor")
2571 $module->description
2573 $color_on = Term::ANSIColor::color("green");
2574 $color_off = Term::ANSIColor::color("reset");
2576 $CPAN::Frontend->myprint(sprintf $sprintf,
2583 $need{$module->id}++;
2587 $CPAN::Frontend->myprint("No modules found for @args\n");
2588 } elsif ($what eq "r") {
2589 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
2593 if ($version_zeroes) {
2594 my $s_has = $version_zeroes > 1 ? "s have" : " has";
2595 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
2596 qq{a version number of 0\n});
2597 if ($CPAN::Config->{show_zero_versions}) {
2599 $CPAN::Frontend->myprint(qq{ they are\n\t@version_zeroes\n});
2600 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }.
2601 qq{to hide them)\n});
2603 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }.
2604 qq{to show them)\n});
2607 if ($version_undefs) {
2608 my $s_has = $version_undefs > 1 ? "s have" : " has";
2609 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
2610 qq{parseable version number\n});
2611 if ($CPAN::Config->{show_unparsable_versions}) {
2613 $CPAN::Frontend->myprint(qq{ they are\n\t@version_undefs\n});
2614 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }.
2615 qq{to hide them)\n});
2617 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }.
2618 qq{to show them)\n});
2625 #-> sub CPAN::Shell::r ;
2627 shift->_u_r_common("r",@_);
2630 #-> sub CPAN::Shell::u ;
2632 shift->_u_r_common("u",@_);
2635 #-> sub CPAN::Shell::failed ;
2637 my($self,$only_id,$silent) = @_;
2639 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
2641 NAY: for my $nosayer ( # order matters!
2650 next unless exists $d->{$nosayer};
2651 next unless defined $d->{$nosayer};
2653 UNIVERSAL::can($d->{$nosayer},"failed") ?
2654 $d->{$nosayer}->failed :
2655 $d->{$nosayer} =~ /^NO/
2657 next NAY if $only_id && $only_id != (
2658 UNIVERSAL::can($d->{$nosayer},"commandid")
2660 $d->{$nosayer}->commandid
2662 $CPAN::CurrentCommandId
2667 next DIST unless $failed;
2671 # " %-45s: %s %s\n",
2674 UNIVERSAL::can($d->{$failed},"failed") ?
2676 $d->{$failed}->commandid,
2679 $d->{$failed}->text,
2680 $d->{$failed}{TIME}||0,
2693 $scope = "this command";
2694 } elsif ($CPAN::Index::HAVE_REANIMATED) {
2695 $scope = "this or a previous session";
2696 # it might be nice to have a section for previous session and
2699 $scope = "this session";
2706 map { sprintf "%5d %-45s: %s %s\n", @$_ }
2707 sort { $a->[0] <=> $b->[0] } @failed;
2710 map { sprintf " %-45s: %s %s\n", @$_[1..3] }
2717 $CPAN::Frontend->myprint("Failed during $scope:\n$print");
2718 } elsif (!$only_id || !$silent) {
2719 $CPAN::Frontend->myprint("Nothing failed in $scope\n");
2723 # XXX intentionally undocumented because completely bogus, unportable,
2726 #-> sub CPAN::Shell::status ;
2729 require Devel::Size;
2730 my $ps = FileHandle->new;
2731 open $ps, "/proc/$$/status";
2734 next unless /VmSize:\s+(\d+)/;
2738 $CPAN::Frontend->mywarn(sprintf(
2739 "%-27s %6d\n%-27s %6d\n",
2743 Devel::Size::total_size($CPAN::META)/1024,
2745 for my $k (sort keys %$CPAN::META) {
2746 next unless substr($k,0,4) eq "read";
2747 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
2748 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
2749 warn sprintf " %-25s %6d (keys: %6d)\n",
2751 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
2752 scalar keys %{$CPAN::META->{$k}{$k2}};
2757 # compare with install_tested
2758 #-> sub CPAN::Shell::is_tested
2761 CPAN::Index->reload;
2762 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
2764 if ($CPAN::META->{is_tested}{$b}) {
2765 $time = scalar(localtime $CPAN::META->{is_tested}{$b});
2767 $time = scalar localtime;
2770 $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b);
2774 #-> sub CPAN::Shell::autobundle ;
2777 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
2778 my(@bundle) = $self->_u_r_common("a",@_);
2779 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
2780 File::Path::mkpath($todir);
2781 unless (-d $todir) {
2782 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
2785 my($y,$m,$d) = (localtime)[5,4,3];
2789 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
2790 my($to) = File::Spec->catfile($todir,"$me.pm");
2792 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
2793 $to = File::Spec->catfile($todir,"$me.pm");
2795 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
2797 "package Bundle::$me;\n\n",
2798 "\$VERSION = '0.01';\n\n",
2802 "Bundle::$me - Snapshot of installation on ",
2803 $Config::Config{'myhostname'},
2806 "\n\n=head1 SYNOPSIS\n\n",
2807 "perl -MCPAN -e 'install Bundle::$me'\n\n",
2808 "=head1 CONTENTS\n\n",
2809 join("\n", @bundle),
2810 "\n\n=head1 CONFIGURATION\n\n",
2812 "\n\n=head1 AUTHOR\n\n",
2813 "This Bundle has been generated automatically ",
2814 "by the autobundle routine in CPAN.pm.\n",
2817 $CPAN::Frontend->myprint("\nWrote bundle file
2821 #-> sub CPAN::Shell::expandany ;
2824 CPAN->debug("s[$s]") if $CPAN::DEBUG;
2825 if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
2826 $s = CPAN::Distribution->normalize($s);
2827 return $CPAN::META->instance('CPAN::Distribution',$s);
2828 # Distributions spring into existence, not expand
2829 } elsif ($s =~ m|^Bundle::|) {
2830 $self->local_bundles; # scanning so late for bundles seems
2831 # both attractive and crumpy: always
2832 # current state but easy to forget
2834 return $self->expand('Bundle',$s);
2836 return $self->expand('Module',$s)
2837 if $CPAN::META->exists('CPAN::Module',$s);
2842 #-> sub CPAN::Shell::expand ;
2845 my($type,@args) = @_;
2846 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
2847 my $class = "CPAN::$type";
2848 my $methods = ['id'];
2849 for my $meth (qw(name)) {
2850 next unless $class->can($meth);
2851 push @$methods, $meth;
2853 $self->expand_by_method($class,$methods,@args);
2856 #-> sub CPAN::Shell::expand_by_method ;
2857 sub expand_by_method {
2859 my($class,$methods,@args) = @_;
2862 my($regex,$command);
2863 if ($arg =~ m|^/(.*)/$|) {
2865 } elsif ($arg =~ m/=/) {
2869 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
2871 defined $regex ? $regex : "UNDEFINED",
2872 defined $command ? $command : "UNDEFINED",
2874 if (defined $regex) {
2875 if (CPAN::_sqlite_running) {
2876 $CPAN::SQLite->search($class, $regex);
2879 $CPAN::META->all_objects($class)
2881 unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) {
2882 # BUG, we got an empty object somewhere
2883 require Data::Dumper;
2884 CPAN->debug(sprintf(
2885 "Bug in CPAN: Empty id on obj[%s][%s]",
2887 Data::Dumper::Dumper($obj)
2891 for my $method (@$methods) {
2892 my $match = eval {$obj->$method() =~ /$regex/i};
2894 my($err) = $@ =~ /^(.+) at .+? line \d+\.$/;
2895 $err ||= $@; # if we were too restrictive above
2896 $CPAN::Frontend->mydie("$err\n");
2903 } elsif ($command) {
2904 die "equal sign in command disabled (immature interface), ".
2906 ! \$CPAN::Shell::ADVANCED_QUERY=1
2907 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
2908 that may go away anytime.\n"
2909 unless $ADVANCED_QUERY;
2910 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
2911 my($matchcrit) = $criterion =~ m/^~(.+)/;
2915 $CPAN::META->all_objects($class)
2917 my $lhs = $self->$method() or next; # () for 5.00503
2919 push @m, $self if $lhs =~ m/$matchcrit/;
2921 push @m, $self if $lhs eq $criterion;
2926 if ( $class eq 'CPAN::Bundle' ) {
2927 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
2928 } elsif ($class eq "CPAN::Distribution") {
2929 $xarg = CPAN::Distribution->normalize($arg);
2933 if ($CPAN::META->exists($class,$xarg)) {
2934 $obj = $CPAN::META->instance($class,$xarg);
2935 } elsif ($CPAN::META->exists($class,$arg)) {
2936 $obj = $CPAN::META->instance($class,$arg);
2943 @m = sort {$a->id cmp $b->id} @m;
2944 if ( $CPAN::DEBUG ) {
2945 my $wantarray = wantarray;
2946 my $join_m = join ",", map {$_->id} @m;
2947 $self->debug("wantarray[$wantarray]join_m[$join_m]");
2949 return wantarray ? @m : $m[0];
2952 #-> sub CPAN::Shell::format_result ;
2955 my($type,@args) = @_;
2956 @args = '/./' unless @args;
2957 my(@result) = $self->expand($type,@args);
2958 my $result = @result == 1 ?
2959 $result[0]->as_string :
2961 "No objects of type $type found for argument @args\n" :
2963 (map {$_->as_glimpse} @result),
2964 scalar @result, " items found\n",
2969 #-> sub CPAN::Shell::report_fh ;
2971 my $installation_report_fh;
2972 my $previously_noticed = 0;
2975 return $installation_report_fh if $installation_report_fh;
2976 if ($CPAN::META->has_inst("File::Temp")) {
2977 $installation_report_fh
2979 dir => File::Spec->tmpdir,
2980 template => 'cpan_install_XXXX',
2985 unless ( $installation_report_fh ) {
2986 warn("Couldn't open installation report file; " .
2987 "no report file will be generated."
2988 ) unless $previously_noticed++;
2994 # The only reason for this method is currently to have a reliable
2995 # debugging utility that reveals which output is going through which
2996 # channel. No, I don't like the colors ;-)
2998 # to turn colordebugging on, write
2999 # cpan> o conf colorize_output 1
3001 #-> sub CPAN::Shell::print_ornamented ;
3003 my $print_ornamented_have_warned = 0;
3004 sub colorize_output {
3005 my $colorize_output = $CPAN::Config->{colorize_output};
3006 if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
3007 unless ($print_ornamented_have_warned++) {
3008 # no myprint/mywarn within myprint/mywarn!
3009 warn "Colorize_output is set to true but Term::ANSIColor is not
3010 installed. To activate colorized output, please install Term::ANSIColor.\n\n";
3012 $colorize_output = 0;
3014 return $colorize_output;
3019 #-> sub CPAN::Shell::print_ornamented ;
3020 sub print_ornamented {
3021 my($self,$what,$ornament) = @_;
3022 return unless defined $what;
3024 local $| = 1; # Flush immediately
3025 if ( $CPAN::Be_Silent ) {
3026 print {report_fh()} $what;
3029 my $swhat = "$what"; # stringify if it is an object
3030 if ($CPAN::Config->{term_is_latin}) {
3031 # note: deprecated, need to switch to $LANG and $LC_*
3034 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
3036 if ($self->colorize_output) {
3037 if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) {
3038 # if you want to have this configurable, please file a bugreport
3039 $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan";
3041 my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
3043 print "Term::ANSIColor rejects color[$ornament]: $@\n
3044 Please choose a different color (Hint: try 'o conf init /color/')\n";
3046 # GGOLDBACH/Test-GreaterVersion-0.008 broke wthout this
3047 # $trailer construct. We want the newline be the last thing if
3048 # there is a newline at the end ensuring that the next line is
3049 # empty for other players
3051 $trailer = $1 if $swhat =~ s/([\r\n]+)\z//;
3054 Term::ANSIColor::color("reset"),
3061 #-> sub CPAN::Shell::myprint ;
3063 # where is myprint/mywarn/Frontend/etc. documented? Where to use what?
3064 # I think, we send everything to STDOUT and use print for normal/good
3065 # news and warn for news that need more attention. Yes, this is our
3066 # working contract for now.
3068 my($self,$what) = @_;
3069 $self->print_ornamented($what,
3070 $CPAN::Config->{colorize_print}||'bold blue on_white',
3075 my($self,$category,$what) = @_;
3076 my $vname = $category . "_verbosity";
3077 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
3078 if (!$CPAN::Config->{$vname}
3079 || $CPAN::Config->{$vname} =~ /^v/
3081 $CPAN::Frontend->myprint($what);
3085 #-> sub CPAN::Shell::myexit ;
3087 my($self,$what) = @_;
3088 $self->myprint($what);
3092 #-> sub CPAN::Shell::mywarn ;
3094 my($self,$what) = @_;
3095 $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
3098 # only to be used for shell commands
3099 #-> sub CPAN::Shell::mydie ;
3101 my($self,$what) = @_;
3102 $self->mywarn($what);
3104 # If it is the shell, we want the following die to be silent,
3105 # but if it is not the shell, we would need a 'die $what'. We need
3106 # to take care that only shell commands use mydie. Is this
3112 # sub CPAN::Shell::colorable_makemaker_prompt ;
3113 sub colorable_makemaker_prompt {
3115 if (CPAN::Shell->colorize_output) {
3116 my $ornament = $CPAN::Config->{colorize_print}||'bold blue on_white';
3117 my $color_on = eval { Term::ANSIColor::color($ornament); } || "";
3120 my $ans = ExtUtils::MakeMaker::prompt($foo,$bar);
3121 if (CPAN::Shell->colorize_output) {
3122 print Term::ANSIColor::color('reset');
3127 # use this only for unrecoverable errors!
3128 #-> sub CPAN::Shell::unrecoverable_error ;
3129 sub unrecoverable_error {
3130 my($self,$what) = @_;
3131 my @lines = split /\n/, $what;
3133 for my $l (@lines) {
3134 $longest = length $l if length $l > $longest;
3136 $longest = 62 if $longest > 62;
3137 for my $l (@lines) {
3138 if ($l =~ /^\s*$/) {
3143 if (length $l < 66) {
3144 $l = pack "A66 A*", $l, "<==";
3148 unshift @lines, "\n";
3149 $self->mydie(join "", @lines);
3152 #-> sub CPAN::Shell::mysleep ;
3154 my($self, $sleep) = @_;
3155 if (CPAN->has_inst("Time::HiRes")) {
3156 Time::HiRes::sleep($sleep);
3158 sleep($sleep < 1 ? 1 : int($sleep + 0.5));
3162 #-> sub CPAN::Shell::setup_output ;
3164 return if -t STDOUT;
3165 my $odef = select STDERR;
3172 #-> sub CPAN::Shell::rematein ;
3173 # RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here
3176 my($meth,@some) = @_;
3178 while($meth =~ /^(ff?orce|notest)$/) {
3179 push @pragma, $meth;
3180 $meth = shift @some or
3181 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
3185 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
3187 # Here is the place to set "test_count" on all involved parties to
3188 # 0. We then can pass this counter on to the involved
3189 # distributions and those can refuse to test if test_count > X. In
3190 # the first stab at it we could use a 1 for "X".
3192 # But when do I reset the distributions to start with 0 again?
3193 # Jost suggested to have a random or cycling interaction ID that
3194 # we pass through. But the ID is something that is just left lying
3195 # around in addition to the counter, so I'd prefer to set the
3196 # counter to 0 now, and repeat at the end of the loop. But what
3197 # about dependencies? They appear later and are not reset, they
3198 # enter the queue but not its copy. How do they get a sensible
3201 # With configure_requires, "get" is vulnerable in recursion.
3203 my $needs_recursion_protection = "get|make|test|install";
3205 # construct the queue
3207 STHING: foreach $s (@some) {
3210 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
3212 } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
3213 } elsif ($s =~ m|^/|) { # looks like a regexp
3214 if (substr($s,-1,1) eq ".") {
3215 $obj = CPAN::Shell->expandany($s);
3217 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
3218 "not supported.\nRejecting argument '$s'\n");
3219 $CPAN::Frontend->mysleep(2);
3222 } elsif ($meth eq "ls") {
3223 $self->globls($s,\@pragma);
3226 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
3227 $obj = CPAN::Shell->expandany($s);
3230 } elsif (ref $obj) {
3231 if ($meth =~ /^($needs_recursion_protection)$/) {
3232 # it would be silly to check for recursion for look or dump
3233 # (we are in CPAN::Shell::rematein)
3234 CPAN->debug("Going to test against recursion") if $CPAN::DEBUG;
3235 eval { $obj->color_cmd_tmps(0,1); };
3238 and $@->isa("CPAN::Exception::RecursiveDependency")) {
3239 $CPAN::Frontend->mywarn($@);
3243 Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@);
3249 CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c");
3251 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
3252 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
3253 if ($meth =~ /^(dump|ls|reports)$/) {
3256 $CPAN::Frontend->mywarn(
3258 "Don't be silly, you can't $meth ",
3262 $CPAN::Frontend->mysleep(2);
3264 } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") {
3265 CPAN::InfoObj->dump($s);
3268 ->mywarn(qq{Warning: Cannot $meth $s, }.
3269 qq{don't know what it is.
3274 to find objects with matching identifiers.
3276 $CPAN::Frontend->mysleep(2);
3280 # queuerunner (please be warned: when I started to change the
3281 # queue to hold objects instead of names, I made one or two
3282 # mistakes and never found which. I reverted back instead)
3283 while (my $q = CPAN::Queue->first) {
3285 my $s = $q->as_string;
3286 my $reqtype = $q->reqtype || "";
3287 $obj = CPAN::Shell->expandany($s);
3289 # don't know how this can happen, maybe we should panic,
3290 # but maybe we get a solution from the first user who hits
3291 # this unfortunate exception?
3292 $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
3293 "to an object. Skipping.\n");
3294 $CPAN::Frontend->mysleep(5);
3295 CPAN::Queue->delete_first($s);
3298 $obj->{reqtype} ||= "";
3300 # force debugging because CPAN::SQLite somehow delivers us
3303 # local $CPAN::DEBUG = 1024; # Shell; probably fixed now
3305 CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]".
3306 "q-reqtype[$reqtype]") if $CPAN::DEBUG;
3308 if ($obj->{reqtype}) {
3309 if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) {
3310 $obj->{reqtype} = $reqtype;
3312 exists $obj->{install}
3315 UNIVERSAL::can($obj->{install},"failed") ?
3316 $obj->{install}->failed :
3317 $obj->{install} =~ /^NO/
3320 delete $obj->{install};
3321 $CPAN::Frontend->mywarn
3322 ("Promoting $obj->{ID} from 'build_requires' to 'requires'");
3326 $obj->{reqtype} = $reqtype;
3329 for my $pragma (@pragma) {
3332 $obj->can($pragma)) {
3333 $obj->$pragma($meth);
3336 if (UNIVERSAL::can($obj, 'called_for')) {
3337 $obj->called_for($s);
3339 CPAN->debug(qq{pragma[@pragma]meth[$meth]}.
3340 qq{ID[$obj->{ID}]}) if $CPAN::DEBUG;
3343 if ($meth =~ /^(report)$/) { # they came here with a pragma?
3345 } elsif (! UNIVERSAL::can($obj,$meth)) {
3347 my $serialized = "";
3349 } elsif ($CPAN::META->has_inst("YAML::Syck")) {
3350 $serialized = YAML::Syck::Dump($obj);
3351 } elsif ($CPAN::META->has_inst("YAML")) {
3352 $serialized = YAML::Dump($obj);
3353 } elsif ($CPAN::META->has_inst("Data::Dumper")) {
3354 $serialized = Data::Dumper::Dumper($obj);
3357 $serialized = overload::StrVal($obj);
3359 CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
3360 $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
3361 } elsif ($obj->$meth()) {
3362 CPAN::Queue->delete($s);
3363 CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG;
3365 CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG;
3369 for my $pragma (@pragma) {
3370 my $unpragma = "un$pragma";
3371 if ($obj->can($unpragma)) {
3375 CPAN::Queue->delete_first($s);
3377 if ($meth =~ /^($needs_recursion_protection)$/) {
3378 for my $obj (@qcopy) {
3379 $obj->color_cmd_tmps(0,0);
3384 #-> sub CPAN::Shell::recent ;
3387 if ($CPAN::META->has_inst("XML::LibXML")) {
3388 my $url = $CPAN::Defaultrecent;
3389 $CPAN::Frontend->myprint("Going to fetch '$url'\n");
3390 unless ($CPAN::META->has_usable("LWP")) {
3391 $CPAN::Frontend->mydie("LWP not installed; cannot continue");
3393 CPAN::LWP::UserAgent->config;
3395 eval { $Ua = CPAN::LWP::UserAgent->new; };
3397 $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
3399 my $resp = $Ua->get($url);
3400 unless ($resp->is_success) {
3401 $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
3403 $CPAN::Frontend->myprint("DONE\n\n");
3404 my $xml = XML::LibXML->new->parse_string($resp->content);
3406 my $s = $xml->serialize(2);
3407 $s =~ s/\n\s*\n/\n/g;
3408 $CPAN::Frontend->myprint($s);
3412 if ($url =~ /winnipeg/) {
3413 my $pubdate = $xml->findvalue("/rss/channel/pubDate");
3414 $CPAN::Frontend->myprint(" pubDate: $pubdate\n\n");
3415 for my $eitem ($xml->findnodes("/rss/channel/item")) {
3416 my $distro = $eitem->findvalue("enclosure/\@url");
3417 $distro =~ s|.*?/authors/id/./../||;
3418 my $size = $eitem->findvalue("enclosure/\@length");
3419 my $desc = $eitem->findvalue("description");
3420 \0 $desc =~ s/.+? - //;
3421 $CPAN::Frontend->myprint("$distro [$size b]\n $desc\n");
3422 push @distros, $distro;
3424 } elsif ($url =~ /search.*uploads.rdf/) {
3425 # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
3426 # xmlns="http://purl.org/rss/1.0/"
3427 # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
3428 # xmlns:dc="http://purl.org/dc/elements/1.1/"
3429 # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
3430 # xmlns:admin="http://webns.net/mvcb/"
3433 my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']");
3434 $CPAN::Frontend->myprint(" dc:date: $dc_date\n\n");
3435 my $finish_eitem = 0;
3436 local $SIG{INT} = sub { $finish_eitem = 1 };
3437 EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) {
3438 my $distro = $eitem->findvalue("\@rdf:about");
3439 $distro =~ s|.*~||; # remove up to the tilde before the name
3440 $distro =~ s|/$||; # remove trailing slash
3441 $distro =~ s|([^/]+)|\U$1\E|; # upcase the name
3442 my $author = uc $1 or die "distro[$distro] without author, cannot continue";
3443 my $desc = $eitem->findvalue("*[local-name(.) = 'description']");
3445 SUBDIRTEST: while () {
3446 last SUBDIRTEST if ++$i >= 6; # half a dozen must do!
3447 if (my @ret = $self->globls("$distro*")) {
3448 @ret = grep {$_->[2] !~ /meta/} @ret;
3449 @ret = grep {length $_->[2]} @ret;
3451 $distro = "$author/$ret[0][2]";
3455 $distro =~ s|/|/*/|; # allow it to reside in a subdirectory
3458 next EITEM if $distro =~ m|\*|; # did not find the thing
3459 $CPAN::Frontend->myprint("____$desc\n");
3460 push @distros, $distro;
3461 last EITEM if $finish_eitem;
3466 # deprecated old version
3467 $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n");
3471 #-> sub CPAN::Shell::smoke ;
3474 my $distros = $self->recent;
3475 DISTRO: for my $distro (@$distros) {
3476 $CPAN::Frontend->myprint(sprintf "Going to download and test '$distro'\n");
3479 local $SIG{INT} = sub { $skip = 1 };
3481 $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_);
3484 $CPAN::Frontend->myprint(" skipped\n");
3489 $CPAN::Frontend->myprint("\r \n"); # leave the dirty line with a newline
3490 $self->test($distro);
3495 # set up the dispatching methods
3497 for my $command (qw(
3514 *$command = sub { shift->rematein($command, @_); };
3518 package CPAN::LWP::UserAgent;
3522 return if $SETUPDONE;
3523 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3524 require LWP::UserAgent;
3525 @ISA = qw(Exporter LWP::UserAgent);
3528 $CPAN::Frontend->mywarn(" LWP::UserAgent not available\n");
3532 sub get_basic_credentials {
3533 my($self, $realm, $uri, $proxy) = @_;
3534 if ($USER && $PASSWD) {
3535 return ($USER, $PASSWD);
3538 ($USER,$PASSWD) = $self->get_proxy_credentials();
3540 ($USER,$PASSWD) = $self->get_non_proxy_credentials();
3542 return($USER,$PASSWD);
3545 sub get_proxy_credentials {
3547 my ($user, $password);
3548 if ( defined $CPAN::Config->{proxy_user} &&
3549 defined $CPAN::Config->{proxy_pass}) {
3550 $user = $CPAN::Config->{proxy_user};
3551 $password = $CPAN::Config->{proxy_pass};
3552 return ($user, $password);
3554 my $username_prompt = "\nProxy authentication needed!
3555 (Note: to permanently configure username and password run
3556 o conf proxy_user your_username
3557 o conf proxy_pass your_password
3559 ($user, $password) =
3560 _get_username_and_password_from_user($username_prompt);
3561 return ($user,$password);
3564 sub get_non_proxy_credentials {
3566 my ($user,$password);
3567 if ( defined $CPAN::Config->{username} &&
3568 defined $CPAN::Config->{password}) {
3569 $user = $CPAN::Config->{username};
3570 $password = $CPAN::Config->{password};
3571 return ($user, $password);
3573 my $username_prompt = "\nAuthentication needed!
3574 (Note: to permanently configure username and password run
3575 o conf username your_username
3576 o conf password your_password
3579 ($user, $password) =
3580 _get_username_and_password_from_user($username_prompt);
3581 return ($user,$password);
3584 sub _get_username_and_password_from_user {
3585 my $username_message = shift;
3586 my ($username,$password);
3588 ExtUtils::MakeMaker->import(qw(prompt));
3589 $username = prompt($username_message);
3590 if ($CPAN::META->has_inst("Term::ReadKey")) {
3591 Term::ReadKey::ReadMode("noecho");
3594 $CPAN::Frontend->mywarn(
3595 "Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n"
3598 $password = prompt("Password:");
3600 if ($CPAN::META->has_inst("Term::ReadKey")) {
3601 Term::ReadKey::ReadMode("restore");
3603 $CPAN::Frontend->myprint("\n\n");
3604 return ($username,$password);
3607 # mirror(): Its purpose is to deal with proxy authentication. When we
3608 # call SUPER::mirror, we relly call the mirror method in
3609 # LWP::UserAgent. LWP::UserAgent will then call
3610 # $self->get_basic_credentials or some equivalent and this will be
3611 # $self->dispatched to our own get_basic_credentials method.
3613 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3615 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3616 # although we have gone through our get_basic_credentials, the proxy
3617 # server refuses to connect. This could be a case where the username or
3618 # password has changed in the meantime, so I'm trying once again without
3619 # $USER and $PASSWD to give the get_basic_credentials routine another
3620 # chance to set $USER and $PASSWD.
3622 # mirror(): Its purpose is to deal with proxy authentication. When we
3623 # call SUPER::mirror, we relly call the mirror method in
3624 # LWP::UserAgent. LWP::UserAgent will then call
3625 # $self->get_basic_credentials or some equivalent and this will be
3626 # $self->dispatched to our own get_basic_credentials method.
3628 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
3630 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
3631 # although we have gone through our get_basic_credentials, the proxy
3632 # server refuses to connect. This could be a case where the username or
3633 # password has changed in the meantime, so I'm trying once again without
3634 # $USER and $PASSWD to give the get_basic_credentials routine another
3635 # chance to set $USER and $PASSWD.
3638 my($self,$url,$aslocal) = @_;
3639 my $result = $self->SUPER::mirror($url,$aslocal);
3640 if ($result->code == 407) {
3643 $result = $self->SUPER::mirror($url,$aslocal);
3651 #-> sub CPAN::FTP::ftp_statistics
3652 # if they want to rewrite, they need to pass in a filehandle
3653 sub _ftp_statistics {
3655 my $locktype = $fh ? LOCK_EX : LOCK_SH;
3656 $fh ||= FileHandle->new;
3657 my $file = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3658 open $fh, "+>>$file" or $CPAN::Frontend->mydie("Could not open '$file': $!");
3661 while (!CPAN::_flock($fh, $locktype|LOCK_NB)) {
3662 $waitstart ||= localtime();
3664 $CPAN::Frontend->mywarn("Waiting for a read lock on '$file' (since $waitstart)\n");
3666 $CPAN::Frontend->mysleep($sleep);
3669 } elsif ($sleep <=6) {
3673 my $stats = eval { CPAN->_yaml_loadfile($file); };
3676 if (ref $@ eq "CPAN::Exception::yaml_not_installed") {
3677 $CPAN::Frontend->myprint("Warning (usually harmless): $@");
3679 } elsif (ref $@ eq "CPAN::Exception::yaml_process_error") {
3680 $CPAN::Frontend->mydie($@);
3683 $CPAN::Frontend->mydie($@);
3689 #-> sub CPAN::FTP::_mytime
3691 if (CPAN->has_inst("Time::HiRes")) {
3692 return Time::HiRes::time();
3698 #-> sub CPAN::FTP::_new_stats
3700 my($self,$file) = @_;
3709 #-> sub CPAN::FTP::_add_to_statistics
3710 sub _add_to_statistics {
3711 my($self,$stats) = @_;
3712 my $yaml_module = CPAN::_yaml_module;
3713 $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG;
3714 if ($CPAN::META->has_inst($yaml_module)) {
3715 $stats->{thesiteurl} = $ThesiteURL;
3716 if (CPAN->has_inst("Time::HiRes")) {
3717 $stats->{end} = Time::HiRes::time();
3719 $stats->{end} = time;
3721 my $fh = FileHandle->new;
3725 @debug = $time if $sdebug;
3726 my $fullstats = $self->_ftp_statistics($fh);
3728 $fullstats->{history} ||= [];
3729 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3730 push @debug, time if $sdebug;
3731 push @{$fullstats->{history}}, $stats;
3732 # arbitrary hardcoded constants until somebody demands to have
3733 # them settable; YAML.pm 0.62 is unacceptably slow with 999;
3734 # YAML::Syck 0.82 has no noticable performance problem with 999;
3736 @{$fullstats->{history}} > 99
3737 || $time - $fullstats->{history}[0]{start} > 14*86400
3739 shift @{$fullstats->{history}}
3741 push @debug, scalar @{$fullstats->{history}} if $sdebug;
3742 push @debug, time if $sdebug;
3743 push @debug, scalar localtime($fullstats->{history}[0]{start}) if $sdebug;
3744 # need no eval because if this fails, it is serious
3745 my $sfile = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
3746 CPAN->_yaml_dumpfile("$sfile.$$",$fullstats);
3748 local $CPAN::DEBUG = 512; # FTP
3750 CPAN->debug(sprintf("DEBUG history: before_read[%d]before[%d]at[%d]".
3751 "after[%d]at[%d]oldest[%s]dumped backat[%d]",
3755 # Win32 cannot rename a file to an existing filename
3756 unlink($sfile) if ($^O eq 'MSWin32');
3757 rename "$sfile.$$", $sfile
3758 or $CPAN::Frontend->mydie("Could not rename '$sfile.$$' to '$sfile': $!\n");
3762 # if file is CHECKSUMS, suggest the place where we got the file to be
3763 # checked from, maybe only for young files?
3764 #-> sub CPAN::FTP::_recommend_url_for
3765 sub _recommend_url_for {
3766 my($self, $file) = @_;
3767 my $urllist = $self->_get_urllist;
3768 if ($file =~ s|/CHECKSUMS(.gz)?$||) {
3769 my $fullstats = $self->_ftp_statistics();
3770 my $history = $fullstats->{history} || [];
3771 while (my $last = pop @$history) {
3772 last if $last->{end} - time > 3600; # only young results are interesting
3773 next unless $last->{file}; # dirname of nothing dies!
3774 next unless $file eq File::Basename::dirname($last->{file});
3775 return $last->{thesiteurl};
3778 if ($CPAN::Config->{randomize_urllist}
3780 rand(1) < $CPAN::Config->{randomize_urllist}
3782 $urllist->[int rand scalar @$urllist];
3788 #-> sub CPAN::FTP::_get_urllist
3791 $CPAN::Config->{urllist} ||= [];
3792 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
3793 $CPAN::Frontend->mywarn("Malformed urllist; ignoring. Configuration file corrupt?\n");
3794 $CPAN::Config->{urllist} = [];
3796 my @urllist = grep { defined $_ and length $_ } @{$CPAN::Config->{urllist}};
3797 for my $u (@urllist) {
3798 CPAN->debug("u[$u]") if $CPAN::DEBUG;
3799 if (UNIVERSAL::can($u,"text")) {
3800 $u->{TEXT} .= "/" unless substr($u->{TEXT},-1) eq "/";
3802 $u .= "/" unless substr($u,-1) eq "/";
3803 $u = CPAN::URL->new(TEXT => $u, FROM => "USER");
3809 #-> sub CPAN::FTP::ftp_get ;
3811 my($class,$host,$dir,$file,$target) = @_;
3813 qq[Going to fetch file [$file] from dir [$dir]
3814 on host [$host] as local [$target]\n]
3816 my $ftp = Net::FTP->new($host);
3818 $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
3821 return 0 unless defined $ftp;
3822 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
3823 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
3824 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ) {
3825 my $msg = $ftp->message;
3826 $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
3829 unless ( $ftp->cwd($dir) ) {
3830 my $msg = $ftp->message;
3831 $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
3835 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
3836 unless ( $ftp->get($file,$target) ) {
3837 my $msg = $ftp->message;
3838 $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
3841 $ftp->quit; # it's ok if this fails
3845 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
3847 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
3848 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
3850 # > *** 1562,1567 ****
3851 # > --- 1562,1580 ----
3852 # > return 1 if substr($url,0,4) eq "file";
3853 # > return 1 unless $url =~ m|://([^/]+)|;
3855 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
3857 # > + $proxy =~ m|://([^/:]+)|;
3859 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
3860 # > + if ($noproxy) {
3861 # > + if ($host !~ /$noproxy$/) {
3862 # > + $host = $proxy;
3865 # > + $host = $proxy;
3868 # > require Net::Ping;
3869 # > return 1 unless $Net::Ping::VERSION >= 2;
3873 #-> sub CPAN::FTP::localize ;
3875 my($self,$file,$aslocal,$force) = @_;
3877 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
3878 unless defined $aslocal;
3879 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
3882 if ($^O eq 'MacOS') {
3883 # Comment by AK on 2000-09-03: Uniq short filenames would be
3884 # available in CHECKSUMS file
3885 my($name, $path) = File::Basename::fileparse($aslocal, '');
3886 if (length($name) > 31) {
3897 my $size = 31 - length($suf);
3898 while (length($name) > $size) {
3902 $aslocal = File::Spec->catfile($path, $name);
3906 if (-f $aslocal && -r _ && !($force & 1)) {
3908 if ($size = -s $aslocal) {
3909 $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG;
3912 # empty file from a previous unsuccessful attempt to download it
3914 $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I ".
3915 "could not remove.");
3918 my($maybe_restore) = 0;
3920 rename $aslocal, "$aslocal.bak$$";
3924 my($aslocal_dir) = File::Basename::dirname($aslocal);
3925 $self->mymkpath($aslocal_dir); # too early for file URLs / RT #28438
3926 # Inheritance is not easier to manage than a few if/else branches
3927 if ($CPAN::META->has_usable('LWP::UserAgent')) {
3929 CPAN::LWP::UserAgent->config;
3930 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
3932 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
3936 $Ua->proxy('ftp', $var)
3937 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
3938 $Ua->proxy('http', $var)
3939 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
3941 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
3945 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
3946 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
3949 # Try the list of urls for each single object. We keep a record
3950 # where we did get a file from
3951 my(@reordered,$last);
3952 my $ccurllist = $self->_get_urllist;
3953 $last = $#$ccurllist;
3954 if ($force & 2) { # local cpans probably out of date, don't reorder
3955 @reordered = (0..$last);
3959 (substr($ccurllist->[$b],0,4) eq "file")
3961 (substr($ccurllist->[$a],0,4) eq "file")
3963 defined($ThesiteURL)
3965 ($ccurllist->[$b] eq $ThesiteURL)
3967 ($ccurllist->[$a] eq $ThesiteURL)
3972 $self->debug("Themethod[$Themethod]reordered[@reordered]") if $CPAN::DEBUG;
3978 ["dleasy", "http","defaultsites"],
3979 ["dlhard", "http","defaultsites"],
3980 ["dleasy", "ftp", "defaultsites"],
3981 ["dlhard", "ftp", "defaultsites"],
3982 ["dlhardest","", "defaultsites"],
3985 @levels = grep {$_->[0] eq $Themethod} @all_levels;
3986 push @levels, grep {$_->[0] ne $Themethod} @all_levels;
3988 @levels = @all_levels;
3990 @levels = qw/dleasy/ if $^O eq 'MacOS';
3992 local $ENV{FTP_PASSIVE} =
3993 exists $CPAN::Config->{ftp_passive} ?
3994 $CPAN::Config->{ftp_passive} : 1;
3996 my $stats = $self->_new_stats($file);
3997 LEVEL: for $levelno (0..$#levels) {
3998 my $level_tuple = $levels[$levelno];
3999 my($level,$scheme,$sitetag) = @$level_tuple;
4000 my $defaultsites = $sitetag && $sitetag eq "defaultsites";
4002 if ($defaultsites) {
4003 unless (defined $connect_to_internet_ok) {
4004 $CPAN::Frontend->myprint(sprintf qq{
4005 I would like to connect to one of the following sites to get '%s':
4010 join("",map { " ".$_->text."\n" } @CPAN::Defaultsites),
4012 my $answer = CPAN::Shell::colorable_makemaker_prompt("Is it OK to try to connect to the Internet?", "yes");
4013 if ($answer =~ /^y/i) {
4014 $connect_to_internet_ok = 1;
4016 $connect_to_internet_ok = 0;
4019 if ($connect_to_internet_ok) {
4020 @urllist = @CPAN::Defaultsites;
4025 my @host_seq = $level =~ /dleasy/ ?
4026 @reordered : 0..$last; # reordered has file and $Thesiteurl first
4027 @urllist = map { $ccurllist->[$_] } @host_seq;
4029 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4030 my $aslocal_tempfile = $aslocal . ".tmp" . $$;
4031 if (my $recommend = $self->_recommend_url_for($file)) {
4032 @urllist = grep { $_ ne $recommend } @urllist;
4033 unshift @urllist, $recommend;
4035 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
4036 $ret = $self->hostdlxxx($level,$scheme,\@urllist,$file,$aslocal_tempfile,$stats);
4038 CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG;
4039 if ($ret eq $aslocal_tempfile) {
4040 # if we got it exactly as we asked for, only then we
4042 rename $aslocal_tempfile, $aslocal
4043 or $CPAN::Frontend->mydie("Error while trying to rename ".
4044 "'$ret' to '$aslocal': $!");
4047 $Themethod = $level;
4049 # utime $now, $now, $aslocal; # too bad, if we do that, we
4050 # might alter a local mirror
4051 $self->debug("level[$level]") if $CPAN::DEBUG;
4054 unlink $aslocal_tempfile;
4055 last if $CPAN::Signal; # need to cleanup
4059 $stats->{filesize} = -s $ret;
4061 $self->debug("before _add_to_statistics") if $CPAN::DEBUG;
4062 $self->_add_to_statistics($stats);
4063 $self->debug("after _add_to_statistics") if $CPAN::DEBUG;
4065 unlink "$aslocal.bak$$";
4068 unless ($CPAN::Signal) {
4071 if (@{$CPAN::Config->{urllist}}) {
4073 qq{Please check, if the URLs I found in your configuration file \(}.
4074 join(", ", @{$CPAN::Config->{urllist}}).
4077 push @mess, qq{Your urllist is empty!};
4079 push @mess, qq{The urllist can be edited.},
4080 qq{E.g. with 'o conf urllist push ftp://myurl/'};
4081 $CPAN::Frontend->mywarn(Text::Wrap::wrap("","","@mess"). "\n\n");
4082 $CPAN::Frontend->mywarn("Could not fetch $file\n");
4083 $CPAN::Frontend->mysleep(2);
4085 if ($maybe_restore) {
4086 rename "$aslocal.bak$$", $aslocal;
4087 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
4088 $self->ls($aslocal));
4095 my($self, $aslocal_dir) = @_;
4096 File::Path::mkpath($aslocal_dir);
4097 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
4098 qq{directory "$aslocal_dir".
4099 I\'ll continue, but if you encounter problems, they may be due
4100 to insufficient permissions.\n}) unless -w $aslocal_dir;
4108 $h = [ grep /^\Q$scheme\E:/, @$h ] if $scheme;
4109 my $method = "host$level";
4110 $self->$method($h, @_);
4114 my($self,$stats,$method,$url) = @_;
4115 push @{$stats->{attempts}}, {
4122 # package CPAN::FTP;
4124 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4126 HOSTEASY: for $ro_url (@$host_seq) {
4127 $self->_set_attempt($stats,"dleasy",$ro_url);
4128 my $url .= "$ro_url$file";
4129 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
4130 if ($url =~ /^file:/) {
4132 if ($CPAN::META->has_inst('URI::URL')) {
4133 my $u = URI::URL->new($url);
4135 } else { # works only on Unix, is poorly constructed, but
4136 # hopefully better than nothing.
4137 # RFC 1738 says fileurl BNF is
4138 # fileurl = "file://" [ host | "localhost" ] "/" fpath
4139 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
4141 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
4142 $l =~ s|^file:||; # assume they
4146 if ! -f $l && $l =~ m|^/\w:|; # e.g. /P:
4148 $self->debug("local file[$l]") if $CPAN::DEBUG;
4149 if ( -f $l && -r _) {
4150 $ThesiteURL = $ro_url;
4153 if ($l =~ /(.+)\.gz$/) {
4155 if ( -f $ungz && -r _) {
4156 $ThesiteURL = $ro_url;
4160 # Maybe mirror has compressed it?
4162 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
4163 eval { CPAN::Tarzip->new("$l.gz")->gunzip($aslocal) };
4165 $ThesiteURL = $ro_url;
4169 $CPAN::Frontend->mywarn("Could not find '$l'\n");
4171 $self->debug("it was not a file URL") if $CPAN::DEBUG;
4172 if ($CPAN::META->has_usable('LWP')) {
4173 $CPAN::Frontend->myprint("Fetching with LWP:
4177 CPAN::LWP::UserAgent->config;
4178 eval { $Ua = CPAN::LWP::UserAgent->new; };
4180 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
4183 my $res = $Ua->mirror($url, $aslocal);
4184 if ($res->is_success) {
4185 $ThesiteURL = $ro_url;
4187 utime $now, $now, $aslocal; # download time is more
4188 # important than upload
4191 } elsif ($url !~ /\.gz(?!\n)\Z/) {
4192 my $gzurl = "$url.gz";
4193 $CPAN::Frontend->myprint("Fetching with LWP:
4196 $res = $Ua->mirror($gzurl, "$aslocal.gz");
4197 if ($res->is_success) {
4198 if (eval {CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)}) {
4199 $ThesiteURL = $ro_url;
4204 $CPAN::Frontend->myprint(sprintf(
4205 "LWP failed with code[%s] message[%s]\n",
4209 # Alan Burlison informed me that in firewall environments
4210 # Net::FTP can still succeed where LWP fails. So we do not
4211 # skip Net::FTP anymore when LWP is available.
4214 $CPAN::Frontend->mywarn(" LWP not available\n");
4216 return if $CPAN::Signal;
4217 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4218 # that's the nice and easy way thanks to Graham
4219 $self->debug("recognized ftp") if $CPAN::DEBUG;
4220 my($host,$dir,$getfile) = ($1,$2,$3);
4221 if ($CPAN::META->has_usable('Net::FTP')) {
4223 $CPAN::Frontend->myprint("Fetching with Net::FTP:
4226 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
4227 "aslocal[$aslocal]") if $CPAN::DEBUG;
4228 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
4229 $ThesiteURL = $ro_url;
4232 if ($aslocal !~ /\.gz(?!\n)\Z/) {
4233 my $gz = "$aslocal.gz";
4234 $CPAN::Frontend->myprint("Fetching with Net::FTP
4237 if (CPAN::FTP->ftp_get($host,
4241 eval{CPAN::Tarzip->new($gz)->gunzip($aslocal)}
4243 $ThesiteURL = $ro_url;
4249 CPAN->debug("Net::FTP does not count as usable atm") if $CPAN::DEBUG;
4253 UNIVERSAL::can($ro_url,"text")
4255 $ro_url->{FROM} eq "USER"
4257 ##address #17973: default URLs should not try to override
4258 ##user-defined URLs just because LWP is not available
4259 my $ret = $self->hostdlhard([$ro_url],$file,$aslocal,$stats);
4260 return $ret if $ret;
4262 return if $CPAN::Signal;
4266 # package CPAN::FTP;
4268 my($self,$host_seq,$file,$aslocal,$stats) = @_;
4270 # Came back if Net::FTP couldn't establish connection (or
4271 # failed otherwise) Maybe they are behind a firewall, but they
4272 # gave us a socksified (or other) ftp program...
4275 my($devnull) = $CPAN::Config->{devnull} || "";
4277 my($aslocal_dir) = File::Basename::dirname($aslocal);
4278 File::Path::mkpath($aslocal_dir);
4279 HOSTHARD: for $ro_url (@$host_seq) {
4280 $self->_set_attempt($stats,"dlhard",$ro_url);
4281 my $url = "$ro_url$file";
4282 my($proto,$host,$dir,$getfile);
4284 # Courtesy Mark Conty mark_conty@cargill.com change from
4285 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
4287 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
4288 # proto not yet used
4289 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
4291 next HOSTHARD; # who said, we could ftp anything except ftp?
4293 next HOSTHARD if $proto eq "file"; # file URLs would have had
4294 # success above. Likely a bogus URL
4296 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
4298 # Try the most capable first and leave ncftp* for last as it only
4300 DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) {
4301 my $funkyftp = CPAN::HandleConfig->safe_quote($CPAN::Config->{$f});
4302 next unless defined $funkyftp;
4303 next if $funkyftp =~ /^\s*$/;
4305 my($asl_ungz, $asl_gz);
4306 ($asl_ungz = $aslocal) =~ s/\.gz//;
4307 $asl_gz = "$asl_ungz.gz";
4309 my($src_switch) = "";
4311 my($stdout_redir) = " > $asl_ungz";
4313 $src_switch = " -source";
4314 } elsif ($f eq "ncftp") {
4315 $src_switch = " -c";
4316 } elsif ($f eq "wget") {
4317 $src_switch = " -O $asl_ungz";
4319 } elsif ($f eq 'curl') {
4320 $src_switch = ' -L -f -s -S --netrc-optional';
4323 if ($f eq "ncftpget") {
4324 $chdir = "cd $aslocal_dir && ";
4327 $CPAN::Frontend->myprint(
4329 Trying with "$funkyftp$src_switch" to get
4333 "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
4334 $self->debug("system[$system]") if $CPAN::DEBUG;
4335 my($wstatus) = system($system);
4337 # lynx returns 0 when it fails somewhere
4339 my $content = do { local *FH;
4340 open FH, $asl_ungz or die;
4343 if ($content =~ /^<.*(<title>[45]|Error [45])/si) {
4344 $CPAN::Frontend->mywarn(qq{
4345 No success, the file that lynx has downloaded looks like an error message:
4348 $CPAN::Frontend->mysleep(1);
4352 $CPAN::Frontend->myprint(qq{
4353 No success, the file that lynx