1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $VERSION = eval $VERSION;
7 use CPAN::HandleConfig;
16 use ExtUtils::MakeMaker qw(prompt); # for some unknown reason,
17 # 5.005_04 does not work without
19 use File::Basename ();
26 use Sys::Hostname qw(hostname);
27 use Text::ParseWords ();
29 no lib "."; # we need to run chdir all over and we would get at wrong
32 require Mac::BuildTools if $^O eq 'MacOS';
34 END { $CPAN::End++; &cleanup; }
37 $CPAN::Frontend ||= "CPAN::Shell";
38 @CPAN::Defaultsites = ("http://www.perl.org/CPAN/","ftp://ftp.perl.org/pub/CPAN/")
39 unless @CPAN::Defaultsites;
40 # $CPAN::iCwd (i for initial) is going to be initialized during find_perl
41 $CPAN::Perl ||= CPAN::find_perl();
42 $CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
43 $CPAN::Defaultrecent ||= "http://search.cpan.org/recent";
49 use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $HAS_USABLE $term
50 $Signal $Suppress_readline $Frontend
51 @Defaultsites $Have_warned $Defaultdocs $Defaultrecent
54 @CPAN::ISA = qw(CPAN::Debug Exporter);
56 # note that these functions live in CPAN::Shell and get executed via
57 # AUTOLOAD when called directly
78 sub soft_chdir_with_alternatives ($);
80 #-> sub CPAN::AUTOLOAD ;
85 @EXPORT{@EXPORT} = '';
86 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
87 if (exists $EXPORT{$l}){
90 die(qq{Unknown CPAN command "$AUTOLOAD". }.
91 qq{Type ? for help.\n});
98 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
99 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
101 my $oprompt = shift || CPAN::Prompt->new;
102 my $prompt = $oprompt;
103 my $commandline = shift || "";
104 $CPAN::CurrentCommandId ||= 1;
107 unless ($Suppress_readline) {
108 require Term::ReadLine;
111 $term->ReadLine eq "Term::ReadLine::Stub"
113 $term = Term::ReadLine->new('CPAN Monitor');
115 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
116 my $attribs = $term->Attribs;
117 $attribs->{attempted_completion_function} = sub {
118 &CPAN::Complete::gnu_cpl;
121 $readline::rl_completion_function =
122 $readline::rl_completion_function = 'CPAN::Complete::cpl';
124 if (my $histfile = $CPAN::Config->{'histfile'}) {{
125 unless ($term->can("AddHistory")) {
126 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
129 my($fh) = FileHandle->new;
130 open $fh, "<$histfile" or last;
134 $term->AddHistory($_);
138 # $term->OUT is autoflushed anyway
139 my $odef = select STDERR;
146 # no strict; # I do not recall why no strict was here (2000-09-03)
150 File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
151 File::Spec->rootdir(),
153 my $try_detect_readline;
154 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
155 my $rl_avail = $Suppress_readline ? "suppressed" :
156 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
157 "available (try 'install Bundle::CPAN')";
159 $CPAN::Frontend->myprint(
161 cpan shell -- CPAN exploration and modules installation (v%s)
168 unless $CPAN::Config->{'inhibit_startup_message'} ;
169 my($continuation) = "";
170 SHELLCOMMAND: while () {
171 if ($Suppress_readline) {
173 last SHELLCOMMAND unless defined ($_ = <> );
176 last SHELLCOMMAND unless
177 defined ($_ = $term->readline($prompt, $commandline));
179 $_ = "$continuation$_" if $continuation;
181 next SHELLCOMMAND if /^$/;
182 $_ = 'h' if /^\s*\?/;
183 if (/^(?:q(?:uit)?|bye|exit)$/i) {
194 use vars qw($import_done);
195 CPAN->import(':DEFAULT') unless $import_done++;
196 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
203 if ($] < 5.00322) { # parsewords had a bug until recently
206 eval { @line = Text::ParseWords::shellwords($_) };
207 warn($@), next SHELLCOMMAND if $@;
208 warn("Text::Parsewords could not parse the line [$_]"),
209 next SHELLCOMMAND unless @line;
211 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
212 my $command = shift @line;
213 eval { CPAN::Shell->$command(@line) };
215 if ($command =~ /^(make|test|install|force|notest)$/) {
216 CPAN::Shell->failed($CPAN::CurrentCommandId,1);
218 soft_chdir_with_alternatives(\@cwd);
219 $CPAN::Frontend->myprint("\n");
221 $CPAN::CurrentCommandId++;
225 $commandline = ""; # I do want to be able to pass a default to
226 # shell, but on the second command I see no
229 CPAN::Queue->nullify_queue;
230 if ($try_detect_readline) {
231 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
233 $CPAN::META->has_inst("Term::ReadLine::Perl")
235 delete $INC{"Term/ReadLine.pm"};
237 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
238 require Term::ReadLine;
239 $CPAN::Frontend->myprint("\n$redef subroutines in ".
240 "Term::ReadLine redefined\n");
246 soft_chdir_with_alternatives(\@cwd);
249 sub soft_chdir_with_alternatives ($) {
251 while (not chdir $cwd->[0]) {
253 $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
254 Trying to chdir to "$cwd->[1]" instead.
258 $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
263 package CPAN::CacheMgr;
265 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
270 use vars qw($Ua $Thesite $ThesiteURL $Themethod);
271 @CPAN::FTP::ISA = qw(CPAN::Debug);
273 package CPAN::LWP::UserAgent;
275 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
276 # we delay requiring LWP::UserAgent and setting up inheritance until we need it
278 package CPAN::Complete;
280 @CPAN::Complete::ISA = qw(CPAN::Debug);
281 @CPAN::Complete::COMMANDS = sort qw(
282 ! a b d h i m o q r u
304 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
305 @CPAN::Index::ISA = qw(CPAN::Debug);
308 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
311 package CPAN::InfoObj;
313 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
315 package CPAN::Author;
317 @CPAN::Author::ISA = qw(CPAN::InfoObj);
319 package CPAN::Distribution;
321 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
323 package CPAN::Bundle;
325 @CPAN::Bundle::ISA = qw(CPAN::Module);
327 package CPAN::Module;
329 @CPAN::Module::ISA = qw(CPAN::InfoObj);
331 package CPAN::Exception::RecursiveDependency;
333 use overload '""' => "as_string";
340 for my $dep (@$deps) {
342 last if $seen{$dep}++;
344 bless { deps => \@deps }, $class;
349 "\nRecursive dependency detected:\n " .
350 join("\n => ", @{$self->{deps}}) .
351 ".\nCannot continue.\n";
354 package CPAN::Prompt; use overload '""' => "as_string";
355 use vars qw($prompt);
357 $CPAN::CurrentCommandId ||= 0;
362 if ($CPAN::Config->{commandnumber_in_prompt}) {
363 sprintf "cpan[%d]> ", $CPAN::CurrentCommandId;
369 package CPAN::Distrostatus;
370 use overload '""' => "as_string",
373 my($class,$arg) = @_;
376 FAILED => substr($arg,0,2) eq "NO",
377 COMMANDID => $CPAN::CurrentCommandId,
380 sub commandid { shift->{COMMANDID} }
381 sub failed { shift->{FAILED} }
385 $self->{TEXT} = $set;
396 use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
397 @CPAN::Shell::ISA = qw(CPAN::Debug);
398 $COLOR_REGISTERED ||= 0;
399 $PRINT_ORNAMENTING ||= 0;
401 #-> sub CPAN::Shell::AUTOLOAD ;
403 my($autoload) = $AUTOLOAD;
404 my $class = shift(@_);
405 # warn "autoload[$autoload] class[$class]";
406 $autoload =~ s/.*:://;
407 if ($autoload =~ /^w/) {
408 if ($CPAN::META->has_inst('CPAN::WAIT')) {
409 CPAN::WAIT->$autoload(@_);
411 $CPAN::Frontend->mywarn(qq{
412 Commands starting with "w" require CPAN::WAIT to be installed.
413 Please consider installing CPAN::WAIT to use the fulltext index.
414 For this you just need to type
419 $CPAN::Frontend->mywarn(qq{Unknown shell command '$autoload'. }.
428 # One use of the queue is to determine if we should or shouldn't
429 # announce the availability of a new CPAN module
431 # Now we try to use it for dependency tracking. For that to happen
432 # we need to draw a dependency tree and do the leaves first. This can
433 # easily be reached by running CPAN.pm recursively, but we don't want
434 # to waste memory and run into deep recursion. So what we can do is
437 # CPAN::Queue is the package where the queue is maintained. Dependencies
438 # often have high priority and must be brought to the head of the queue,
439 # possibly by jumping the queue if they are already there. My first code
440 # attempt tried to be extremely correct. Whenever a module needed
441 # immediate treatment, I either unshifted it to the front of the queue,
442 # or, if it was already in the queue, I spliced and let it bypass the
443 # others. This became a too correct model that made it impossible to put
444 # an item more than once into the queue. Why would you need that? Well,
445 # you need temporary duplicates as the manager of the queue is a loop
448 # (1) looks at the first item in the queue without shifting it off
450 # (2) cares for the item
452 # (3) removes the item from the queue, *even if its agenda failed and
453 # even if the item isn't the first in the queue anymore* (that way
454 # protecting against never ending queues)
456 # So if an item has prerequisites, the installation fails now, but we
457 # want to retry later. That's easy if we have it twice in the queue.
459 # I also expect insane dependency situations where an item gets more
460 # than two lives in the queue. Simplest example is triggered by 'install
461 # Foo Foo Foo'. People make this kind of mistakes and I don't want to
462 # get in the way. I wanted the queue manager to be a dumb servant, not
463 # one that knows everything.
465 # Who would I tell in this model that the user wants to be asked before
466 # processing? I can't attach that information to the module object,
467 # because not modules are installed but distributions. So I'd have to
468 # tell the distribution object that it should ask the user before
469 # processing. Where would the question be triggered then? Most probably
470 # in CPAN::Distribution::rematein.
471 # Hope that makes sense, my head is a bit off:-) -- AK
478 my $self = bless { qmod => $s }, $class;
483 # CPAN::Queue::first ;
489 # CPAN::Queue::delete_first ;
491 my($class,$what) = @_;
493 for my $i (0..$#All) {
494 if ( $All[$i]->{qmod} eq $what ) {
501 # CPAN::Queue::jumpqueue ;
505 CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
506 join(",",map {$_->{qmod}} @All),
509 WHAT: for my $what (reverse @what) {
511 for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
512 CPAN->debug("i[$All[$i]]what[$what]") if $CPAN::DEBUG;
513 if ($All[$i]->{qmod} eq $what){
515 if ($jumped > 100) { # one's OK if e.g. just
516 # processing now; more are OK if
517 # user typed it several times
518 $CPAN::Frontend->mywarn(
519 qq{Object [$what] queued more than 100 times, ignoring}
525 my $obj = bless { qmod => $what }, $class;
528 CPAN->debug(sprintf("after jumpqueue All[%s] what[%s]",
529 join(",",map {$_->{qmod}} @All),
534 # CPAN::Queue::exists ;
536 my($self,$what) = @_;
537 my @all = map { $_->{qmod} } @All;
538 my $exists = grep { $_->{qmod} eq $what } @All;
539 # warn "in exists what[$what] all[@all] exists[$exists]";
543 # CPAN::Queue::delete ;
546 @All = grep { $_->{qmod} ne $mod } @All;
549 # CPAN::Queue::nullify_queue ;
559 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
561 # from here on only subs.
562 ################################################################################
564 #-> sub CPAN::all_objects ;
566 my($mgr,$class) = @_;
567 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
568 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
570 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
572 *all = \&all_objects;
574 # Called by shell, not in batch mode. In batch mode I see no risk in
575 # having many processes updating something as installations are
576 # continually checked at runtime. In shell mode I suspect it is
577 # unintentional to open more than one shell at a time
579 #-> sub CPAN::checklock ;
582 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
583 if (-f $lockfile && -M _ > 0) {
584 my $fh = FileHandle->new($lockfile) or
585 $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
586 my $otherpid = <$fh>;
587 my $otherhost = <$fh>;
589 if (defined $otherpid && $otherpid) {
592 if (defined $otherhost && $otherhost) {
595 my $thishost = hostname();
596 if (defined $otherhost && defined $thishost &&
597 $otherhost ne '' && $thishost ne '' &&
598 $otherhost ne $thishost) {
599 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
600 "reports other host $otherhost and other ".
601 "process $otherpid.\n".
602 "Cannot proceed.\n"));
604 elsif (defined $otherpid && $otherpid) {
605 return if $$ == $otherpid; # should never happen
606 $CPAN::Frontend->mywarn(
608 There seems to be running another CPAN process (pid $otherpid). Contacting...
610 if (kill 0, $otherpid) {
611 $CPAN::Frontend->mydie(qq{Other job is running.
612 You may want to kill it and delete the lockfile, maybe. On UNIX try:
616 } elsif (-w $lockfile) {
618 ExtUtils::MakeMaker::prompt
619 (qq{Other job not responding. Shall I overwrite }.
620 qq{the lockfile '$lockfile'? (Y/n)},"y");
621 $CPAN::Frontend->myexit("Ok, bye\n")
622 unless $ans =~ /^y/i;
625 qq{Lockfile '$lockfile' not writeable by you. }.
626 qq{Cannot proceed.\n}.
628 qq{ rm '$lockfile'\n}.
629 qq{ and then rerun us.\n}
633 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
634 "reports other process with ID ".
635 "$otherpid. Cannot proceed.\n"));
638 my $dotcpan = $CPAN::Config->{cpan_home};
639 eval { File::Path::mkpath($dotcpan);};
641 # A special case at least for Jarkko.
646 $symlinkcpan = readlink $dotcpan;
647 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
648 eval { File::Path::mkpath($symlinkcpan); };
652 $CPAN::Frontend->mywarn(qq{
653 Working directory $symlinkcpan created.
657 unless (-d $dotcpan) {
659 Your configuration suggests "$dotcpan" as your
660 CPAN.pm working directory. I could not create this directory due
661 to this error: $firsterror\n};
663 As "$dotcpan" is a symlink to "$symlinkcpan",
664 I tried to create that, but I failed with this error: $seconderror
667 Please make sure the directory exists and is writable.
669 $CPAN::Frontend->mydie($diemess);
671 } # $@ after eval mkpath $dotcpan
673 unless ($fh = FileHandle->new(">$lockfile")) {
674 if ($! =~ /Permission/) {
675 my $incc = $INC{'CPAN/Config.pm'};
676 my $myincc = File::Spec->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
677 $CPAN::Frontend->myprint(qq{
679 Your configuration suggests that CPAN.pm should use a working
681 $CPAN::Config->{cpan_home}
682 Unfortunately we could not create the lock file
684 due to permission problems.
686 Please make sure that the configuration variable
687 \$CPAN::Config->{cpan_home}
688 points to a directory where you can write a .lock file. You can set
689 this variable in either
694 if(!$INC{'CPAN/MyConfig.pm'}) {
695 $CPAN::Frontend->myprint("You don't seem to have a user ".
696 "configuration (MyConfig.pm) yet.\n");
697 my $new = ExtUtils::MakeMaker::prompt("Do you want to create a ".
698 "user configuration now? (Y/n)",
701 CPAN::Shell->mkmyconfig();
706 $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
708 $fh->print($$, "\n");
709 $fh->print(hostname(), "\n");
710 $self->{LOCK} = $lockfile;
714 $CPAN::Frontend->mydie("Got SIGTERM, leaving");
719 $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
720 print "Caught SIGINT\n";
724 # From: Larry Wall <larry@wall.org>
725 # Subject: Re: deprecating SIGDIE
726 # To: perl5-porters@perl.org
727 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
729 # The original intent of __DIE__ was only to allow you to substitute one
730 # kind of death for another on an application-wide basis without respect
731 # to whether you were in an eval or not. As a global backstop, it should
732 # not be used any more lightly (or any more heavily :-) than class
733 # UNIVERSAL. Any attempt to build a general exception model on it should
734 # be politely squashed. Any bug that causes every eval {} to have to be
735 # modified should be not so politely squashed.
737 # Those are my current opinions. It is also my optinion that polite
738 # arguments degenerate to personal arguments far too frequently, and that
739 # when they do, it's because both people wanted it to, or at least didn't
740 # sufficiently want it not to.
744 # global backstop to cleanup if we should really die
745 $SIG{__DIE__} = \&cleanup;
746 $self->debug("Signal handler set.") if $CPAN::DEBUG;
749 #-> sub CPAN::DESTROY ;
751 &cleanup; # need an eval?
754 #-> sub CPAN::anycwd ;
757 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
762 sub cwd {Cwd::cwd();}
764 #-> sub CPAN::getcwd ;
765 sub getcwd {Cwd::getcwd();}
767 #-> sub CPAN::fastcwd ;
768 sub fastcwd {Cwd::fastcwd();}
770 #-> sub CPAN::backtickcwd ;
771 sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
773 #-> sub CPAN::find_perl ;
775 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
776 my $pwd = $CPAN::iCwd = CPAN::anycwd();
777 my $candidate = File::Spec->catfile($pwd,$^X);
778 $perl ||= $candidate if MM->maybe_command($candidate);
781 my ($component,$perl_name);
782 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
783 PATH_COMPONENT: foreach $component (File::Spec->path(),
784 $Config::Config{'binexp'}) {
785 next unless defined($component) && $component;
786 my($abs) = File::Spec->catfile($component,$perl_name);
787 if (MM->maybe_command($abs)) {
799 #-> sub CPAN::exists ;
801 my($mgr,$class,$id) = @_;
802 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
804 ### Carp::croak "exists called without class argument" unless $class;
806 $id =~ s/:+/::/g if $class eq "CPAN::Module";
807 exists $META->{readonly}{$class}{$id} or
808 exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
811 #-> sub CPAN::delete ;
813 my($mgr,$class,$id) = @_;
814 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
815 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
818 #-> sub CPAN::has_usable
819 # has_inst is sometimes too optimistic, we should replace it with this
820 # has_usable whenever a case is given
822 my($self,$mod,$message) = @_;
823 return 1 if $HAS_USABLE->{$mod};
824 my $has_inst = $self->has_inst($mod,$message);
825 return unless $has_inst;
828 LWP => [ # we frequently had "Can't locate object
829 # method "new" via package "LWP::UserAgent" at
830 # (eval 69) line 2006
832 sub {require LWP::UserAgent},
833 sub {require HTTP::Request},
834 sub {require URI::URL},
837 sub {require Net::FTP},
838 sub {require Net::Config},
841 if ($usable->{$mod}) {
842 for my $c (0..$#{$usable->{$mod}}) {
843 my $code = $usable->{$mod}[$c];
844 my $ret = eval { &$code() };
846 warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
851 return $HAS_USABLE->{$mod} = 1;
854 #-> sub CPAN::has_inst
856 my($self,$mod,$message) = @_;
857 Carp::croak("CPAN->has_inst() called without an argument")
859 my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
860 keys %{$CPAN::Config->{dontload_hash}||{}},
861 @{$CPAN::Config->{dontload_list}||[]};
862 if (defined $message && $message eq "no" # afair only used by Nox
866 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
874 # checking %INC is wrong, because $INC{LWP} may be true
875 # although $INC{"URI/URL.pm"} may have failed. But as
876 # I really want to say "bla loaded OK", I have to somehow
878 ### warn "$file in %INC"; #debug
880 } elsif (eval { require $file }) {
881 # eval is good: if we haven't yet read the database it's
882 # perfect and if we have installed the module in the meantime,
883 # it tries again. The second require is only a NOOP returning
884 # 1 if we had success, otherwise it's retrying
886 $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
887 if ($mod eq "CPAN::WAIT") {
888 push @CPAN::Shell::ISA, 'CPAN::WAIT';
891 } elsif ($mod eq "Net::FTP") {
892 $CPAN::Frontend->mywarn(qq{
893 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
895 install Bundle::libnet
897 }) unless $Have_warned->{"Net::FTP"}++;
899 } elsif ($mod eq "Digest::SHA"){
900 if ($Have_warned->{"Digest::SHA"}++) {
901 $CPAN::Frontend->myprint(qq{CPAN: checksum security checks disabled}.
902 qq{because Digest::SHA not installed.\n});
904 $CPAN::Frontend->myprint(qq{
905 CPAN: checksum security checks disabled because Digest::SHA not installed.
906 Please consider installing the Digest::SHA module.
911 } elsif ($mod eq "Module::Signature"){
912 unless ($Have_warned->{"Module::Signature"}++) {
913 # No point in complaining unless the user can
914 # reasonably install and use it.
915 if (eval { require Crypt::OpenPGP; 1 } ||
916 defined $CPAN::Config->{'gpg'}) {
917 $CPAN::Frontend->myprint(qq{
918 CPAN: Module::Signature security checks disabled because Module::Signature
919 not installed. Please consider installing the Module::Signature module.
920 You may also need to be able to connect over the Internet to the public
921 keyservers like pgp.mit.edu (port 11371).
928 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
933 #-> sub CPAN::instance ;
935 my($mgr,$class,$id) = @_;
938 # unsafe meta access, ok?
939 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
940 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
948 #-> sub CPAN::cleanup ;
950 # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
951 local $SIG{__DIE__} = '';
956 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
958 $subroutine eq '(eval)';
960 return if $ineval && !$CPAN::End;
961 return unless defined $META->{LOCK};
962 return unless -f $META->{LOCK};
964 unlink $META->{LOCK};
966 # Carp::cluck("DEBUGGING");
967 $CPAN::Frontend->mywarn("Lockfile removed.\n");
970 #-> sub CPAN::savehist
973 my($histfile,$histsize);
974 unless ($histfile = $CPAN::Config->{'histfile'}){
975 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
978 $histsize = $CPAN::Config->{'histsize'} || 100;
980 unless ($CPAN::term->can("GetHistory")) {
981 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
987 my @h = $CPAN::term->GetHistory;
988 splice @h, 0, @h-$histsize if @h>$histsize;
989 my($fh) = FileHandle->new;
990 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
991 local $\ = local $, = "\n";
997 my($self,$what) = @_;
998 $self->{is_tested}{$what} = 1;
1002 my($self,$what) = @_;
1003 delete $self->{is_tested}{$what};
1008 $self->{is_tested} ||= {};
1009 return unless %{$self->{is_tested}};
1010 my $env = $ENV{PERL5LIB};
1011 $env = $ENV{PERLLIB} unless defined $env;
1013 push @env, $env if defined $env and length $env;
1014 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
1015 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
1016 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
1019 package CPAN::CacheMgr;
1022 #-> sub CPAN::CacheMgr::as_string ;
1024 eval { require Data::Dumper };
1026 return shift->SUPER::as_string;
1028 return Data::Dumper::Dumper(shift);
1032 #-> sub CPAN::CacheMgr::cachesize ;
1037 #-> sub CPAN::CacheMgr::tidyup ;
1040 return unless -d $self->{ID};
1041 while ($self->{DU} > $self->{'MAX'} ) {
1042 my($toremove) = shift @{$self->{FIFO}};
1043 $CPAN::Frontend->myprint(sprintf(
1044 "Deleting from cache".
1045 ": $toremove (%.1f>%.1f MB)\n",
1046 $self->{DU}, $self->{'MAX'})
1048 return if $CPAN::Signal;
1049 $self->force_clean_cache($toremove);
1050 return if $CPAN::Signal;
1054 #-> sub CPAN::CacheMgr::dir ;
1059 #-> sub CPAN::CacheMgr::entries ;
1061 my($self,$dir) = @_;
1062 return unless defined $dir;
1063 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
1064 $dir ||= $self->{ID};
1065 my($cwd) = CPAN::anycwd();
1066 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
1067 my $dh = DirHandle->new(File::Spec->curdir)
1068 or Carp::croak("Couldn't opendir $dir: $!");
1071 next if $_ eq "." || $_ eq "..";
1073 push @entries, File::Spec->catfile($dir,$_);
1075 push @entries, File::Spec->catdir($dir,$_);
1077 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
1080 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
1081 sort { -M $b <=> -M $a} @entries;
1084 #-> sub CPAN::CacheMgr::disk_usage ;
1086 my($self,$dir) = @_;
1087 return if exists $self->{SIZE}{$dir};
1088 return if $CPAN::Signal;
1092 unless (chmod 0755, $dir) {
1093 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
1094 "permission to change the permission; cannot ".
1095 "estimate disk usage of '$dir'\n");
1096 $CPAN::Frontend->mysleep(5);
1101 $CPAN::Frontend->mywarn("Directory '$dir' has gone. Cannot continue.\n");
1102 $CPAN::Frontend->mysleep(2);
1107 $File::Find::prune++ if $CPAN::Signal;
1109 if ($^O eq 'MacOS') {
1111 my $cat = Mac::Files::FSpGetCatInfo($_);
1112 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
1116 unless (chmod 0755, $_) {
1117 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
1118 "the permission to change the permission; ".
1119 "can only partially estimate disk usage ".
1132 return if $CPAN::Signal;
1133 $self->{SIZE}{$dir} = $Du/1024/1024;
1134 push @{$self->{FIFO}}, $dir;
1135 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
1136 $self->{DU} += $Du/1024/1024;
1140 #-> sub CPAN::CacheMgr::force_clean_cache ;
1141 sub force_clean_cache {
1142 my($self,$dir) = @_;
1143 return unless -e $dir;
1144 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
1146 File::Path::rmtree($dir);
1147 $self->{DU} -= $self->{SIZE}{$dir};
1148 delete $self->{SIZE}{$dir};
1151 #-> sub CPAN::CacheMgr::new ;
1158 ID => $CPAN::Config->{'build_dir'},
1159 MAX => $CPAN::Config->{'build_cache'},
1160 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
1163 File::Path::mkpath($self->{ID});
1164 my $dh = DirHandle->new($self->{ID});
1165 bless $self, $class;
1168 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
1170 CPAN->debug($debug) if $CPAN::DEBUG;
1174 #-> sub CPAN::CacheMgr::scan_cache ;
1177 return if $self->{SCAN} eq 'never';
1178 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1179 unless $self->{SCAN} eq 'atstart';
1180 $CPAN::Frontend->myprint(
1181 sprintf("Scanning cache %s for sizes\n",
1184 for $e ($self->entries($self->{ID})) {
1185 next if $e eq ".." || $e eq ".";
1186 $self->disk_usage($e);
1187 return if $CPAN::Signal;
1192 package CPAN::Shell;
1195 #-> sub CPAN::Shell::h ;
1197 my($class,$about) = @_;
1198 if (defined $about) {
1199 $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
1201 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
1202 $CPAN::Frontend->myprint(qq{
1203 Display Information $filler (ver $CPAN::VERSION)
1204 command argument description
1205 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1206 i WORD or /REGEXP/ about any of the above
1207 r NONE report updatable modules
1208 ls AUTHOR or GLOB about files in the author's directory
1209 (with WORD being a module, bundle or author name or a distribution
1210 name of the form AUTHOR/DISTRIBUTION)
1212 Download, Test, Make, Install...
1213 get download clean make clean
1214 make make (implies get) look open subshell in dist directory
1215 test make test (implies make) readme display these README files
1216 install make install (implies test) perldoc display POD documentation
1219 force COMMAND unconditionally do command
1220 notest COMMAND skip testing
1223 h,? display this menu ! perl-code eval a perl command
1224 o conf [opt] set and query options q quit the cpan shell
1225 reload cpan load CPAN.pm again reload index load newer indices
1226 autobundle Snapshot recent latest CPAN uploads});
1232 #-> sub CPAN::Shell::a ;
1234 my($self,@arg) = @_;
1235 # authors are always UPPERCASE
1237 $_ = uc $_ unless /=/;
1239 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1242 #-> sub CPAN::Shell::globls ;
1244 my($self,$s,$pragmas) = @_;
1245 # ls is really very different, but we had it once as an ordinary
1246 # command in the Shell (upto rev. 321) and we could not handle
1248 my(@accept,@preexpand);
1249 if ($s =~ /[\*\?\/]/) {
1250 if ($CPAN::META->has_inst("Text::Glob")) {
1251 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
1252 my $rau = Text::Glob::glob_to_regex(uc $au);
1253 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
1255 push @preexpand, map { $_->id . "/" . $pathglob }
1256 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
1258 my $rau = Text::Glob::glob_to_regex(uc $s);
1259 push @preexpand, map { $_->id }
1260 CPAN::Shell->expand_by_method('CPAN::Author',
1265 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
1268 push @preexpand, uc $s;
1271 unless (/^[A-Z0-9\-]+(\/|$)/i) {
1272 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1277 my $silent = @accept>1;
1278 my $last_alpha = "";
1280 for my $a (@accept){
1281 my($author,$pathglob);
1282 if ($a =~ m|(.*?)/(.*)|) {
1285 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1287 $a2) or die "No author found for $a2";
1289 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1291 $a) or die "No author found for $a";
1294 my $alpha = substr $author->id, 0, 1;
1296 if ($alpha eq $last_alpha) {
1300 $last_alpha = $alpha;
1302 $CPAN::Frontend->myprint($ad);
1304 for my $pragma (@$pragmas) {
1305 if ($author->can($pragma)) {
1309 push @results, $author->ls($pathglob,$silent); # silent if
1312 for my $pragma (@$pragmas) {
1313 my $meth = "un$pragma";
1314 if ($author->can($meth)) {
1322 #-> sub CPAN::Shell::local_bundles ;
1324 my($self,@which) = @_;
1325 my($incdir,$bdir,$dh);
1326 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1327 my @bbase = "Bundle";
1328 while (my $bbase = shift @bbase) {
1329 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1330 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1331 if ($dh = DirHandle->new($bdir)) { # may fail
1333 for $entry ($dh->read) {
1334 next if $entry =~ /^\./;
1335 next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
1336 if (-d File::Spec->catdir($bdir,$entry)){
1337 push @bbase, "$bbase\::$entry";
1339 next unless $entry =~ s/\.pm(?!\n)\Z//;
1340 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1348 #-> sub CPAN::Shell::b ;
1350 my($self,@which) = @_;
1351 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1352 $self->local_bundles;
1353 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1356 #-> sub CPAN::Shell::d ;
1357 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1359 #-> sub CPAN::Shell::m ;
1360 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1362 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1365 #-> sub CPAN::Shell::i ;
1369 @args = '/./' unless @args;
1371 for my $type (qw/Bundle Distribution Module/) {
1372 push @result, $self->expand($type,@args);
1374 # Authors are always uppercase.
1375 push @result, $self->expand("Author", map { uc $_ } @args);
1377 my $result = @result == 1 ?
1378 $result[0]->as_string :
1380 "No objects found of any type for argument @args\n" :
1382 (map {$_->as_glimpse} @result),
1383 scalar @result, " items found\n",
1385 $CPAN::Frontend->myprint($result);
1388 #-> sub CPAN::Shell::o ;
1390 # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf'
1391 # should have been called set and 'o debug' maybe 'set debug'
1393 my($self,$o_type,@o_what) = @_;
1396 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1397 if ($o_type eq 'conf') {
1398 if (!@o_what) { # print all things, "o conf"
1400 $CPAN::Frontend->myprint("CPAN::Config options");
1401 if (exists $INC{'CPAN/Config.pm'}) {
1402 $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1404 if (exists $INC{'CPAN/MyConfig.pm'}) {
1405 $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1407 $CPAN::Frontend->myprint(":\n");
1408 for $k (sort keys %CPAN::HandleConfig::can) {
1409 $v = $CPAN::HandleConfig::can{$k};
1410 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
1412 $CPAN::Frontend->myprint("\n");
1413 for $k (sort keys %$CPAN::Config) {
1414 CPAN::HandleConfig->prettyprint($k);
1416 $CPAN::Frontend->myprint("\n");
1417 } elsif (!CPAN::HandleConfig->edit(@o_what)) {
1418 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
1421 } elsif ($o_type eq 'debug') {
1423 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1426 my($what) = shift @o_what;
1427 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
1428 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
1431 if ( exists $CPAN::DEBUG{$what} ) {
1432 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1433 } elsif ($what =~ /^\d/) {
1434 $CPAN::DEBUG = $what;
1435 } elsif (lc $what eq 'all') {
1437 for (values %CPAN::DEBUG) {
1440 $CPAN::DEBUG = $max;
1443 for (keys %CPAN::DEBUG) {
1444 next unless lc($_) eq lc($what);
1445 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
1448 $CPAN::Frontend->myprint("unknown argument [$what]\n")
1453 my $raw = "Valid options for debug are ".
1454 join(", ",sort(keys %CPAN::DEBUG), 'all').
1455 qq{ or a number. Completion works on the options. }.
1456 qq{Case is ignored.};
1458 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
1459 $CPAN::Frontend->myprint("\n\n");
1462 $CPAN::Frontend->myprint("Options set for debugging:\n");
1464 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1465 $v = $CPAN::DEBUG{$k};
1466 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
1467 if $v & $CPAN::DEBUG;
1470 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
1473 $CPAN::Frontend->myprint(qq{
1475 conf set or get configuration variables
1476 debug set or get debugging options
1481 sub paintdots_onreload {
1484 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
1488 # $CPAN::Frontend->myprint(".($subr)");
1489 $CPAN::Frontend->myprint(".");
1496 #-> sub CPAN::Shell::reload ;
1498 my($self,$command,@arg) = @_;
1500 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1501 if ($command =~ /cpan/i) {
1503 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
1505 MFILE: for my $f (qw(CPAN.pm CPAN/HandleConfig.pm CPAN/FirstTime.pm CPAN/Tarzip.pm
1506 CPAN/Debug.pm CPAN/Version.pm)) {
1507 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
1508 $self->reload_this($f) or $failed++;
1510 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
1511 $failed++ unless $redef;
1513 $CPAN::Frontend->mywarn("\n$failed errors during reload. You better quit ".
1516 } elsif ($command =~ /index/) {
1517 CPAN::Index->force_reload;
1519 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
1520 index re-reads the index files\n});
1526 return 1 unless $INC{$f};
1527 my $pwd = CPAN::anycwd();
1528 CPAN->debug("reloading the whole '$f' from '$INC{$f}' while pwd='$pwd'")
1531 for my $inc (@INC) {
1532 $read = File::Spec->catfile($inc,split /\//, $f);
1539 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
1542 my $fh = FileHandle->new($read) or
1543 $CPAN::Frontend->mydie("Could not open $read: $!");
1547 CPAN->debug(sprintf("evaling [%s...]\n",substr($eval,0,64)))
1557 #-> sub CPAN::Shell::mkmyconfig ;
1559 my($self, $cpanpm, %args) = @_;
1560 require CPAN::FirstTime;
1561 $cpanpm = $INC{'CPAN/MyConfig.pm'} || "$ENV{HOME}/.cpan/CPAN/MyConfig.pm";
1562 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
1563 if(!$INC{'CPAN/Config.pm'}) {
1564 eval { require CPAN::Config; };
1566 $CPAN::Config ||= {};
1571 keep_source_where => undef,
1574 CPAN::FirstTime::init($cpanpm, %args);
1577 #-> sub CPAN::Shell::_binary_extensions ;
1578 sub _binary_extensions {
1579 my($self) = shift @_;
1580 my(@result,$module,%seen,%need,$headerdone);
1581 for $module ($self->expand('Module','/./')) {
1582 my $file = $module->cpan_file;
1583 next if $file eq "N/A";
1584 next if $file =~ /^Contact Author/;
1585 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
1586 next if $dist->isa_perl;
1587 next unless $module->xs_file;
1589 $CPAN::Frontend->myprint(".");
1590 push @result, $module;
1592 # print join " | ", @result;
1593 $CPAN::Frontend->myprint("\n");
1597 #-> sub CPAN::Shell::recompile ;
1599 my($self) = shift @_;
1600 my($module,@module,$cpan_file,%dist);
1601 @module = $self->_binary_extensions();
1602 for $module (@module){ # we force now and compile later, so we
1604 $cpan_file = $module->cpan_file;
1605 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1607 $dist{$cpan_file}++;
1609 for $cpan_file (sort keys %dist) {
1610 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
1611 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1613 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1614 # stop a package from recompiling,
1615 # e.g. IO-1.12 when we have perl5.003_10
1619 #-> sub CPAN::Shell::_u_r_common ;
1621 my($self) = shift @_;
1622 my($what) = shift @_;
1623 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1624 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
1625 $what && $what =~ /^[aru]$/;
1627 @args = '/./' unless @args;
1628 my(@result,$module,%seen,%need,$headerdone,
1629 $version_undefs,$version_zeroes);
1630 $version_undefs = $version_zeroes = 0;
1631 my $sprintf = "%s%-25s%s %9s %9s %s\n";
1632 my @expand = $self->expand('Module',@args);
1633 my $expand = scalar @expand;
1634 if (0) { # Looks like noise to me, was very useful for debugging
1635 # for metadata cache
1636 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
1638 MODULE: for $module (@expand) {
1639 my $file = $module->cpan_file;
1640 next MODULE unless defined $file; # ??
1641 $file =~ s|^./../||;
1642 my($latest) = $module->cpan_version;
1643 my($inst_file) = $module->inst_file;
1645 return if $CPAN::Signal;
1648 $have = $module->inst_version;
1649 } elsif ($what eq "r") {
1650 $have = $module->inst_version;
1652 if ($have eq "undef"){
1654 } elsif ($have == 0){
1657 next MODULE unless CPAN::Version->vgt($latest, $have);
1658 # to be pedantic we should probably say:
1659 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1660 # to catch the case where CPAN has a version 0 and we have a version undef
1661 } elsif ($what eq "u") {
1667 } elsif ($what eq "r") {
1669 } elsif ($what eq "u") {
1673 return if $CPAN::Signal; # this is sometimes lengthy
1676 push @result, sprintf "%s %s\n", $module->id, $have;
1677 } elsif ($what eq "r") {
1678 push @result, $module->id;
1679 next MODULE if $seen{$file}++;
1680 } elsif ($what eq "u") {
1681 push @result, $module->id;
1682 next MODULE if $seen{$file}++;
1683 next MODULE if $file =~ /^Contact/;
1685 unless ($headerdone++){
1686 $CPAN::Frontend->myprint("\n");
1687 $CPAN::Frontend->myprint(sprintf(
1690 "Package namespace",
1702 $CPAN::META->has_inst("Term::ANSIColor")
1704 $module->description
1706 $color_on = Term::ANSIColor::color("green");
1707 $color_off = Term::ANSIColor::color("reset");
1709 $CPAN::Frontend->myprint(sprintf $sprintf,
1716 $need{$module->id}++;
1720 $CPAN::Frontend->myprint("No modules found for @args\n");
1721 } elsif ($what eq "r") {
1722 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
1726 if ($version_zeroes) {
1727 my $s_has = $version_zeroes > 1 ? "s have" : " has";
1728 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1729 qq{a version number of 0\n});
1731 if ($version_undefs) {
1732 my $s_has = $version_undefs > 1 ? "s have" : " has";
1733 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1734 qq{parseable version number\n});
1740 #-> sub CPAN::Shell::r ;
1742 shift->_u_r_common("r",@_);
1745 #-> sub CPAN::Shell::u ;
1747 shift->_u_r_common("u",@_);
1750 #-> sub CPAN::Shell::failed ;
1752 my($self,$only_id,$silent) = @_;
1754 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
1763 next unless exists $d->{$nosayer};
1765 $d->{$nosayer}->can("failed") ?
1766 $d->{$nosayer}->failed :
1767 $d->{$nosayer} =~ /^NO/
1772 next DIST unless $failed;
1773 next DIST if $only_id && $only_id != (
1774 $d->{$failed}->can("commandid")
1776 $d->{$failed}->commandid
1778 $CPAN::CurrentCommandId
1783 # " %-45s: %s %s\n",
1786 $d->{$failed}->can("failed") ?
1788 $d->{$failed}->commandid,
1791 $d->{$failed}->text,
1801 my $scope = $only_id ? "command" : "session";
1803 my $print = join "",
1804 map { sprintf " %-45s: %s %s\n", @$_[1,2,3] }
1805 sort { $a->[0] <=> $b->[0] } @failed;
1806 $CPAN::Frontend->myprint("Failed during this $scope:\n$print");
1807 } elsif (!$only_id || !$silent) {
1808 $CPAN::Frontend->myprint("Nothing failed in this $scope\n");
1812 # XXX intentionally undocumented because completely bogus, unportable,
1815 #-> sub CPAN::Shell::status ;
1818 require Devel::Size;
1819 my $ps = FileHandle->new;
1820 open $ps, "/proc/$$/status";
1823 next unless /VmSize:\s+(\d+)/;
1827 $CPAN::Frontend->mywarn(sprintf(
1828 "%-27s %6d\n%-27s %6d\n",
1832 Devel::Size::total_size($CPAN::META)/1024,
1834 for my $k (sort keys %$CPAN::META) {
1835 next unless substr($k,0,4) eq "read";
1836 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
1837 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
1838 warn sprintf " %-25s %6d %6d\n",
1840 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
1841 scalar keys %{$CPAN::META->{$k}{$k2}};
1846 #-> sub CPAN::Shell::autobundle ;
1849 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1850 my(@bundle) = $self->_u_r_common("a",@_);
1851 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1852 File::Path::mkpath($todir);
1853 unless (-d $todir) {
1854 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1857 my($y,$m,$d) = (localtime)[5,4,3];
1861 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1862 my($to) = File::Spec->catfile($todir,"$me.pm");
1864 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1865 $to = File::Spec->catfile($todir,"$me.pm");
1867 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1869 "package Bundle::$me;\n\n",
1870 "\$VERSION = '0.01';\n\n",
1874 "Bundle::$me - Snapshot of installation on ",
1875 $Config::Config{'myhostname'},
1878 "\n\n=head1 SYNOPSIS\n\n",
1879 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1880 "=head1 CONTENTS\n\n",
1881 join("\n", @bundle),
1882 "\n\n=head1 CONFIGURATION\n\n",
1884 "\n\n=head1 AUTHOR\n\n",
1885 "This Bundle has been generated automatically ",
1886 "by the autobundle routine in CPAN.pm.\n",
1889 $CPAN::Frontend->myprint("\nWrote bundle file
1893 #-> sub CPAN::Shell::expandany ;
1896 CPAN->debug("s[$s]") if $CPAN::DEBUG;
1897 if ($s =~ m|/|) { # looks like a file
1898 $s = CPAN::Distribution->normalize($s);
1899 return $CPAN::META->instance('CPAN::Distribution',$s);
1900 # Distributions spring into existence, not expand
1901 } elsif ($s =~ m|^Bundle::|) {
1902 $self->local_bundles; # scanning so late for bundles seems
1903 # both attractive and crumpy: always
1904 # current state but easy to forget
1906 return $self->expand('Bundle',$s);
1908 return $self->expand('Module',$s)
1909 if $CPAN::META->exists('CPAN::Module',$s);
1914 #-> sub CPAN::Shell::expand ;
1917 my($type,@args) = @_;
1918 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1919 my $class = "CPAN::$type";
1920 my $methods = ['id'];
1921 for my $meth (qw(name)) {
1922 next if $] < 5.00303; # no "can"
1923 next unless $class->can($meth);
1924 push @$methods, $meth;
1926 $self->expand_by_method($class,$methods,@args);
1929 sub expand_by_method {
1931 my($class,$methods,@args) = @_;
1934 my($regex,$command);
1935 if ($arg =~ m|^/(.*)/$|) {
1937 } elsif ($arg =~ m/=/) {
1941 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1943 defined $regex ? $regex : "UNDEFINED",
1944 defined $command ? $command : "UNDEFINED",
1946 if (defined $regex) {
1948 $CPAN::META->all_objects($class)
1951 # BUG, we got an empty object somewhere
1952 require Data::Dumper;
1953 CPAN->debug(sprintf(
1954 "Bug in CPAN: Empty id on obj[%s][%s]",
1956 Data::Dumper::Dumper($obj)
1960 for my $method (@$methods) {
1961 if ($obj->$method() =~ /$regex/i) {
1967 } elsif ($command) {
1968 die "equal sign in command disabled (immature interface), ".
1970 ! \$CPAN::Shell::ADVANCED_QUERY=1
1971 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1972 that may go away anytime.\n"
1973 unless $ADVANCED_QUERY;
1974 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1975 my($matchcrit) = $criterion =~ m/^~(.+)/;
1979 $CPAN::META->all_objects($class)
1981 my $lhs = $self->$method() or next; # () for 5.00503
1983 push @m, $self if $lhs =~ m/$matchcrit/;
1985 push @m, $self if $lhs eq $criterion;
1990 if ( $class eq 'CPAN::Bundle' ) {
1991 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1992 } elsif ($class eq "CPAN::Distribution") {
1993 $xarg = CPAN::Distribution->normalize($arg);
1997 if ($CPAN::META->exists($class,$xarg)) {
1998 $obj = $CPAN::META->instance($class,$xarg);
1999 } elsif ($CPAN::META->exists($class,$arg)) {
2000 $obj = $CPAN::META->instance($class,$arg);
2007 @m = sort {$a->id cmp $b->id} @m;
2008 if ( $CPAN::DEBUG ) {
2009 my $wantarray = wantarray;
2010 my $join_m = join ",", map {$_->id} @m;
2011 $self->debug("wantarray[$wantarray]join_m[$join_m]");
2013 return wantarray ? @m : $m[0];
2016 #-> sub CPAN::Shell::format_result ;
2019 my($type,@args) = @_;
2020 @args = '/./' unless @args;
2021 my(@result) = $self->expand($type,@args);
2022 my $result = @result == 1 ?
2023 $result[0]->as_string :
2025 "No objects of type $type found for argument @args\n" :
2027 (map {$_->as_glimpse} @result),
2028 scalar @result, " items found\n",
2033 #-> sub CPAN::Shell::report_fh ;
2035 my $installation_report_fh;
2036 my $previously_noticed = 0;
2039 return $installation_report_fh if $installation_report_fh;
2040 if ($CPAN::META->has_inst("File::Temp")) {
2041 $installation_report_fh
2043 template => 'cpan_install_XXXX',
2048 unless ( $installation_report_fh ) {
2049 warn("Couldn't open installation report file; " .
2050 "no report file will be generated."
2051 ) unless $previously_noticed++;
2057 # The only reason for this method is currently to have a reliable
2058 # debugging utility that reveals which output is going through which
2059 # channel. No, I don't like the colors ;-)
2061 #-> sub CPAN::Shell::print_ornameted ;
2062 sub print_ornamented {
2063 my($self,$what,$ornament) = @_;
2065 return unless defined $what;
2067 local $| = 1; # Flush immediately
2068 if ( $CPAN::Be_Silent ) {
2069 print {report_fh()} $what;
2073 if ($CPAN::Config->{term_is_latin}){
2076 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
2078 if ($PRINT_ORNAMENTING) {
2079 unless (defined &color) {
2080 if ($CPAN::META->has_inst("Term::ANSIColor")) {
2081 import Term::ANSIColor "color";
2083 *color = sub { return "" };
2087 for $line (split /\n/, $what) {
2088 $longest = length($line) if length($line) > $longest;
2090 my $sprintf = "%-" . $longest . "s";
2092 $what =~ s/(.*\n?)//m;
2095 my($nl) = chomp $line ? "\n" : "";
2096 # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
2097 print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
2101 # $what .= "\n"; # newlines unless $PRINT_ORNAMENTING
2107 my($self,$what) = @_;
2109 $self->print_ornamented($what, 'bold blue on_yellow');
2113 my($self,$what) = @_;
2114 $self->myprint($what);
2119 my($self,$what) = @_;
2120 $self->print_ornamented($what, 'bold red on_yellow');
2124 # my($self,$what) = @_;
2125 # $self->print_ornamented($what, 'bold red on_white');
2126 # Carp::confess "died";
2129 # only to be used for shell commands
2131 my($self,$what) = @_;
2132 $self->print_ornamented($what, 'bold red on_white');
2134 # If it is the shell, we want that the following die to be silent,
2135 # but if it is not the shell, we would need a 'die $what'. We need
2136 # to take care that only shell commands use mydie. Is this
2142 # use this only for unrecoverable errors!
2143 sub unrecoverable_error {
2144 my($self,$what) = @_;
2145 my @lines = split /\n/, $what;
2147 for my $l (@lines) {
2148 $longest = length $l if length $l > $longest;
2150 $longest = 62 if $longest > 62;
2151 for my $l (@lines) {
2157 if (length $l < 66) {
2158 $l = pack "A66 A*", $l, "<==";
2162 unshift @lines, "\n";
2163 $self->mydie(join "", @lines);
2167 my($self, $sleep) = @_;
2172 return if -t STDOUT;
2173 my $odef = select STDERR;
2180 #-> sub CPAN::Shell::rematein ;
2181 # RE-adme||MA-ke||TE-st||IN-stall
2184 my($meth,@some) = @_;
2186 while($meth =~ /^(force|notest)$/) {
2187 push @pragma, $meth;
2188 $meth = shift @some or
2189 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
2193 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
2195 # Here is the place to set "test_count" on all involved parties to
2196 # 0. We then can pass this counter on to the involved
2197 # distributions and those can refuse to test if test_count > X. In
2198 # the first stab at it we could use a 1 for "X".
2200 # But when do I reset the distributions to start with 0 again?
2201 # Jost suggested to have a random or cycling interaction ID that
2202 # we pass through. But the ID is something that is just left lying
2203 # around in addition to the counter, so I'd prefer to set the
2204 # counter to 0 now, and repeat at the end of the loop. But what
2205 # about dependencies? They appear later and are not reset, they
2206 # enter the queue but not its copy. How do they get a sensible
2209 # construct the queue
2211 STHING: foreach $s (@some) {
2214 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
2216 } elsif ($s =~ m|^/|) { # looks like a regexp
2217 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
2221 } elsif ($meth eq "ls") {
2222 $self->globls($s,\@pragma);
2225 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
2226 $obj = CPAN::Shell->expandany($s);
2229 $obj->color_cmd_tmps(0,1);
2230 CPAN::Queue->new($obj->id);
2232 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
2233 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
2234 if ($meth =~ /^(dump|ls)$/) {
2237 $CPAN::Frontend->myprint(
2239 "Don't be silly, you can't $meth ",
2247 ->myprint(qq{Warning: Cannot $meth $s, }.
2248 qq{don\'t know what it is.
2253 to find objects with matching identifiers.
2259 # queuerunner (please be warned: when I started to change the
2260 # queue to hold objects instead of names, I made one or two
2261 # mistakes and never found which. I reverted back instead)
2262 while ($s = CPAN::Queue->first) {
2265 $obj = $s; # I do not believe, we would survive if this happened
2267 $obj = CPAN::Shell->expandany($s);
2269 for my $pragma (@pragma) {
2272 ($] < 5.00303 || $obj->can($pragma))){
2273 ### compatibility with 5.003
2274 $obj->$pragma($meth); # the pragma "force" in
2275 # "CPAN::Distribution" must know
2276 # what we are intending
2279 if ($]>=5.00303 && $obj->can('called_for')) {
2280 $obj->called_for($s);
2283 qq{pragma[@pragma]meth[$meth]obj[$obj]as_string[$obj->{ID}]}
2287 CPAN::Queue->delete($s);
2289 CPAN->debug("failed");
2293 CPAN::Queue->delete_first($s);
2295 for my $obj (@qcopy) {
2296 $obj->color_cmd_tmps(0,0);
2297 delete $obj->{incommandcolor};
2301 #-> sub CPAN::Shell::recent ;
2305 CPAN::Distribution::_display_url( $self, $CPAN::Defaultrecent );
2310 # set up the dispatching methods
2312 for my $command (qw(
2327 *$command = sub { shift->rematein($command, @_); };
2331 package CPAN::LWP::UserAgent;
2335 return if $SETUPDONE;
2336 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2337 require LWP::UserAgent;
2338 @ISA = qw(Exporter LWP::UserAgent);
2341 $CPAN::Frontend->mywarn("LWP::UserAgent not available\n");
2345 sub get_basic_credentials {
2346 my($self, $realm, $uri, $proxy) = @_;
2347 return unless $proxy;
2348 if ($USER && $PASSWD) {
2349 } elsif (defined $CPAN::Config->{proxy_user} &&
2350 defined $CPAN::Config->{proxy_pass}) {
2351 $USER = $CPAN::Config->{proxy_user};
2352 $PASSWD = $CPAN::Config->{proxy_pass};
2354 ExtUtils::MakeMaker->import(qw(prompt));
2355 $USER = prompt("Proxy authentication needed!
2356 (Note: to permanently configure username and password run
2357 o conf proxy_user your_username
2358 o conf proxy_pass your_password
2360 if ($CPAN::META->has_inst("Term::ReadKey")) {
2361 Term::ReadKey::ReadMode("noecho");
2363 $CPAN::Frontend->mywarn("Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n");
2365 $PASSWD = prompt("Password:");
2366 if ($CPAN::META->has_inst("Term::ReadKey")) {
2367 Term::ReadKey::ReadMode("restore");
2369 $CPAN::Frontend->myprint("\n\n");
2371 return($USER,$PASSWD);
2374 # mirror(): Its purpose is to deal with proxy authentication. When we
2375 # call SUPER::mirror, we relly call the mirror method in
2376 # LWP::UserAgent. LWP::UserAgent will then call
2377 # $self->get_basic_credentials or some equivalent and this will be
2378 # $self->dispatched to our own get_basic_credentials method.
2380 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2382 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2383 # although we have gone through our get_basic_credentials, the proxy
2384 # server refuses to connect. This could be a case where the username or
2385 # password has changed in the meantime, so I'm trying once again without
2386 # $USER and $PASSWD to give the get_basic_credentials routine another
2387 # chance to set $USER and $PASSWD.
2389 # mirror(): Its purpose is to deal with proxy authentication. When we
2390 # call SUPER::mirror, we relly call the mirror method in
2391 # LWP::UserAgent. LWP::UserAgent will then call
2392 # $self->get_basic_credentials or some equivalent and this will be
2393 # $self->dispatched to our own get_basic_credentials method.
2395 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2397 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2398 # although we have gone through our get_basic_credentials, the proxy
2399 # server refuses to connect. This could be a case where the username or
2400 # password has changed in the meantime, so I'm trying once again without
2401 # $USER and $PASSWD to give the get_basic_credentials routine another
2402 # chance to set $USER and $PASSWD.
2405 my($self,$url,$aslocal) = @_;
2406 my $result = $self->SUPER::mirror($url,$aslocal);
2407 if ($result->code == 407) {
2410 $result = $self->SUPER::mirror($url,$aslocal);
2418 #-> sub CPAN::FTP::ftp_get ;
2420 my($class,$host,$dir,$file,$target) = @_;
2422 qq[Going to fetch file [$file] from dir [$dir]
2423 on host [$host] as local [$target]\n]
2425 my $ftp = Net::FTP->new($host);
2427 $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
2430 return 0 unless defined $ftp;
2431 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
2432 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
2433 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
2434 my $msg = $ftp->message;
2435 $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
2438 unless ( $ftp->cwd($dir) ){
2439 my $msg = $ftp->message;
2440 $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
2444 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
2445 unless ( $ftp->get($file,$target) ){
2446 my $msg = $ftp->message;
2447 $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
2450 $ftp->quit; # it's ok if this fails
2454 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
2456 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
2457 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
2459 # > *** 1562,1567 ****
2460 # > --- 1562,1580 ----
2461 # > return 1 if substr($url,0,4) eq "file";
2462 # > return 1 unless $url =~ m|://([^/]+)|;
2464 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
2466 # > + $proxy =~ m|://([^/:]+)|;
2468 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
2469 # > + if ($noproxy) {
2470 # > + if ($host !~ /$noproxy$/) {
2471 # > + $host = $proxy;
2474 # > + $host = $proxy;
2477 # > require Net::Ping;
2478 # > return 1 unless $Net::Ping::VERSION >= 2;
2482 #-> sub CPAN::FTP::localize ;
2484 my($self,$file,$aslocal,$force) = @_;
2486 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
2487 unless defined $aslocal;
2488 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
2491 if ($^O eq 'MacOS') {
2492 # Comment by AK on 2000-09-03: Uniq short filenames would be
2493 # available in CHECKSUMS file
2494 my($name, $path) = File::Basename::fileparse($aslocal, '');
2495 if (length($name) > 31) {
2506 my $size = 31 - length($suf);
2507 while (length($name) > $size) {
2511 $aslocal = File::Spec->catfile($path, $name);
2515 if (-f $aslocal && -r _ && !($force & 1)){
2517 if ($size = -s $aslocal) {
2518 $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG;
2521 # empty file from a previous unsuccessful attempt to download it
2523 $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I could not remove.");
2528 rename $aslocal, "$aslocal.bak";
2532 my($aslocal_dir) = File::Basename::dirname($aslocal);
2533 File::Path::mkpath($aslocal_dir);
2534 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
2535 qq{directory "$aslocal_dir".
2536 I\'ll continue, but if you encounter problems, they may be due
2537 to insufficient permissions.\n}) unless -w $aslocal_dir;
2539 # Inheritance is not easier to manage than a few if/else branches
2540 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2542 CPAN::LWP::UserAgent->config;
2543 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
2545 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
2549 $Ua->proxy('ftp', $var)
2550 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
2551 $Ua->proxy('http', $var)
2552 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
2555 # >>>>> On Wed, 13 Dec 2000 09:21:34 -0500, "Robison, Jonathon (J.M.)" <jrobiso2@visteon.com> said:
2557 # > I note that although CPAN.pm can use proxies, it doesn't seem equipped to
2558 # > use ones that require basic autorization.
2560 # > Example of when I use it manually in my own stuff:
2562 # > $ua->proxy(['http','ftp'], http://my.proxy.server:83');
2563 # > $req->proxy_authorization_basic("username","password");
2564 # > $res = $ua->request($req);
2568 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
2572 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
2573 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
2576 # Try the list of urls for each single object. We keep a record
2577 # where we did get a file from
2578 my(@reordered,$last);
2579 $CPAN::Config->{urllist} ||= [];
2580 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
2581 $CPAN::Frontend->mywarn("Malformed urllist; ignoring. Configuration file corrupt?\n");
2582 $CPAN::Config->{urllist} = [];
2584 $last = $#{$CPAN::Config->{urllist}};
2585 if ($force & 2) { # local cpans probably out of date, don't reorder
2586 @reordered = (0..$last);
2590 (substr($CPAN::Config->{urllist}[$b],0,4) eq "file")
2592 (substr($CPAN::Config->{urllist}[$a],0,4) eq "file")
2594 defined($ThesiteURL)
2596 ($CPAN::Config->{urllist}[$b] eq $ThesiteURL)
2598 ($CPAN::Config->{urllist}[$a] eq $ThesiteURL)
2603 @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/);
2605 @levels = qw/easy hard hardest/;
2607 @levels = qw/easy/ if $^O eq 'MacOS';
2609 local $ENV{FTP_PASSIVE} =
2610 exists $CPAN::Config->{ftp_passive} ?
2611 $CPAN::Config->{ftp_passive} : 1;
2612 for $levelno (0..$#levels) {
2613 my $level = $levels[$levelno];
2614 my $method = "host$level";
2615 my @host_seq = $level eq "easy" ?
2616 @reordered : 0..$last; # reordered has CDROM up front
2617 my @urllist = map { $CPAN::Config->{urllist}[$_] } @host_seq;
2618 for my $u (@urllist) {
2619 $u .= "/" unless substr($u,-1) eq "/";
2621 for my $u (@CPAN::Defaultsites) {
2622 push @urllist, $u unless grep { $_ eq $u } @urllist;
2624 $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
2625 my $ret = $self->$method(\@urllist,$file,$aslocal);
2627 $Themethod = $level;
2629 # utime $now, $now, $aslocal; # too bad, if we do that, we
2630 # might alter a local mirror
2631 $self->debug("level[$level]") if $CPAN::DEBUG;
2635 last if $CPAN::Signal; # need to cleanup
2638 unless ($CPAN::Signal) {
2641 qq{Please check, if the URLs I found in your configuration file \(}.
2642 join(", ", @{$CPAN::Config->{urllist}}).
2643 qq{\) are valid. The urllist can be edited.},
2644 qq{E.g. with 'o conf urllist push ftp://myurl/'};
2645 $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n");
2647 $CPAN::Frontend->myprint("Could not fetch $file\n");
2650 rename "$aslocal.bak", $aslocal;
2651 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
2652 $self->ls($aslocal));
2658 # package CPAN::FTP;
2660 my($self,$host_seq,$file,$aslocal) = @_;
2662 HOSTEASY: for $ro_url (@$host_seq) {
2663 my $url .= "$ro_url$file";
2664 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
2665 if ($url =~ /^file:/) {
2667 if ($CPAN::META->has_inst('URI::URL')) {
2668 my $u = URI::URL->new($url);
2670 } else { # works only on Unix, is poorly constructed, but
2671 # hopefully better than nothing.
2672 # RFC 1738 says fileurl BNF is
2673 # fileurl = "file://" [ host | "localhost" ] "/" fpath
2674 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
2676 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
2677 $l =~ s|^file:||; # assume they
2681 if ! -f $l && $l =~ m|^/\w:|; # e.g. /P:
2683 $self->debug("local file[$l]") if $CPAN::DEBUG;
2684 if ( -f $l && -r _) {
2685 $ThesiteURL = $ro_url;
2688 if ($l =~ /(.+)\.gz$/) {
2690 if ( -f $ungz && -r _) {
2691 $ThesiteURL = $ro_url;
2695 # Maybe mirror has compressed it?
2697 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
2698 CPAN::Tarzip->new("$l.gz")->gunzip($aslocal);
2700 $ThesiteURL = $ro_url;
2705 if ($CPAN::META->has_usable('LWP')) {
2706 $CPAN::Frontend->myprint("Fetching with LWP:
2710 CPAN::LWP::UserAgent->config;
2711 eval { $Ua = CPAN::LWP::UserAgent->new; };
2713 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
2716 my $res = $Ua->mirror($url, $aslocal);
2717 if ($res->is_success) {
2718 $ThesiteURL = $ro_url;
2720 utime $now, $now, $aslocal; # download time is more
2721 # important than upload time
2723 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2724 my $gzurl = "$url.gz";
2725 $CPAN::Frontend->myprint("Fetching with LWP:
2728 $res = $Ua->mirror($gzurl, "$aslocal.gz");
2729 if ($res->is_success &&
2730 CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)
2732 $ThesiteURL = $ro_url;
2736 $CPAN::Frontend->myprint(sprintf(
2737 "LWP failed with code[%s] message[%s]\n",
2741 # Alan Burlison informed me that in firewall environments
2742 # Net::FTP can still succeed where LWP fails. So we do not
2743 # skip Net::FTP anymore when LWP is available.
2746 $CPAN::Frontend->myprint("LWP not available\n");
2748 return if $CPAN::Signal;
2749 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2750 # that's the nice and easy way thanks to Graham
2751 my($host,$dir,$getfile) = ($1,$2,$3);
2752 if ($CPAN::META->has_usable('Net::FTP')) {
2754 $CPAN::Frontend->myprint("Fetching with Net::FTP:
2757 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
2758 "aslocal[$aslocal]") if $CPAN::DEBUG;
2759 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
2760 $ThesiteURL = $ro_url;
2763 if ($aslocal !~ /\.gz(?!\n)\Z/) {
2764 my $gz = "$aslocal.gz";
2765 $CPAN::Frontend->myprint("Fetching with Net::FTP
2768 if (CPAN::FTP->ftp_get($host,
2772 CPAN::Tarzip->new($gz)->gunzip($aslocal)
2774 $ThesiteURL = $ro_url;
2781 return if $CPAN::Signal;
2785 # package CPAN::FTP;
2787 my($self,$host_seq,$file,$aslocal) = @_;
2789 # Came back if Net::FTP couldn't establish connection (or
2790 # failed otherwise) Maybe they are behind a firewall, but they
2791 # gave us a socksified (or other) ftp program...
2794 my($devnull) = $CPAN::Config->{devnull} || "";
2796 my($aslocal_dir) = File::Basename::dirname($aslocal);
2797 File::Path::mkpath($aslocal_dir);
2798 HOSTHARD: for $ro_url (@$host_seq) {
2799 my $url = "$ro_url$file";
2800 my($proto,$host,$dir,$getfile);
2802 # Courtesy Mark Conty mark_conty@cargill.com change from
2803 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2805 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
2806 # proto not yet used
2807 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
2809 next HOSTHARD; # who said, we could ftp anything except ftp?
2811 next HOSTHARD if $proto eq "file"; # file URLs would have had
2812 # success above. Likely a bogus URL
2814 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
2816 # Try the most capable first and leave ncftp* for last as it only
2818 DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) {
2819 my $funkyftp = $CPAN::Config->{$f};
2820 next unless defined $funkyftp;
2821 next if $funkyftp =~ /^\s*$/;
2823 my($asl_ungz, $asl_gz);
2824 ($asl_ungz = $aslocal) =~ s/\.gz//;
2825 $asl_gz = "$asl_ungz.gz";
2827 my($src_switch) = "";
2829 my($stdout_redir) = " > $asl_ungz";
2831 $src_switch = " -source";
2832 } elsif ($f eq "ncftp"){
2833 $src_switch = " -c";
2834 } elsif ($f eq "wget"){
2835 $src_switch = " -O $asl_ungz";
2837 } elsif ($f eq 'curl'){
2838 $src_switch = ' -L -f -s -S --netrc-optional';
2841 if ($f eq "ncftpget"){
2842 $chdir = "cd $aslocal_dir && ";
2845 $CPAN::Frontend->myprint(
2847 Trying with "$funkyftp$src_switch" to get
2851 "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
2852 $self->debug("system[$system]") if $CPAN::DEBUG;
2853 my($wstatus) = system($system);
2855 # lynx returns 0 when it fails somewhere
2857 my $content = do { local *FH; open FH, $asl_ungz or die; local $/; <FH> };
2858 if ($content =~ /^<.*<title>[45]/si) {
2859 $CPAN::Frontend->myprint(qq{
2860 No success, the file that lynx has has downloaded looks like an error message:
2863 $CPAN::Frontend->mysleep(1);
2867 $CPAN::Frontend->myprint(qq{
2868 No success, the file that lynx has has downloaded is an empty file.
2873 if ($wstatus == 0) {
2876 } elsif ($asl_ungz ne $aslocal) {
2877 # test gzip integrity
2878 if (CPAN::Tarzip->new($asl_ungz)->gtest) {
2879 # e.g. foo.tar is gzipped --> foo.tar.gz
2880 rename $asl_ungz, $aslocal;
2882 CPAN::Tarzip->new($asl_gz)->gzip($asl_ungz);
2885 $ThesiteURL = $ro_url;
2887 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2889 -f $asl_ungz && -s _ == 0;
2890 my $gz = "$aslocal.gz";
2891 my $gzurl = "$url.gz";
2892 $CPAN::Frontend->myprint(
2894 Trying with "$funkyftp$src_switch" to get
2897 my($system) = "$funkyftp$src_switch \"$url.gz\" $devnull > $asl_gz";
2898 $self->debug("system[$system]") if $CPAN::DEBUG;
2900 if (($wstatus = system($system)) == 0
2904 # test gzip integrity
2905 my $ct = CPAN::Tarzip->new($asl_gz);
2907 $ct->gunzip($aslocal);
2909 # somebody uncompressed file for us?
2910 rename $asl_ungz, $aslocal;
2912 $ThesiteURL = $ro_url;
2915 unlink $asl_gz if -f $asl_gz;
2918 my $estatus = $wstatus >> 8;
2919 my $size = -f $aslocal ?
2920 ", left\n$aslocal with size ".-s _ :
2921 "\nWarning: expected file [$aslocal] doesn't exist";
2922 $CPAN::Frontend->myprint(qq{
2923 System call "$system"
2924 returned status $estatus (wstat $wstatus)$size
2927 return if $CPAN::Signal;
2928 } # transfer programs
2932 # package CPAN::FTP;
2934 my($self,$host_seq,$file,$aslocal) = @_;
2937 my($aslocal_dir) = File::Basename::dirname($aslocal);
2938 File::Path::mkpath($aslocal_dir);
2939 my $ftpbin = $CPAN::Config->{ftp};
2940 unless (length $ftpbin && MM->maybe_command($ftpbin)) {
2941 $CPAN::Frontend->myprint("No external ftp command available\n\n");
2944 $CPAN::Frontend->myprint(qq{
2945 As a last ressort we now switch to the external ftp command '$ftpbin'
2948 Doing so often leads to problems that are hard to diagnose, even endless
2949 loops may be encountered.
2951 If you're victim of such problems, please consider unsetting the ftp
2952 config variable with
2958 $CPAN::Frontend->mysleep(4);
2959 HOSTHARDEST: for $ro_url (@$host_seq) {
2960 my $url = "$ro_url$file";
2961 $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
2962 unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2965 my($host,$dir,$getfile) = ($1,$2,$3);
2967 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
2968 $ctime,$blksize,$blocks) = stat($aslocal);
2969 $timestamp = $mtime ||= 0;
2970 my($netrc) = CPAN::FTP::netrc->new;
2971 my($netrcfile) = $netrc->netrc;
2972 my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
2973 my $targetfile = File::Basename::basename($aslocal);
2979 map("cd $_", split /\//, $dir), # RFC 1738
2981 "get $getfile $targetfile",
2985 CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
2986 } elsif ($netrc->hasdefault || $netrc->contains($host)) {
2987 CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
2989 $netrc->contains($host))) if $CPAN::DEBUG;
2990 if ($netrc->protected) {
2991 my $dialog = join "", map { " $_\n" } @dialog;
2993 if ($netrc->contains($host)) {
2994 $netrc_explain = "Relying that your .netrc entry for '$host' ".
2995 "manages the login";
2997 $netrc_explain = "Relying that your default .netrc entry ".
2998 "manages the login";
3000 $CPAN::Frontend->myprint(qq{
3001 Trying with external ftp to get
3004 Going to send the dialog
3008 $self->talk_ftp("$ftpbin$verbose $host",
3010 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
3011 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
3013 if ($mtime > $timestamp) {
3014 $CPAN::Frontend->myprint("GOT $aslocal\n");
3015 $ThesiteURL = $ro_url;
3018 $CPAN::Frontend->myprint("Hmm... Still failed!\n");
3020 return if $CPAN::Signal;
3022 $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
3023 qq{correctly protected.\n});
3026 $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
3027 nor does it have a default entry\n");
3030 # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
3031 # then and login manually to host, using e-mail as
3033 $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n});
3037 "user anonymous $Config::Config{'cf_email'}"
3039 my $dialog = join "", map { " $_\n" } @dialog;
3040 $CPAN::Frontend->myprint(qq{
3041 Trying with external ftp to get
3043 Going to send the dialog
3047 $self->talk_ftp("$ftpbin$verbose -n", @dialog);
3048 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
3049 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
3051 if ($mtime > $timestamp) {
3052 $CPAN::Frontend->myprint("GOT $aslocal\n");
3053 $ThesiteURL = $ro_url;
3056 $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
3058 return if $CPAN::Signal;
3059 $CPAN::Frontend->myprint("Can't access URL $url.\n\n");
3064 # package CPAN::FTP;
3066 my($self,$command,@dialog) = @_;
3067 my $fh = FileHandle->new;
3068 $fh->open("|$command") or die "Couldn't open ftp: $!";
3069 foreach (@dialog) { $fh->print("$_\n") }
3070 $fh->close; # Wait for process to complete
3072 my $estatus = $wstatus >> 8;
3073 $CPAN::Frontend->myprint(qq{
3074 Subprocess "|$command"
3075 returned status $estatus (wstat $wstatus)
3079 # find2perl needs modularization, too, all the following is stolen
3083 my($self,$name) = @_;
3084 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
3085 $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
3087 my($perms,%user,%group);
3091 $blocks = int(($blocks + 1) / 2);
3094 $blocks = int(($sizemm + 1023) / 1024);
3097 if (-f _) { $perms = '-'; }
3098 elsif (-d _) { $perms = 'd'; }
3099 elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
3100 elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
3101 elsif (-p _) { $perms = 'p'; }
3102 elsif (-S _) { $perms = 's'; }
3103 else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
3105 my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
3106 my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
3107 my $tmpmode = $mode;
3108 my $tmp = $rwx[$tmpmode & 7];
3110 $tmp = $rwx[$tmpmode & 7] . $tmp;
3112 $tmp = $rwx[$tmpmode & 7] . $tmp;
3113 substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
3114 substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
3115 substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
3118 my $user = $user{$uid} || $uid; # too lazy to implement lookup
3119 my $group = $group{$gid} || $gid;
3121 my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
3123 my($moname) = $moname[$mon];
3124 if (-M _ > 365.25 / 2) {
3125 $timeyear = $year + 1900;
3128 $timeyear = sprintf("%02d:%02d", $hour, $min);
3131 sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
3145 package CPAN::FTP::netrc;
3148 # package CPAN::FTP::netrc;
3151 my $file = File::Spec->catfile($ENV{HOME},".netrc");
3153 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
3154 $atime,$mtime,$ctime,$blksize,$blocks)
3159 my($fh,@machines,$hasdefault);
3161 $fh = FileHandle->new or die "Could not create a filehandle";
3163 if($fh->open($file)){
3164 $protected = ($mode & 077) == 0;
3166 NETRC: while (<$fh>) {
3167 my(@tokens) = split " ", $_;
3168 TOKEN: while (@tokens) {
3169 my($t) = shift @tokens;
3170 if ($t eq "default"){
3174 last TOKEN if $t eq "macdef";
3175 if ($t eq "machine") {
3176 push @machines, shift @tokens;
3181 $file = $hasdefault = $protected = "";
3185 'mach' => [@machines],
3187 'hasdefault' => $hasdefault,
3188 'protected' => $protected,
3192 # CPAN::FTP::netrc::hasdefault;
3193 sub hasdefault { shift->{'hasdefault'} }
3194 sub netrc { shift->{'netrc'} }
3195 sub protected { shift->{'protected'} }
3197 my($self,$mach) = @_;
3198 for ( @{$self->{'mach'}} ) {
3199 return 1 if $_ eq $mach;
3204 package CPAN::Complete;
3208 my($text, $line, $start, $end) = @_;
3209 my(@perlret) = cpl($text, $line, $start);
3210 # find longest common match. Can anybody show me how to peruse
3211 # T::R::Gnu to have this done automatically? Seems expensive.
3212 return () unless @perlret;
3213 my($newtext) = $text;
3214 for (my $i = length($text)+1;;$i++) {
3215 last unless length($perlret[0]) && length($perlret[0]) >= $i;
3216 my $try = substr($perlret[0],0,$i);
3217 my @tries = grep {substr($_,0,$i) eq $try} @perlret;
3218 # warn "try[$try]tries[@tries]";
3219 if (@tries == @perlret) {
3225 ($newtext,@perlret);
3228 #-> sub CPAN::Complete::cpl ;
3230 my($word,$line,$pos) = @_;
3234 CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3236 if ($line =~ s/^(force\s*)//) {
3241 @return = grep /^$word/, @CPAN::Complete::COMMANDS;
3242 } elsif ( $line !~ /^[\!abcdghimorutl]/ ) {
3244 } elsif ($line =~ /^(a|ls)\s/) {
3245 @return = cplx('CPAN::Author',uc($word));
3246 } elsif ($line =~ /^b\s/) {
3247 CPAN::Shell->local_bundles;
3248 @return = cplx('CPAN::Bundle',$word);
3249 } elsif ($line =~ /^d\s/) {
3250 @return = cplx('CPAN::Distribution',$word);
3251 } elsif ($line =~ m/^(
3252 [mru]|make|clean|dump|get|test|install|readme|look|cvs_import|perldoc|recent
3254 if ($word =~ /^Bundle::/) {
3255 CPAN::Shell->local_bundles;
3257 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
3258 } elsif ($line =~ /^i\s/) {
3259 @return = cpl_any($word);
3260 } elsif ($line =~ /^reload\s/) {
3261 @return = cpl_reload($word,$line,$pos);
3262 } elsif ($line =~ /^o\s/) {
3263 @return = cpl_option($word,$line,$pos);
3264 } elsif ($line =~ m/^\S+\s/ ) {
3265 # fallback for future commands and what we have forgotten above
3266 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
3273 #-> sub CPAN::Complete::cplx ;
3275 my($class, $word) = @_;
3276 # I believed for many years that this was sorted, today I
3277 # realized, it wasn't sorted anymore. Now (rev 1.301 / v 1.55) I
3278 # make it sorted again. Maybe sort was dropped when GNU-readline
3279 # support came in? The RCS file is difficult to read on that:-(
3280 sort grep /^\Q$word\E/, map { $_->id } $CPAN::META->all_objects($class);
3283 #-> sub CPAN::Complete::cpl_any ;
3287 cplx('CPAN::Author',$word),
3288 cplx('CPAN::Bundle',$word),
3289 cplx('CPAN::Distribution',$word),
3290 cplx('CPAN::Module',$word),
3294 #-> sub CPAN::Complete::cpl_reload ;
3296 my($word,$line,$pos) = @_;
3298 my(@words) = split " ", $line;
3299 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3300 my(@ok) = qw(cpan index);
3301 return @ok if @words == 1;
3302 return grep /^\Q$word\E/, @ok if @words == 2 && $word;
3305 #-> sub CPAN::Complete::cpl_option ;
3307 my($word,$line,$pos) = @_;
3309 my(@words) = split " ", $line;
3310 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3311 my(@ok) = qw(conf debug);
3312 return @ok if @words == 1;
3313 return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
3315 } elsif ($words[1] eq 'index') {
3317 } elsif ($words[1] eq 'conf') {
3318 return CPAN::HandleConfig::cpl(@_);
3319 } elsif ($words[1] eq 'debug') {
3320 return sort grep /^\Q$word\E/i,
3321 sort keys %CPAN::DEBUG, 'all';
3325 package CPAN::Index;
3328 #-> sub CPAN::Index::force_reload ;
3331 $CPAN::Index::LAST_TIME = 0;
3335 #-> sub CPAN::Index::reload ;
3337 my($cl,$force) = @_;
3340 # XXX check if a newer one is available. (We currently read it
3341 # from time to time)
3342 for ($CPAN::Config->{index_expire}) {
3343 $_ = 0.001 unless $_ && $_ > 0.001;
3345 unless (1 || $CPAN::Have_warned->{readmetadatacache}++) {
3346 # debug here when CPAN doesn't seem to read the Metadata
3348 Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]");
3350 unless ($CPAN::META->{PROTOCOL}) {
3351 $cl->read_metadata_cache;
3352 $CPAN::META->{PROTOCOL} ||= "1.0";
3354 if ( $CPAN::META->{PROTOCOL} < PROTOCOL ) {
3355 # warn "Setting last_time to 0";
3356 $LAST_TIME = 0; # No warning necessary
3358 return if $LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time
3361 # IFF we are developing, it helps to wipe out the memory
3362 # between reloads, otherwise it is not what a user expects.
3363 undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274)
3364 $CPAN::META = CPAN->new;
3368 local $LAST_TIME = $time;
3369 local $CPAN::META->{PROTOCOL} = PROTOCOL;
3371 my $needshort = $^O eq "dos";
3373 $cl->rd_authindex($cl
3375 "authors/01mailrc.txt.gz",
3377 File::Spec->catfile('authors', '01mailrc.gz') :
3378 File::Spec->catfile('authors', '01mailrc.txt.gz'),
3381 $debug = "timing reading 01[".($t2 - $time)."]";
3383 return if $CPAN::Signal; # this is sometimes lengthy
3384 $cl->rd_modpacks($cl
3386 "modules/02packages.details.txt.gz",
3388 File::Spec->catfile('modules', '02packag.gz') :
3389 File::Spec->catfile('modules', '02packages.details.txt.gz'),
3392 $debug .= "02[".($t2 - $time)."]";
3394 return if $CPAN::Signal; # this is sometimes lengthy
3397 "modules/03modlist.data.gz",
3399 File::Spec->catfile('modules', '03mlist.gz') :
3400 File::Spec->catfile('modules', '03modlist.data.gz'),
3402 $cl->write_metadata_cache;
3404 $debug .= "03[".($t2 - $time)."]";
3406 CPAN->debug($debug) if $CPAN::DEBUG;
3409 $CPAN::META->{PROTOCOL} = PROTOCOL;
3412 #-> sub CPAN::Index::reload_x ;
3414 my($cl,$wanted,$localname,$force) = @_;
3415 $force |= 2; # means we're dealing with an index here
3416 CPAN::HandleConfig->load; # we should guarantee loading wherever we rely
3418 $localname ||= $wanted;
3419 my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'},
3423 -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
3426 my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
3427 $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
3428 qq{day$s. I\'ll use that.});
3431 $force |= 1; # means we're quite serious about it.
3433 return CPAN::FTP->localize($wanted,$abs_wanted,$force);
3436 #-> sub CPAN::Index::rd_authindex ;
3438 my($cl, $index_target) = @_;
3440 return unless defined $index_target;
3441 $CPAN::Frontend->myprint("Going to read $index_target\n");
3443 tie *FH, 'CPAN::Tarzip', $index_target;
3446 push @lines, split /\012/ while <FH>;
3448 my($userid,$fullname,$email) =
3449 m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
3450 next unless $userid && $fullname && $email;
3452 # instantiate an author object
3453 my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
3454 $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
3455 return if $CPAN::Signal;
3460 my($self,$dist) = @_;
3461 $dist = $self->{'id'} unless defined $dist;
3462 my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
3466 #-> sub CPAN::Index::rd_modpacks ;
3468 my($self, $index_target) = @_;
3470 return unless defined $index_target;
3471 $CPAN::Frontend->myprint("Going to read $index_target\n");
3472 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3475 while ($_ = $fh->READLINE) {
3477 my @ls = map {"$_\n"} split /\n/, $_;
3478 unshift @ls, "\n" x length($1) if /^(\n+)/;
3482 my($line_count,$last_updated);
3484 my $shift = shift(@lines);
3485 last if $shift =~ /^\s*$/;
3486 $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1;
3487 $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1;
3489 if (not defined $line_count) {
3491 warn qq{Warning: Your $index_target does not contain a Line-Count header.
3492 Please check the validity of the index file by comparing it to more
3493 than one CPAN mirror. I'll continue but problems seem likely to
3498 } elsif ($line_count != scalar @lines) {
3500 warn sprintf qq{Warning: Your %s
3501 contains a Line-Count header of %d but I see %d lines there. Please
3502 check the validity of the index file by comparing it to more than one
3503 CPAN mirror. I'll continue but problems seem likely to happen.\a\n},
3504 $index_target, $line_count, scalar(@lines);
3507 if (not defined $last_updated) {
3509 warn qq{Warning: Your $index_target does not contain a Last-Updated header.
3510 Please check the validity of the index file by comparing it to more
3511 than one CPAN mirror. I'll continue but problems seem likely to
3519 ->myprint(sprintf qq{ Database was generated on %s\n},
3521 $DATE_OF_02 = $last_updated;
3524 if ($CPAN::META->has_inst('HTTP::Date')) {
3526 $age -= HTTP::Date::str2time($last_updated);
3528 $CPAN::Frontend->myprint(" HTTP::Date not available\n");
3529 require Time::Local;
3530 my(@d) = $last_updated =~ / (\d+) (\w+) (\d+) (\d+):(\d+):(\d+) /;
3531 $d[1] = index("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", $d[1])/4;
3532 $age -= $d[1]>=0 ? Time::Local::timegm(@d[5,4,3,0,1,2]) : 0;
3539 qq{Warning: This index file is %d days old.
3540 Please check the host you chose as your CPAN mirror for staleness.
3541 I'll continue but problems seem likely to happen.\a\n},
3544 } elsif ($age < -1) {
3548 qq{Warning: Your system date is %d days behind this index file!
3550 Timestamp index file: %s
3551 Please fix your system time, problems with the make command expected.\n},
3561 # A necessity since we have metadata_cache: delete what isn't
3563 my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN");
3564 CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
3568 # before 1.56 we split into 3 and discarded the rest. From
3569 # 1.57 we assign remaining text to $comment thus allowing to
3570 # influence isa_perl
3571 my($mod,$version,$dist,$comment) = split " ", $_, 4;
3572 my($bundle,$id,$userid);
3574 if ($mod eq 'CPAN' &&
3576 CPAN::Queue->exists('Bundle::CPAN') ||
3577 CPAN::Queue->exists('CPAN')
3581 if ($version > $CPAN::VERSION){
3582 $CPAN::Frontend->myprint(qq{
3583 There's a new CPAN.pm version (v$version) available!
3584 [Current version is v$CPAN::VERSION]
3585 You might want to try
3588 without quitting the current session. It should be a seamless upgrade
3589 while we are running...
3592 $CPAN::Frontend->myprint(qq{\n});
3594 last if $CPAN::Signal;
3595 } elsif ($mod =~ /^Bundle::(.*)/) {
3600 $id = $CPAN::META->instance('CPAN::Bundle',$mod);
3601 # Let's make it a module too, because bundles have so much
3602 # in common with modules.
3604 # Changed in 1.57_63: seems like memory bloat now without
3605 # any value, so commented out
3607 # $CPAN::META->instance('CPAN::Module',$mod);
3611 # instantiate a module object
3612 $id = $CPAN::META->instance('CPAN::Module',$mod);
3616 # Although CPAN prohibits same name with different version the
3617 # indexer may have changed the version for the same distro
3618 # since the last time ("Force Reindexing" feature)
3619 if ($id->cpan_file ne $dist
3621 $id->cpan_version ne $version
3623 $userid = $id->userid || $self->userid($dist);
3625 'CPAN_USERID' => $userid,
3626 'CPAN_VERSION' => $version,
3627 'CPAN_FILE' => $dist,
3631 # instantiate a distribution object
3632 if ($CPAN::META->exists('CPAN::Distribution',$dist)) {
3633 # we do not need CONTAINSMODS unless we do something with
3634 # this dist, so we better produce it on demand.
3636 ## my $obj = $CPAN::META->instance(
3637 ## 'CPAN::Distribution' => $dist
3639 ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental
3641 $CPAN::META->instance(
3642 'CPAN::Distribution' => $dist
3644 'CPAN_USERID' => $userid,
3645 'CPAN_COMMENT' => $comment,
3649 for my $name ($mod,$dist) {
3650 CPAN->debug("exists name[$name]") if $CPAN::DEBUG;
3651 $exists{$name} = undef;
3654 return if $CPAN::Signal;
3658 for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) {
3659 for my $o ($CPAN::META->all_objects($class)) {
3660 next if exists $exists{$o->{ID}};
3661 $CPAN::META->delete($class,$o->{ID});
3662 CPAN->debug("deleting ID[$o->{ID}] in class[$class]")
3669 #-> sub CPAN::Index::rd_modlist ;
3671 my($cl,$index_target) = @_;
3672 return unless defined $index_target;
3673 $CPAN::Frontend->myprint("Going to read $index_target\n");
3674 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3678 while ($_ = $fh->READLINE) {
3680 my @ls = map {"$_\n"} split /\n/, $_;
3681 unshift @ls, "\n" x length($1) if /^(\n+)/;
3685 my $shift = shift(@eval);
3686 if ($shift =~ /^Date:\s+(.*)/){
3687 return if $DATE_OF_03 eq $1;
3690 last if $shift =~ /^\s*$/;
3693 push @eval, q{CPAN::Modulelist->data;};
3695 my($comp) = Safe->new("CPAN::Safe1");
3696 my($eval) = join("", @eval);
3697 my $ret = $comp->reval($eval);
3698 Carp::confess($@) if $@;
3699 return if $CPAN::Signal;
3701 my $obj = $CPAN::META->instance("CPAN::Module",$_);
3702 delete $ret->{$_}{modid}; # not needed here, maybe elsewhere
3703 $obj->set(%{$ret->{$_}});
3704 return if $CPAN::Signal;
3708 #-> sub CPAN::Index::write_metadata_cache ;
3709 sub write_metadata_cache {
3711 return unless $CPAN::Config->{'cache_metadata'};
3712 return unless $CPAN::META->has_usable("Storable");
3714 foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module
3715 CPAN::Distribution)) {
3716 $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok
3718 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3719 $cache->{last_time} = $LAST_TIME;
3720 $cache->{DATE_OF_02} = $DATE_OF_02;
3721 $cache->{PROTOCOL} = PROTOCOL;
3722 $CPAN::Frontend->myprint("Going to write $metadata_file\n");
3723 eval { Storable::nstore($cache, $metadata_file) };
3724 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3727 #-> sub CPAN::Index::read_metadata_cache ;
3728 sub read_metadata_cache {
3730 return unless $CPAN::Config->{'cache_metadata'};
3731 return unless $CPAN::META->has_usable("Storable");
3732 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3733 return unless -r $metadata_file and -f $metadata_file;
3734 $CPAN::Frontend->myprint("Going to read $metadata_file\n");
3736 eval { $cache = Storable::retrieve($metadata_file) };
3737 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3738 if (!$cache || ref $cache ne 'HASH'){
3742 if (exists $cache->{PROTOCOL}) {
3743 if (PROTOCOL > $cache->{PROTOCOL}) {
3744 $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ".
3745 "with protocol v%s, requiring v%s\n",
3752 $CPAN::Frontend->mywarn("Ignoring Metadata cache written ".
3753 "with protocol v1.0\n");
3758 while(my($class,$v) = each %$cache) {
3759 next unless $class =~ /^CPAN::/;
3760 $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok
3761 while (my($id,$ro) = each %$v) {
3762 $CPAN::META->{readwrite}{$class}{$id} ||=
3763 $class->new(ID=>$id, RO=>$ro);
3768 unless ($clcnt) { # sanity check
3769 $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n");
3772 if ($idcnt < 1000) {
3773 $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ".
3774 "in $metadata_file\n");
3777 $CPAN::META->{PROTOCOL} ||=
3778 $cache->{PROTOCOL}; # reading does not up or downgrade, but it
3779 # does initialize to some protocol
3780 $LAST_TIME = $cache->{last_time};
3781 $DATE_OF_02 = $cache->{DATE_OF_02};
3782 $CPAN::Frontend->myprint(" Database was generated on $DATE_OF_02\n")
3783 if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
3787 package CPAN::InfoObj;
3792 exists $self->{RO} and return $self->{RO};
3797 my $ro = $self->ro or return;
3798 return $ro->{CPAN_USERID};
3801 sub id { shift->{ID}; }
3803 #-> sub CPAN::InfoObj::new ;
3805 my $this = bless {}, shift;
3810 # The set method may only be used by code that reads index data or
3811 # otherwise "objective" data from the outside world. All session
3812 # related material may do anything else with instance variables but
3813 # must not touch the hash under the RO attribute. The reason is that
3814 # the RO hash gets written to Metadata file and is thus persistent.
3816 #-> sub CPAN::InfoObj::safe_chdir ;
3818 my($self,$todir) = @_;
3819 # we die if we cannot chdir and we are debuggable
3820 Carp::confess("safe_chdir called without todir argument")
3821 unless defined $todir and length $todir;
3823 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
3827 unless (-x $todir) {
3828 unless (chmod 0755, $todir) {
3829 my $cwd = CPAN::anycwd();
3830 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
3831 "permission to change the permission; cannot ".
3832 "chdir to '$todir'\n");
3833 $CPAN::Frontend->mysleep(5);
3834 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
3835 qq{to todir[$todir]: $!});
3839 $CPAN::Frontend->mydie("Directory '$todir' has gone. Cannot continue.\n");
3842 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
3845 my $cwd = CPAN::anycwd();
3846 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
3847 qq{to todir[$todir] (a chmod has been issued): $!});
3852 #-> sub CPAN::InfoObj::set ;
3854 my($self,%att) = @_;
3855 my $class = ref $self;
3857 # This must be ||=, not ||, because only if we write an empty
3858 # reference, only then the set method will write into the readonly
3859 # area. But for Distributions that spring into existence, maybe
3860 # because of a typo, we do not like it that they are written into
3861 # the readonly area and made permanent (at least for a while) and
3862 # that is why we do not "allow" other places to call ->set.
3863 unless ($self->id) {
3864 CPAN->debug("Bug? Empty ID, rejecting");
3867 my $ro = $self->{RO} =
3868 $CPAN::META->{readonly}{$class}{$self->id} ||= {};
3870 while (my($k,$v) = each %att) {
3875 #-> sub CPAN::InfoObj::as_glimpse ;
3879 my $class = ref($self);
3880 $class =~ s/^CPAN:://;
3881 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
3885 #-> sub CPAN::InfoObj::as_string ;
3889 my $class = ref($self);
3890 $class =~ s/^CPAN:://;
3891 push @m, $class, " id = $self->{ID}\n";
3893 unless ($ro = $self->ro) {
3894 $CPAN::Frontend->mydie("Unknown object $self->{ID}");
3896 for (sort keys %$ro) {
3897 # next if m/^(ID|RO)$/;
3899 if ($_ eq "CPAN_USERID") {
3901 $extra .= $self->fullname;
3902 my $email; # old perls!
3903 if ($email = $CPAN::META->instance("CPAN::Author",
3906 $extra .= " <$email>";
3908 $extra .= " <no email>";
3911 } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
3912 push @m, sprintf " %-12s %s\n", $_, $self->fullname;
3915 next unless defined $ro->{$_};
3916 push @m, sprintf " %-12s %s%s\n", $_, $ro->{$_}, $extra;
3918 for (sort keys %$self) {
3919 next if m/^(ID|RO)$/;
3920 if (ref($self->{$_}) eq "ARRAY") {
3921 push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
3922 } elsif (ref($self->{$_}) eq "HASH") {
3926 join(" ",sort keys %{$self->{$_}}),
3929 push @m, sprintf " %-12s %s\n", $_, $self->{$_};
3935 #-> sub CPAN::InfoObj::fullname ;
3938 $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
3941 #-> sub CPAN::InfoObj::dump ;
3944 require Data::Dumper;
3945 local $Data::Dumper::Sortkeys;
3946 $Data::Dumper::Sortkeys = 1;
3947 print Data::Dumper::Dumper($self);
3950 package CPAN::Author;
3953 #-> sub CPAN::Author::force
3959 #-> sub CPAN::Author::force
3962 delete $self->{force};
3965 #-> sub CPAN::Author::id
3968 my $id = $self->{ID};
3969 $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
3973 #-> sub CPAN::Author::as_glimpse ;
3977 my $class = ref($self);
3978 $class =~ s/^CPAN:://;
3979 push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
3987 #-> sub CPAN::Author::fullname ;
3989 shift->ro->{FULLNAME};
3993 #-> sub CPAN::Author::email ;
3994 sub email { shift->ro->{EMAIL}; }
3996 #-> sub CPAN::Author::ls ;
3999 my $glob = shift || "";
4000 my $silent = shift || 0;
4003 # adapted from CPAN::Distribution::verifyCHECKSUM ;
4004 my(@csf); # chksumfile
4005 @csf = $self->id =~ /(.)(.)(.*)/;
4006 $csf[1] = join "", @csf[0,1];
4007 $csf[2] = join "", @csf[1,2]; # ("A","AN","ANDK")
4009 @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0, 1);
4010 unless (grep {$_->[2] eq $csf[1]} @dl) {
4011 $CPAN::Frontend->myprint("Directory $csf[1]/ does not exist\n") unless $silent ;
4014 @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0, 1);
4015 unless (grep {$_->[2] eq $csf[2]} @dl) {
4016 $CPAN::Frontend->myprint("Directory $id/ does not exist\n") unless $silent;
4019 @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1, 1);
4021 if ($CPAN::META->has_inst("Text::Glob")) {
4022 my $rglob = Text::Glob::glob_to_regex($glob);
4023 @dl = grep { $_->[2] =~ /$rglob/ } @dl;
4025 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
4028 $CPAN::Frontend->myprint(join "", map {
4029 sprintf("%8d %10s %s/%s\n", $_->[0], $_->[1], $id, $_->[2])
4030 } sort { $a->[2] cmp $b->[2] } @dl);
4034 # returns an array of arrays, the latter contain (size,mtime,filename)
4035 #-> sub CPAN::Author::dir_listing ;
4038 my $chksumfile = shift;
4039 my $recursive = shift;
4040 my $may_ftp = shift;
4043 File::Spec->catfile($CPAN::Config->{keep_source_where},
4044 "authors", "id", @$chksumfile);
4048 # Purge and refetch old (pre-PGP) CHECKSUMS; they are a security
4049 # hazard. (Without GPG installed they are not that much better,
4051 $fh = FileHandle->new;
4052 if (open($fh, $lc_want)) {
4053 my $line = <$fh>; close $fh;
4054 unlink($lc_want) unless $line =~ /PGP/;
4058 # connect "force" argument with "index_expire".
4059 my $force = $self->{force};
4060 if (my @stat = stat $lc_want) {
4061 $force ||= $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
4065 $lc_file = CPAN::FTP->localize(
4066 "authors/id/@$chksumfile",
4071 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
4072 $chksumfile->[-1] .= ".gz";
4073 $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
4076 $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
4077 CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file);
4083 $lc_file = $lc_want;
4084 # we *could* second-guess and if the user has a file: URL,
4085 # then we could look there. But on the other hand, if they do
4086 # have a file: URL, wy did they choose to set
4087 # $CPAN::Config->{show_upload_date} to false?
4090 # adapted from CPAN::Distribution::CHECKSUM_check_file ;
4091 $fh = FileHandle->new;
4093 if (open $fh, $lc_file){
4096 $eval =~ s/\015?\012/\n/g;
4098 my($comp) = Safe->new();
4099 $cksum = $comp->reval($eval);
4101 rename $lc_file, "$lc_file.bad";
4102 Carp::confess($@) if $@;
4104 } elsif ($may_ftp) {
4105 Carp::carp "Could not open '$lc_file' for reading.";
4107 # Maybe should warn: "You may want to set show_upload_date to a true value"
4111 for $f (sort keys %$cksum) {
4112 if (exists $cksum->{$f}{isdir}) {
4114 my(@dir) = @$chksumfile;
4116 push @dir, $f, "CHECKSUMS";
4118 [$_->[0], $_->[1], "$f/$_->[2]"]
4119 } $self->dir_listing(\@dir,1,$may_ftp);
4121 push @result, [ 0, "-", $f ];
4125 ($cksum->{$f}{"size"}||0),
4126 $cksum->{$f}{"mtime"}||"---",
4134 package CPAN::Distribution;
4140 my $ro = $self->ro or return;
4144 # CPAN::Distribution::undelay
4147 delete $self->{later};
4150 # add the A/AN/ stuff
4151 # CPAN::Distribution::normalize
4154 $s = $self->id unless defined $s;
4158 $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
4160 return $s if $s =~ m:^N/A|^Contact Author: ;
4161 $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4| or
4162 $CPAN::Frontend->mywarn("Strange distribution name [$s]\n");
4163 CPAN->debug("s[$s]") if $CPAN::DEBUG;
4168 #-> sub CPAN::Distribution::author ;
4171 my($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
4172 CPAN::Shell->expand("Author",$authorid);
4175 # tries to get the yaml from CPAN instead of the distro itself:
4176 # EXPERIMENTAL, UNDOCUMENTED AND UNTESTED, for Tels
4179 my $meta = $self->pretty_id;
4180 $meta =~ s/\.(tar.gz|tgz|zip|tar.bz2)/.meta/;
4181 my(@ls) = CPAN::Shell->globls($meta);
4182 my $norm = $self->normalize($meta);
4186 File::Spec->catfile(
4187 $CPAN::Config->{keep_source_where},
4192 $self->debug("Doing localize") if $CPAN::DEBUG;
4193 unless ($local_file =
4194 CPAN::FTP->localize("authors/id/$norm",
4196 $CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n");
4198 if ($CPAN::META->has_inst("YAML")) {
4199 my $yaml = YAML::LoadFile($local_file);
4202 $CPAN::Frontend->mydie("Yaml not installed, cannot parse '$local_file'\n");
4209 return $id unless $id =~ m|^./../|;
4213 # mark as dirty/clean
4214 #-> sub CPAN::Distribution::color_cmd_tmps ;
4215 sub color_cmd_tmps {
4217 my($depth) = shift || 0;
4218 my($color) = shift || 0;
4219 my($ancestors) = shift || [];
4220 # a distribution needs to recurse into its prereq_pms
4222 return if exists $self->{incommandcolor}
4223 && $self->{incommandcolor}==$color;
4225 $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
4227 # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
4228 my $prereq_pm = $self->prereq_pm;
4229 if (defined $prereq_pm) {
4230 PREREQ: for my $pre (keys %$prereq_pm) {
4232 unless ($premo = CPAN::Shell->expand("Module",$pre)) {
4233 $CPAN::Frontend->mywarn("prerequisite module[$pre] not known\n");
4234 $CPAN::Frontend->mysleep(2);
4237 $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
4241 delete $self->{sponsored_mods};
4242 delete $self->{badtestcnt};
4244 $self->{incommandcolor} = $color;
4247 #-> sub CPAN::Distribution::as_string ;
4250 $self->containsmods;
4252 $self->SUPER::as_string(@_);
4255 #-> sub CPAN::Distribution::containsmods ;
4258 return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
4259 my $dist_id = $self->{ID};
4260 for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
4261 my $mod_file = $mod->cpan_file or next;
4262 my $mod_id = $mod->{ID} or next;
4263 # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
4265 $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
4267 keys %{$self->{CONTAINSMODS}};
4270 #-> sub CPAN::Distribution::upload_date ;
4273 return $self->{UPLOAD_DATE} if exists $self->{UPLOAD_DATE};
4274 my(@local_wanted) = split(/\//,$self->id);
4275 my $filename = pop @local_wanted;
4276 push @local_wanted, "CHECKSUMS";
4277 my $author = CPAN::Shell->expand("Author",$self->cpan_userid);
4278 return unless $author;
4279 my @dl = $author->dir_listing(\@local_wanted,0,$CPAN::Config->{show_upload_date});
4281 my($dirent) = grep { $_->[2] eq $filename } @dl;
4282 # warn sprintf "dirent[%s]id[%s]", $dirent, $self->id;
4283 return unless $dirent->[1];
4284 return $self->{UPLOAD_DATE} = $dirent->[1];
4287 #-> sub CPAN::Distribution::uptodate ;
4291 foreach $c ($self->containsmods) {
4292 my $obj = CPAN::Shell->expandany($c);
4293 return 0 unless $obj->uptodate;
4298 #-> sub CPAN::Distribution::called_for ;
4301 $self->{CALLED_FOR} = $id if defined $id;
4302 return $self->{CALLED_FOR};
4305 #-> sub CPAN::Distribution::get ;
4310 exists $self->{'build_dir'} and push @e,
4311 "Is already unwrapped into directory $self->{'build_dir'}";
4312 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4314 my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
4317 # Get the file on local disk
4322 File::Spec->catfile(
4323 $CPAN::Config->{keep_source_where},
4326 split(/\//,$self->id)
4329 $self->debug("Doing localize") if $CPAN::DEBUG;
4330 unless ($local_file =
4331 CPAN::FTP->localize("authors/id/$self->{ID}",
4334 if ($CPAN::Index::DATE_OF_02) {
4335 $note = "Note: Current database in memory was generated ".
4336 "on $CPAN::Index::DATE_OF_02\n";
4338 $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
4340 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
4341 $self->{localfile} = $local_file;
4342 return if $CPAN::Signal;
4347 if ($CPAN::META->has_inst("Digest::SHA")) {
4348 $self->debug("Digest::SHA is installed, verifying");
4349 $self->verifyCHECKSUM;
4351 $self->debug("Digest::SHA is NOT installed");
4353 return if $CPAN::Signal;
4356 # Create a clean room and go there
4358 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
4359 my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
4360 $self->safe_chdir($builddir);
4361 $self->debug("Removing tmp") if $CPAN::DEBUG;
4362 File::Path::rmtree("tmp");
4363 unless (mkdir "tmp", 0755) {
4364 $CPAN::Frontend->unrecoverable_error(<<EOF);
4365 Couldn't mkdir '$builddir/tmp': $!
4367 Cannot continue: Please find the reason why I cannot make the
4370 and fix the problem, then retry.
4375 $self->safe_chdir($sub_wd);
4378 $self->safe_chdir("tmp");
4383 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
4384 my $ct = CPAN::Tarzip->new($local_file);
4385 if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i){
4386 $self->{was_uncompressed}++ unless $ct->gtest();
4387 $self->untar_me($ct);
4388 } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
4389 $self->unzip_me($ct);
4390 } elsif ( $local_file =~ /\.pm(\.(gz|Z))?(?!\n)\Z/) {
4391 $self->{was_uncompressed}++ unless $ct->gtest();
4392 $self->debug("calling pm2dir for local_file[$local_file]") if $CPAN::DEBUG;
4393 $self->pm2dir_me($local_file);
4395 $self->{archived} = "NO";
4396 $self->safe_chdir($sub_wd);
4400 # we are still in the tmp directory!
4401 # Let's check if the package has its own directory.
4402 my $dh = DirHandle->new(File::Spec->curdir)
4403 or Carp::croak("Couldn't opendir .: $!");
4404 my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
4406 my ($distdir,$packagedir);
4407 if (@readdir == 1 && -d $readdir[0]) {
4408 $distdir = $readdir[0];
4409 $packagedir = File::Spec->catdir($builddir,$distdir);
4410 $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]")
4412 -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
4414 File::Path::rmtree($packagedir);
4415 unless (File::Copy::move($distdir,$packagedir)) {
4416 $CPAN::Frontend->unrecoverable_error(<<EOF);
4417 Couldn't move '$distdir' to '$packagedir': $!
4419 Cannot continue: Please find the reason why I cannot move
4420 $builddir/tmp/$distdir
4423 and fix the problem, then retry
4427 $self->debug(sprintf("moved distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
4434 my $userid = $self->cpan_userid;
4436 CPAN->debug("no userid? self[$self]");
4439 my $pragmatic_dir = $userid . '000';
4440 $pragmatic_dir =~ s/\W_//g;
4441 $pragmatic_dir++ while -d "../$pragmatic_dir";
4442 $packagedir = File::Spec->catdir($builddir,$pragmatic_dir);
4443 $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG;
4444 File::Path::mkpath($packagedir);
4446 for $f (@readdir) { # is already without "." and ".."
4447 my $to = File::Spec->catdir($packagedir,$f);
4448 File::Copy::move($f,$to) or Carp::confess("Couldn't move $f to $to: $!");
4452 $self->safe_chdir($sub_wd);
4456 $self->{'build_dir'} = $packagedir;
4457 $self->safe_chdir($builddir);
4458 File::Path::rmtree("tmp");
4460 $self->safe_chdir($packagedir);
4461 if ($CPAN::META->has_inst("Module::Signature")) {
4462 if (-f "SIGNATURE") {
4463 $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
4464 my $rv = Module::Signature::verify();
4465 if ($rv != Module::Signature::SIGNATURE_OK() and
4466 $rv != Module::Signature::SIGNATURE_MISSING()) {
4467 $CPAN::Frontend->myprint(
4468 qq{\nSignature invalid for }.
4469 qq{distribution file. }.
4470 qq{Please investigate.\n\n}.
4472 $CPAN::META->instance(
4479 sprintf(qq{I'd recommend removing %s. Its signature
4480 is invalid. Maybe you have configured your 'urllist' with
4481 a bad URL. Please check this array with 'o conf urllist', and
4482 retry. For more information, try opening a subshell with
4490 $self->{signature_verify} = CPAN::Distrostatus->new("NO");
4491 $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap));
4492 $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep");
4494 $self->{signature_verify} = CPAN::Distrostatus->new("YES");
4497 $CPAN::Frontend->myprint(qq{Package came without SIGNATURE\n\n});
4500 $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;