1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $VERSION = eval $VERSION;
7 use CPAN::HandleConfig;
16 use ExtUtils::MakeMaker (); # $SelfLoader::DEBUG=1;
17 use File::Basename ();
24 use Sys::Hostname qw(hostname);
25 use Text::ParseWords ();
27 no lib "."; # we need to run chdir all over and we would get at wrong
30 require Mac::BuildTools if $^O eq 'MacOS';
32 END { $CPAN::End++; &cleanup; }
35 $CPAN::Frontend ||= "CPAN::Shell";
36 @CPAN::Defaultsites = ("http://www.perl.org/CPAN/","ftp://ftp.perl.org/pub/CPAN/")
37 unless @CPAN::Defaultsites;
38 # $CPAN::iCwd (i for initial) is going to be initialized during find_perl
39 $CPAN::Perl ||= CPAN::find_perl();
40 $CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
41 $CPAN::Defaultrecent ||= "http://search.cpan.org/recent";
47 use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $HAS_USABLE $term
48 $Signal $Suppress_readline $Frontend
49 @Defaultsites $Have_warned $Defaultdocs $Defaultrecent
52 @CPAN::ISA = qw(CPAN::Debug Exporter);
54 # note that these functions live in CPAN::Shell and get executed via
55 # AUTOLOAD when called directly
76 sub soft_chdir_with_alternatives ($);
78 #-> sub CPAN::AUTOLOAD ;
83 @EXPORT{@EXPORT} = '';
84 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
85 if (exists $EXPORT{$l}){
88 $CPAN::Frontend->mywarn(qq{Unknown CPAN command "$AUTOLOAD". }.
97 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
98 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
100 my $oprompt = shift || CPAN::Prompt->new;
101 my $prompt = $oprompt;
102 my $commandline = shift || "";
103 $CPAN::CurrentCommandId ||= 1;
106 unless ($Suppress_readline) {
107 require Term::ReadLine;
110 $term->ReadLine eq "Term::ReadLine::Stub"
112 $term = Term::ReadLine->new('CPAN Monitor');
114 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
115 my $attribs = $term->Attribs;
116 $attribs->{attempted_completion_function} = sub {
117 &CPAN::Complete::gnu_cpl;
120 $readline::rl_completion_function =
121 $readline::rl_completion_function = 'CPAN::Complete::cpl';
123 if (my $histfile = $CPAN::Config->{'histfile'}) {{
124 unless ($term->can("AddHistory")) {
125 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
128 my($fh) = FileHandle->new;
129 open $fh, "<$histfile" or last;
133 $term->AddHistory($_);
137 # $term->OUT is autoflushed anyway
138 my $odef = select STDERR;
145 # no strict; # I do not recall why no strict was here (2000-09-03)
149 File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
150 File::Spec->rootdir(),
152 my $try_detect_readline;
153 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
154 my $rl_avail = $Suppress_readline ? "suppressed" :
155 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
156 "available (try 'install Bundle::CPAN')";
158 $CPAN::Frontend->myprint(
160 cpan shell -- CPAN exploration and modules installation (v%s)
167 unless $CPAN::Config->{'inhibit_startup_message'} ;
168 my($continuation) = "";
169 SHELLCOMMAND: while () {
170 if ($Suppress_readline) {
172 last SHELLCOMMAND unless defined ($_ = <> );
175 last SHELLCOMMAND unless
176 defined ($_ = $term->readline($prompt, $commandline));
178 $_ = "$continuation$_" if $continuation;
180 next SHELLCOMMAND if /^$/;
181 $_ = 'h' if /^\s*\?/;
182 if (/^(?:q(?:uit)?|bye|exit)$/i) {
193 use vars qw($import_done);
194 CPAN->import(':DEFAULT') unless $import_done++;
195 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
202 if ($] < 5.00322) { # parsewords had a bug until recently
205 eval { @line = Text::ParseWords::shellwords($_) };
206 warn($@), next SHELLCOMMAND if $@;
207 warn("Text::Parsewords could not parse the line [$_]"),
208 next SHELLCOMMAND unless @line;
210 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
211 my $command = shift @line;
212 eval { CPAN::Shell->$command(@line) };
214 if ($command =~ /^(make|test|install|force|notest)$/) {
215 CPAN::Shell->failed($CPAN::CurrentCommandId,1);
217 soft_chdir_with_alternatives(\@cwd);
218 $CPAN::Frontend->myprint("\n");
220 $CPAN::CurrentCommandId++;
224 $commandline = ""; # I do want to be able to pass a default to
225 # shell, but on the second command I see no
228 CPAN::Queue->nullify_queue;
229 if ($try_detect_readline) {
230 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
232 $CPAN::META->has_inst("Term::ReadLine::Perl")
234 delete $INC{"Term/ReadLine.pm"};
236 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
237 require Term::ReadLine;
238 $CPAN::Frontend->myprint("\n$redef subroutines in ".
239 "Term::ReadLine redefined\n");
245 soft_chdir_with_alternatives(\@cwd);
248 sub soft_chdir_with_alternatives ($) {
250 while (not chdir $cwd->[0]) {
252 $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
253 Trying to chdir to "$cwd->[1]" instead.
257 $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
262 package CPAN::CacheMgr;
264 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
269 use vars qw($Ua $Thesite $ThesiteURL $Themethod);
270 @CPAN::FTP::ISA = qw(CPAN::Debug);
272 package CPAN::LWP::UserAgent;
274 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
275 # we delay requiring LWP::UserAgent and setting up inheritance until we need it
277 package CPAN::Complete;
279 @CPAN::Complete::ISA = qw(CPAN::Debug);
280 @CPAN::Complete::COMMANDS = sort qw(
281 ! a b d h i m o q r u
303 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
304 @CPAN::Index::ISA = qw(CPAN::Debug);
307 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
310 package CPAN::InfoObj;
312 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
314 package CPAN::Author;
316 @CPAN::Author::ISA = qw(CPAN::InfoObj);
318 package CPAN::Distribution;
320 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
322 package CPAN::Bundle;
324 @CPAN::Bundle::ISA = qw(CPAN::Module);
326 package CPAN::Module;
328 @CPAN::Module::ISA = qw(CPAN::InfoObj);
330 package CPAN::Exception::RecursiveDependency;
332 use overload '""' => "as_string";
339 for my $dep (@$deps) {
341 last if $seen{$dep}++;
343 bless { deps => \@deps }, $class;
348 "\nRecursive dependency detected:\n " .
349 join("\n => ", @{$self->{deps}}) .
350 ".\nCannot continue.\n";
353 package CPAN::Prompt; use overload '""' => "as_string";
354 use vars qw($prompt);
356 $CPAN::CurrentCommandId ||= 0;
357 sub as_randomly_capitalized_string {
359 substr($prompt,$_,1)=rand()<0.5 ?
360 uc(substr($prompt,$_,1)) :
361 lc(substr($prompt,$_,1)) for 0..3;
368 if ($CPAN::Config->{commandnumber_in_prompt}) {
369 sprintf "cpan[%d]> ", $CPAN::CurrentCommandId;
375 package CPAN::Distrostatus;
376 use overload '""' => "as_string",
379 my($class,$arg) = @_;
382 FAILED => substr($arg,0,2) eq "NO",
383 COMMANDID => $CPAN::CurrentCommandId,
386 sub commandid { shift->{COMMANDID} }
387 sub failed { shift->{FAILED} }
391 $self->{TEXT} = $set;
402 use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
403 @CPAN::Shell::ISA = qw(CPAN::Debug);
404 $COLOR_REGISTERED ||= 0;
405 $PRINT_ORNAMENTING ||= 0;
407 #-> sub CPAN::Shell::AUTOLOAD ;
409 my($autoload) = $AUTOLOAD;
410 my $class = shift(@_);
411 # warn "autoload[$autoload] class[$class]";
412 $autoload =~ s/.*:://;
413 if ($autoload =~ /^w/) {
414 if ($CPAN::META->has_inst('CPAN::WAIT')) {
415 CPAN::WAIT->$autoload(@_);
417 $CPAN::Frontend->mywarn(qq{
418 Commands starting with "w" require CPAN::WAIT to be installed.
419 Please consider installing CPAN::WAIT to use the fulltext index.
420 For this you just need to type
425 $CPAN::Frontend->mywarn(qq{Unknown shell command '$autoload'. }.
434 # One use of the queue is to determine if we should or shouldn't
435 # announce the availability of a new CPAN module
437 # Now we try to use it for dependency tracking. For that to happen
438 # we need to draw a dependency tree and do the leaves first. This can
439 # easily be reached by running CPAN.pm recursively, but we don't want
440 # to waste memory and run into deep recursion. So what we can do is
443 # CPAN::Queue is the package where the queue is maintained. Dependencies
444 # often have high priority and must be brought to the head of the queue,
445 # possibly by jumping the queue if they are already there. My first code
446 # attempt tried to be extremely correct. Whenever a module needed
447 # immediate treatment, I either unshifted it to the front of the queue,
448 # or, if it was already in the queue, I spliced and let it bypass the
449 # others. This became a too correct model that made it impossible to put
450 # an item more than once into the queue. Why would you need that? Well,
451 # you need temporary duplicates as the manager of the queue is a loop
454 # (1) looks at the first item in the queue without shifting it off
456 # (2) cares for the item
458 # (3) removes the item from the queue, *even if its agenda failed and
459 # even if the item isn't the first in the queue anymore* (that way
460 # protecting against never ending queues)
462 # So if an item has prerequisites, the installation fails now, but we
463 # want to retry later. That's easy if we have it twice in the queue.
465 # I also expect insane dependency situations where an item gets more
466 # than two lives in the queue. Simplest example is triggered by 'install
467 # Foo Foo Foo'. People make this kind of mistakes and I don't want to
468 # get in the way. I wanted the queue manager to be a dumb servant, not
469 # one that knows everything.
471 # Who would I tell in this model that the user wants to be asked before
472 # processing? I can't attach that information to the module object,
473 # because not modules are installed but distributions. So I'd have to
474 # tell the distribution object that it should ask the user before
475 # processing. Where would the question be triggered then? Most probably
476 # in CPAN::Distribution::rematein.
477 # Hope that makes sense, my head is a bit off:-) -- AK
484 my $self = bless { qmod => $s }, $class;
489 # CPAN::Queue::first ;
495 # CPAN::Queue::delete_first ;
497 my($class,$what) = @_;
499 for my $i (0..$#All) {
500 if ( $All[$i]->{qmod} eq $what ) {
507 # CPAN::Queue::jumpqueue ;
511 CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
512 join(",",map {$_->{qmod}} @All),
515 WHAT: for my $what (reverse @what) {
517 for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
518 CPAN->debug("i[$All[$i]]what[$what]") if $CPAN::DEBUG;
519 if ($All[$i]->{qmod} eq $what){
521 if ($jumped > 100) { # one's OK if e.g. just
522 # processing now; more are OK if
523 # user typed it several times
524 $CPAN::Frontend->mywarn(
525 qq{Object [$what] queued more than 100 times, ignoring}
531 my $obj = bless { qmod => $what }, $class;
534 CPAN->debug(sprintf("after jumpqueue All[%s] what[%s]",
535 join(",",map {$_->{qmod}} @All),
540 # CPAN::Queue::exists ;
542 my($self,$what) = @_;
543 my @all = map { $_->{qmod} } @All;
544 my $exists = grep { $_->{qmod} eq $what } @All;
545 # warn "in exists what[$what] all[@all] exists[$exists]";
549 # CPAN::Queue::delete ;
552 @All = grep { $_->{qmod} ne $mod } @All;
555 # CPAN::Queue::nullify_queue ;
565 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
567 # from here on only subs.
568 ################################################################################
570 #-> sub CPAN::all_objects ;
572 my($mgr,$class) = @_;
573 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
574 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
576 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
578 *all = \&all_objects;
580 # Called by shell, not in batch mode. In batch mode I see no risk in
581 # having many processes updating something as installations are
582 # continually checked at runtime. In shell mode I suspect it is
583 # unintentional to open more than one shell at a time
585 #-> sub CPAN::checklock ;
588 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
589 if (-f $lockfile && -M _ > 0) {
590 my $fh = FileHandle->new($lockfile) or
591 $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
592 my $otherpid = <$fh>;
593 my $otherhost = <$fh>;
595 if (defined $otherpid && $otherpid) {
598 if (defined $otherhost && $otherhost) {
601 my $thishost = hostname();
602 if (defined $otherhost && defined $thishost &&
603 $otherhost ne '' && $thishost ne '' &&
604 $otherhost ne $thishost) {
605 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
606 "reports other host $otherhost and other ".
607 "process $otherpid.\n".
608 "Cannot proceed.\n"));
610 elsif (defined $otherpid && $otherpid) {
611 return if $$ == $otherpid; # should never happen
612 $CPAN::Frontend->mywarn(
614 There seems to be running another CPAN process (pid $otherpid). Contacting...
616 if (kill 0, $otherpid) {
617 $CPAN::Frontend->mydie(qq{Other job is running.
618 You may want to kill it and delete the lockfile, maybe. On UNIX try:
622 } elsif (-w $lockfile) {
624 ExtUtils::MakeMaker::prompt
625 (qq{Other job not responding. Shall I overwrite }.
626 qq{the lockfile '$lockfile'? (Y/n)},"y");
627 $CPAN::Frontend->myexit("Ok, bye\n")
628 unless $ans =~ /^y/i;
631 qq{Lockfile '$lockfile' not writeable by you. }.
632 qq{Cannot proceed.\n}.
634 qq{ rm '$lockfile'\n}.
635 qq{ and then rerun us.\n}
639 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
640 "reports other process with ID ".
641 "$otherpid. Cannot proceed.\n"));
644 my $dotcpan = $CPAN::Config->{cpan_home};
645 eval { File::Path::mkpath($dotcpan);};
647 # A special case at least for Jarkko.
652 $symlinkcpan = readlink $dotcpan;
653 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
654 eval { File::Path::mkpath($symlinkcpan); };
658 $CPAN::Frontend->mywarn(qq{
659 Working directory $symlinkcpan created.
663 unless (-d $dotcpan) {
665 Your configuration suggests "$dotcpan" as your
666 CPAN.pm working directory. I could not create this directory due
667 to this error: $firsterror\n};
669 As "$dotcpan" is a symlink to "$symlinkcpan",
670 I tried to create that, but I failed with this error: $seconderror
673 Please make sure the directory exists and is writable.
675 $CPAN::Frontend->mydie($diemess);
677 } # $@ after eval mkpath $dotcpan
679 unless ($fh = FileHandle->new(">$lockfile")) {
680 if ($! =~ /Permission/) {
681 my $incc = $INC{'CPAN/Config.pm'};
682 my $myincc = File::Spec->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
683 $CPAN::Frontend->myprint(qq{
685 Your configuration suggests that CPAN.pm should use a working
687 $CPAN::Config->{cpan_home}
688 Unfortunately we could not create the lock file
690 due to permission problems.
692 Please make sure that the configuration variable
693 \$CPAN::Config->{cpan_home}
694 points to a directory where you can write a .lock file. You can set
695 this variable in either
700 if(!$INC{'CPAN/MyConfig.pm'}) {
701 $CPAN::Frontend->myprint("You don't seem to have a user ".
702 "configuration (MyConfig.pm) yet.\n");
703 my $new = ExtUtils::MakeMaker::prompt("Do you want to create a ".
704 "user configuration now? (Y/n)",
707 CPAN::Shell->mkmyconfig();
712 $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
714 $fh->print($$, "\n");
715 $fh->print(hostname(), "\n");
716 $self->{LOCK} = $lockfile;
720 $CPAN::Frontend->mydie("Got SIGTERM, leaving");
725 $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
726 print "Caught SIGINT\n";
730 # From: Larry Wall <larry@wall.org>
731 # Subject: Re: deprecating SIGDIE
732 # To: perl5-porters@perl.org
733 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
735 # The original intent of __DIE__ was only to allow you to substitute one
736 # kind of death for another on an application-wide basis without respect
737 # to whether you were in an eval or not. As a global backstop, it should
738 # not be used any more lightly (or any more heavily :-) than class
739 # UNIVERSAL. Any attempt to build a general exception model on it should
740 # be politely squashed. Any bug that causes every eval {} to have to be
741 # modified should be not so politely squashed.
743 # Those are my current opinions. It is also my optinion that polite
744 # arguments degenerate to personal arguments far too frequently, and that
745 # when they do, it's because both people wanted it to, or at least didn't
746 # sufficiently want it not to.
750 # global backstop to cleanup if we should really die
751 $SIG{__DIE__} = \&cleanup;
752 $self->debug("Signal handler set.") if $CPAN::DEBUG;
755 #-> sub CPAN::DESTROY ;
757 &cleanup; # need an eval?
760 #-> sub CPAN::anycwd ;
763 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
768 sub cwd {Cwd::cwd();}
770 #-> sub CPAN::getcwd ;
771 sub getcwd {Cwd::getcwd();}
773 #-> sub CPAN::fastcwd ;
774 sub fastcwd {Cwd::fastcwd();}
776 #-> sub CPAN::backtickcwd ;
777 sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
779 #-> sub CPAN::find_perl ;
781 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
782 my $pwd = $CPAN::iCwd = CPAN::anycwd();
783 my $candidate = File::Spec->catfile($pwd,$^X);
784 $perl ||= $candidate if MM->maybe_command($candidate);
787 my ($component,$perl_name);
788 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
789 PATH_COMPONENT: foreach $component (File::Spec->path(),
790 $Config::Config{'binexp'}) {
791 next unless defined($component) && $component;
792 my($abs) = File::Spec->catfile($component,$perl_name);
793 if (MM->maybe_command($abs)) {
805 #-> sub CPAN::exists ;
807 my($mgr,$class,$id) = @_;
808 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
810 ### Carp::croak "exists called without class argument" unless $class;
812 $id =~ s/:+/::/g if $class eq "CPAN::Module";
813 exists $META->{readonly}{$class}{$id} or
814 exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
817 #-> sub CPAN::delete ;
819 my($mgr,$class,$id) = @_;
820 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
821 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
824 #-> sub CPAN::has_usable
825 # has_inst is sometimes too optimistic, we should replace it with this
826 # has_usable whenever a case is given
828 my($self,$mod,$message) = @_;
829 return 1 if $HAS_USABLE->{$mod};
830 my $has_inst = $self->has_inst($mod,$message);
831 return unless $has_inst;
834 LWP => [ # we frequently had "Can't locate object
835 # method "new" via package "LWP::UserAgent" at
836 # (eval 69) line 2006
838 sub {require LWP::UserAgent},
839 sub {require HTTP::Request},
840 sub {require URI::URL},
843 sub {require Net::FTP},
844 sub {require Net::Config},
847 if ($usable->{$mod}) {
848 for my $c (0..$#{$usable->{$mod}}) {
849 my $code = $usable->{$mod}[$c];
850 my $ret = eval { &$code() };
852 warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
857 return $HAS_USABLE->{$mod} = 1;
860 #-> sub CPAN::has_inst
862 my($self,$mod,$message) = @_;
863 Carp::croak("CPAN->has_inst() called without an argument")
865 my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
866 keys %{$CPAN::Config->{dontload_hash}||{}},
867 @{$CPAN::Config->{dontload_list}||[]};
868 if (defined $message && $message eq "no" # afair only used by Nox
872 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
880 # checking %INC is wrong, because $INC{LWP} may be true
881 # although $INC{"URI/URL.pm"} may have failed. But as
882 # I really want to say "bla loaded OK", I have to somehow
884 ### warn "$file in %INC"; #debug
886 } elsif (eval { require $file }) {
887 # eval is good: if we haven't yet read the database it's
888 # perfect and if we have installed the module in the meantime,
889 # it tries again. The second require is only a NOOP returning
890 # 1 if we had success, otherwise it's retrying
892 $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
893 if ($mod eq "CPAN::WAIT") {
894 push @CPAN::Shell::ISA, 'CPAN::WAIT';
897 } elsif ($mod eq "Net::FTP") {
898 $CPAN::Frontend->mywarn(qq{
899 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
901 install Bundle::libnet
903 }) unless $Have_warned->{"Net::FTP"}++;
905 } elsif ($mod eq "Digest::SHA"){
906 if ($Have_warned->{"Digest::SHA"}++) {
907 $CPAN::Frontend->myprint(qq{CPAN: checksum security checks disabled}.
908 qq{because Digest::SHA not installed.\n});
910 $CPAN::Frontend->myprint(qq{
911 CPAN: checksum security checks disabled because Digest::SHA not installed.
912 Please consider installing the Digest::SHA module.
917 } elsif ($mod eq "Module::Signature"){
918 unless ($Have_warned->{"Module::Signature"}++) {
919 # No point in complaining unless the user can
920 # reasonably install and use it.
921 if (eval { require Crypt::OpenPGP; 1 } ||
922 defined $CPAN::Config->{'gpg'}) {
923 $CPAN::Frontend->myprint(qq{
924 CPAN: Module::Signature security checks disabled because Module::Signature
925 not installed. Please consider installing the Module::Signature module.
926 You may also need to be able to connect over the Internet to the public
927 keyservers like pgp.mit.edu (port 11371).
934 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
939 #-> sub CPAN::instance ;
941 my($mgr,$class,$id) = @_;
944 # unsafe meta access, ok?
945 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
946 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
954 #-> sub CPAN::cleanup ;
956 # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
957 local $SIG{__DIE__} = '';
962 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
964 $subroutine eq '(eval)';
966 return if $ineval && !$CPAN::End;
967 return unless defined $META->{LOCK};
968 return unless -f $META->{LOCK};
970 unlink $META->{LOCK};
972 # Carp::cluck("DEBUGGING");
973 $CPAN::Frontend->mywarn("Lockfile removed.\n");
976 #-> sub CPAN::savehist
979 my($histfile,$histsize);
980 unless ($histfile = $CPAN::Config->{'histfile'}){
981 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
984 $histsize = $CPAN::Config->{'histsize'} || 100;
986 unless ($CPAN::term->can("GetHistory")) {
987 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
993 my @h = $CPAN::term->GetHistory;
994 splice @h, 0, @h-$histsize if @h>$histsize;
995 my($fh) = FileHandle->new;
996 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
997 local $\ = local $, = "\n";
1003 my($self,$what) = @_;
1004 $self->{is_tested}{$what} = 1;
1008 my($self,$what) = @_;
1009 delete $self->{is_tested}{$what};
1014 $self->{is_tested} ||= {};
1015 return unless %{$self->{is_tested}};
1016 my $env = $ENV{PERL5LIB};
1017 $env = $ENV{PERLLIB} unless defined $env;
1019 push @env, $env if defined $env and length $env;
1020 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
1021 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
1022 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
1025 package CPAN::CacheMgr;
1028 #-> sub CPAN::CacheMgr::as_string ;
1030 eval { require Data::Dumper };
1032 return shift->SUPER::as_string;
1034 return Data::Dumper::Dumper(shift);
1038 #-> sub CPAN::CacheMgr::cachesize ;
1043 #-> sub CPAN::CacheMgr::tidyup ;
1046 return unless -d $self->{ID};
1047 while ($self->{DU} > $self->{'MAX'} ) {
1048 my($toremove) = shift @{$self->{FIFO}};
1049 $CPAN::Frontend->myprint(sprintf(
1050 "Deleting from cache".
1051 ": $toremove (%.1f>%.1f MB)\n",
1052 $self->{DU}, $self->{'MAX'})
1054 return if $CPAN::Signal;
1055 $self->force_clean_cache($toremove);
1056 return if $CPAN::Signal;
1060 #-> sub CPAN::CacheMgr::dir ;
1065 #-> sub CPAN::CacheMgr::entries ;
1067 my($self,$dir) = @_;
1068 return unless defined $dir;
1069 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
1070 $dir ||= $self->{ID};
1071 my($cwd) = CPAN::anycwd();
1072 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
1073 my $dh = DirHandle->new(File::Spec->curdir)
1074 or Carp::croak("Couldn't opendir $dir: $!");
1077 next if $_ eq "." || $_ eq "..";
1079 push @entries, File::Spec->catfile($dir,$_);
1081 push @entries, File::Spec->catdir($dir,$_);
1083 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
1086 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
1087 sort { -M $b <=> -M $a} @entries;
1090 #-> sub CPAN::CacheMgr::disk_usage ;
1092 my($self,$dir) = @_;
1093 return if exists $self->{SIZE}{$dir};
1094 return if $CPAN::Signal;
1098 unless (chmod 0755, $dir) {
1099 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
1100 "permission to change the permission; cannot ".
1101 "estimate disk usage of '$dir'\n");
1102 $CPAN::Frontend->mysleep(5);
1107 $CPAN::Frontend->mywarn("Directory '$dir' has gone. Cannot continue.\n");
1108 $CPAN::Frontend->mysleep(2);
1113 $File::Find::prune++ if $CPAN::Signal;
1115 if ($^O eq 'MacOS') {
1117 my $cat = Mac::Files::FSpGetCatInfo($_);
1118 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
1122 unless (chmod 0755, $_) {
1123 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
1124 "the permission to change the permission; ".
1125 "can only partially estimate disk usage ".
1138 return if $CPAN::Signal;
1139 $self->{SIZE}{$dir} = $Du/1024/1024;
1140 push @{$self->{FIFO}}, $dir;
1141 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
1142 $self->{DU} += $Du/1024/1024;
1146 #-> sub CPAN::CacheMgr::force_clean_cache ;
1147 sub force_clean_cache {
1148 my($self,$dir) = @_;
1149 return unless -e $dir;
1150 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
1152 File::Path::rmtree($dir);
1153 $self->{DU} -= $self->{SIZE}{$dir};
1154 delete $self->{SIZE}{$dir};
1157 #-> sub CPAN::CacheMgr::new ;
1164 ID => $CPAN::Config->{'build_dir'},
1165 MAX => $CPAN::Config->{'build_cache'},
1166 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
1169 File::Path::mkpath($self->{ID});
1170 my $dh = DirHandle->new($self->{ID});
1171 bless $self, $class;
1174 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
1176 CPAN->debug($debug) if $CPAN::DEBUG;
1180 #-> sub CPAN::CacheMgr::scan_cache ;
1183 return if $self->{SCAN} eq 'never';
1184 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1185 unless $self->{SCAN} eq 'atstart';
1186 $CPAN::Frontend->myprint(
1187 sprintf("Scanning cache %s for sizes\n",
1190 for $e ($self->entries($self->{ID})) {
1191 next if $e eq ".." || $e eq ".";
1192 $self->disk_usage($e);
1193 return if $CPAN::Signal;
1198 package CPAN::Shell;
1201 #-> sub CPAN::Shell::h ;
1203 my($class,$about) = @_;
1204 if (defined $about) {
1205 $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
1207 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
1208 $CPAN::Frontend->myprint(qq{
1209 Display Information $filler (ver $CPAN::VERSION)
1210 command argument description
1211 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1212 i WORD or /REGEXP/ about any of the above
1213 r NONE report updatable modules
1214 ls AUTHOR or GLOB about files in the author's directory
1215 (with WORD being a module, bundle or author name or a distribution
1216 name of the form AUTHOR/DISTRIBUTION)
1218 Download, Test, Make, Install...
1219 get download clean make clean
1220 make make (implies get) look open subshell in dist directory
1221 test make test (implies make) readme display these README files
1222 install make install (implies test) perldoc display POD documentation
1225 force COMMAND unconditionally do command
1226 notest COMMAND skip testing
1229 h,? display this menu ! perl-code eval a perl command
1230 o conf [opt] set and query options q quit the cpan shell
1231 reload cpan load CPAN.pm again reload index load newer indices
1232 autobundle Snapshot recent latest CPAN uploads});
1238 #-> sub CPAN::Shell::a ;
1240 my($self,@arg) = @_;
1241 # authors are always UPPERCASE
1243 $_ = uc $_ unless /=/;
1245 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1248 #-> sub CPAN::Shell::globls ;
1250 my($self,$s,$pragmas) = @_;
1251 # ls is really very different, but we had it once as an ordinary
1252 # command in the Shell (upto rev. 321) and we could not handle
1254 my(@accept,@preexpand);
1255 if ($s =~ /[\*\?\/]/) {
1256 if ($CPAN::META->has_inst("Text::Glob")) {
1257 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
1258 my $rau = Text::Glob::glob_to_regex(uc $au);
1259 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
1261 push @preexpand, map { $_->id . "/" . $pathglob }
1262 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
1264 my $rau = Text::Glob::glob_to_regex(uc $s);
1265 push @preexpand, map { $_->id }
1266 CPAN::Shell->expand_by_method('CPAN::Author',
1271 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
1274 push @preexpand, uc $s;
1277 unless (/^[A-Z0-9\-]+(\/|$)/i) {
1278 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1283 my $silent = @accept>1;
1284 my $last_alpha = "";
1286 for my $a (@accept){
1287 my($author,$pathglob);
1288 if ($a =~ m|(.*?)/(.*)|) {
1291 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1293 $a2) or die "No author found for $a2";
1295 $author = CPAN::Shell->expand_by_method('CPAN::Author',
1297 $a) or die "No author found for $a";
1300 my $alpha = substr $author->id, 0, 1;
1302 if ($alpha eq $last_alpha) {
1306 $last_alpha = $alpha;
1308 $CPAN::Frontend->myprint($ad);
1310 for my $pragma (@$pragmas) {
1311 if ($author->can($pragma)) {
1315 push @results, $author->ls($pathglob,$silent); # silent if
1318 for my $pragma (@$pragmas) {
1319 my $meth = "un$pragma";
1320 if ($author->can($meth)) {
1328 #-> sub CPAN::Shell::local_bundles ;
1330 my($self,@which) = @_;
1331 my($incdir,$bdir,$dh);
1332 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1333 my @bbase = "Bundle";
1334 while (my $bbase = shift @bbase) {
1335 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1336 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1337 if ($dh = DirHandle->new($bdir)) { # may fail
1339 for $entry ($dh->read) {
1340 next if $entry =~ /^\./;
1341 if (-d File::Spec->catdir($bdir,$entry)){
1342 push @bbase, "$bbase\::$entry";
1344 next unless $entry =~ s/\.pm(?!\n)\Z//;
1345 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1353 #-> sub CPAN::Shell::b ;
1355 my($self,@which) = @_;
1356 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1357 $self->local_bundles;
1358 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1361 #-> sub CPAN::Shell::d ;
1362 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1364 #-> sub CPAN::Shell::m ;
1365 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1367 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1370 #-> sub CPAN::Shell::i ;
1374 @args = '/./' unless @args;
1376 for my $type (qw/Bundle Distribution Module/) {
1377 push @result, $self->expand($type,@args);
1379 # Authors are always uppercase.
1380 push @result, $self->expand("Author", map { uc $_ } @args);
1382 my $result = @result == 1 ?
1383 $result[0]->as_string :
1385 "No objects found of any type for argument @args\n" :
1387 (map {$_->as_glimpse} @result),
1388 scalar @result, " items found\n",
1390 $CPAN::Frontend->myprint($result);
1393 #-> sub CPAN::Shell::o ;
1395 # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf'
1396 # should have been called set and 'o debug' maybe 'set debug'
1398 my($self,$o_type,@o_what) = @_;
1401 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1402 if ($o_type eq 'conf') {
1403 if (!@o_what) { # print all things, "o conf"
1405 $CPAN::Frontend->myprint("CPAN::Config options");
1406 if (exists $INC{'CPAN/Config.pm'}) {
1407 $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1409 if (exists $INC{'CPAN/MyConfig.pm'}) {
1410 $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1412 $CPAN::Frontend->myprint(":\n");
1413 for $k (sort keys %CPAN::HandleConfig::can) {
1414 $v = $CPAN::HandleConfig::can{$k};
1415 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
1417 $CPAN::Frontend->myprint("\n");
1418 for $k (sort keys %$CPAN::Config) {
1419 CPAN::HandleConfig->prettyprint($k);
1421 $CPAN::Frontend->myprint("\n");
1422 } elsif (!CPAN::HandleConfig->edit(@o_what)) {
1423 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
1426 } elsif ($o_type eq 'debug') {
1428 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1431 my($what) = shift @o_what;
1432 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
1433 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
1436 if ( exists $CPAN::DEBUG{$what} ) {
1437 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1438 } elsif ($what =~ /^\d/) {
1439 $CPAN::DEBUG = $what;
1440 } elsif (lc $what eq 'all') {
1442 for (values %CPAN::DEBUG) {
1445 $CPAN::DEBUG = $max;
1448 for (keys %CPAN::DEBUG) {
1449 next unless lc($_) eq lc($what);
1450 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
1453 $CPAN::Frontend->myprint("unknown argument [$what]\n")
1458 my $raw = "Valid options for debug are ".
1459 join(", ",sort(keys %CPAN::DEBUG), 'all').
1460 qq{ or a number. Completion works on the options. }.
1461 qq{Case is ignored.};
1463 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
1464 $CPAN::Frontend->myprint("\n\n");
1467 $CPAN::Frontend->myprint("Options set for debugging:\n");
1469 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1470 $v = $CPAN::DEBUG{$k};
1471 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
1472 if $v & $CPAN::DEBUG;
1475 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
1478 $CPAN::Frontend->myprint(qq{
1480 conf set or get configuration variables
1481 debug set or get debugging options
1486 sub paintdots_onreload {
1489 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
1493 # $CPAN::Frontend->myprint(".($subr)");
1494 $CPAN::Frontend->myprint(".");
1501 #-> sub CPAN::Shell::reload ;
1503 my($self,$command,@arg) = @_;
1505 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1506 if ($command =~ /cpan/i) {
1508 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
1510 MFILE: for my $f (qw(CPAN.pm CPAN/HandleConfig.pm CPAN/FirstTime.pm CPAN/Tarzip.pm
1511 CPAN/Debug.pm CPAN/Version.pm)) {
1512 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
1513 $self->reload_this($f) or $failed++;
1515 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
1516 $failed++ unless $redef;
1518 $CPAN::Frontend->mywarn("\n$failed errors during reload. You better quit ".
1521 } elsif ($command =~ /index/) {
1522 CPAN::Index->force_reload;
1524 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
1525 index re-reads the index files\n});
1531 return 1 unless $INC{$f};
1532 my $pwd = CPAN::anycwd();
1533 CPAN->debug("reloading the whole '$f' from '$INC{$f}' while pwd='$pwd'")
1536 for my $inc (@INC) {
1537 $read = File::Spec->catfile($inc,split /\//, $f);
1544 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
1547 my $fh = FileHandle->new($read) or
1548 $CPAN::Frontend->mydie("Could not open $read: $!");
1552 CPAN->debug(sprintf("evaling [%s...]\n",substr($eval,0,64)))
1562 #-> sub CPAN::Shell::mkmyconfig ;
1564 my($self, $cpanpm, %args) = @_;
1565 require CPAN::FirstTime;
1566 $cpanpm = $INC{'CPAN/MyConfig.pm'} || "$ENV{HOME}/.cpan/CPAN/MyConfig.pm";
1567 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
1568 if(!$INC{'CPAN/Config.pm'}) {
1569 eval { require CPAN::Config; };
1571 $CPAN::Config ||= {};
1576 keep_source_where => undef,
1579 CPAN::FirstTime::init($cpanpm, %args);
1582 #-> sub CPAN::Shell::_binary_extensions ;
1583 sub _binary_extensions {
1584 my($self) = shift @_;
1585 my(@result,$module,%seen,%need,$headerdone);
1586 for $module ($self->expand('Module','/./')) {
1587 my $file = $module->cpan_file;
1588 next if $file eq "N/A";
1589 next if $file =~ /^Contact Author/;
1590 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
1591 next if $dist->isa_perl;
1592 next unless $module->xs_file;
1594 $CPAN::Frontend->myprint(".");
1595 push @result, $module;
1597 # print join " | ", @result;
1598 $CPAN::Frontend->myprint("\n");
1602 #-> sub CPAN::Shell::recompile ;
1604 my($self) = shift @_;
1605 my($module,@module,$cpan_file,%dist);
1606 @module = $self->_binary_extensions();
1607 for $module (@module){ # we force now and compile later, so we
1609 $cpan_file = $module->cpan_file;
1610 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1612 $dist{$cpan_file}++;
1614 for $cpan_file (sort keys %dist) {
1615 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
1616 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1618 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1619 # stop a package from recompiling,
1620 # e.g. IO-1.12 when we have perl5.003_10
1624 #-> sub CPAN::Shell::_u_r_common ;
1626 my($self) = shift @_;
1627 my($what) = shift @_;
1628 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1629 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
1630 $what && $what =~ /^[aru]$/;
1632 @args = '/./' unless @args;
1633 my(@result,$module,%seen,%need,$headerdone,
1634 $version_undefs,$version_zeroes);
1635 $version_undefs = $version_zeroes = 0;
1636 my $sprintf = "%s%-25s%s %9s %9s %s\n";
1637 my @expand = $self->expand('Module',@args);
1638 my $expand = scalar @expand;
1639 if (0) { # Looks like noise to me, was very useful for debugging
1640 # for metadata cache
1641 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
1643 MODULE: for $module (@expand) {
1644 my $file = $module->cpan_file;
1645 next MODULE unless defined $file; # ??
1646 $file =~ s|^./../||;
1647 my($latest) = $module->cpan_version;
1648 my($inst_file) = $module->inst_file;
1650 return if $CPAN::Signal;
1653 $have = $module->inst_version;
1654 } elsif ($what eq "r") {
1655 $have = $module->inst_version;
1657 if ($have eq "undef"){
1659 } elsif ($have == 0){
1662 next MODULE unless CPAN::Version->vgt($latest, $have);
1663 # to be pedantic we should probably say:
1664 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1665 # to catch the case where CPAN has a version 0 and we have a version undef
1666 } elsif ($what eq "u") {
1672 } elsif ($what eq "r") {
1674 } elsif ($what eq "u") {
1678 return if $CPAN::Signal; # this is sometimes lengthy
1681 push @result, sprintf "%s %s\n", $module->id, $have;
1682 } elsif ($what eq "r") {
1683 push @result, $module->id;
1684 next MODULE if $seen{$file}++;
1685 } elsif ($what eq "u") {
1686 push @result, $module->id;
1687 next MODULE if $seen{$file}++;
1688 next MODULE if $file =~ /^Contact/;
1690 unless ($headerdone++){
1691 $CPAN::Frontend->myprint("\n");
1692 $CPAN::Frontend->myprint(sprintf(
1695 "Package namespace",
1707 $CPAN::META->has_inst("Term::ANSIColor")
1709 $module->description
1711 $color_on = Term::ANSIColor::color("green");
1712 $color_off = Term::ANSIColor::color("reset");
1714 $CPAN::Frontend->myprint(sprintf $sprintf,
1721 $need{$module->id}++;
1725 $CPAN::Frontend->myprint("No modules found for @args\n");
1726 } elsif ($what eq "r") {
1727 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
1731 if ($version_zeroes) {
1732 my $s_has = $version_zeroes > 1 ? "s have" : " has";
1733 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1734 qq{a version number of 0\n});
1736 if ($version_undefs) {
1737 my $s_has = $version_undefs > 1 ? "s have" : " has";
1738 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1739 qq{parseable version number\n});
1745 #-> sub CPAN::Shell::r ;
1747 shift->_u_r_common("r",@_);
1750 #-> sub CPAN::Shell::u ;
1752 shift->_u_r_common("u",@_);
1755 #-> sub CPAN::Shell::failed ;
1757 my($self,$only_id,$silent) = @_;
1759 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
1768 next unless exists $d->{$nosayer};
1770 $d->{$nosayer}->can("failed") ?
1771 $d->{$nosayer}->failed :
1772 $d->{$nosayer} =~ /^NO/
1777 next DIST unless $failed;
1778 next DIST if $only_id && $only_id != (
1779 $d->{$failed}->can("commandid")
1781 $d->{$failed}->commandid
1783 $CPAN::CurrentCommandId
1788 # " %-45s: %s %s\n",
1791 $d->{$failed}->can("failed") ?
1793 $d->{$failed}->commandid,
1796 $d->{$failed}->text,
1806 my $scope = $only_id ? "command" : "session";
1808 my $print = join "",
1809 map { sprintf " %-45s: %s %s\n", @$_[1,2,3] }
1810 sort { $a->[0] <=> $b->[0] } @failed;
1811 $CPAN::Frontend->myprint("Failed during this $scope:\n$print");
1812 } elsif (!$only_id || !$silent) {
1813 $CPAN::Frontend->myprint("Nothing failed in this $scope\n");
1817 # XXX intentionally undocumented because completely bogus, unportable,
1820 #-> sub CPAN::Shell::status ;
1823 require Devel::Size;
1824 my $ps = FileHandle->new;
1825 open $ps, "/proc/$$/status";
1828 next unless /VmSize:\s+(\d+)/;
1832 $CPAN::Frontend->mywarn(sprintf(
1833 "%-27s %6d\n%-27s %6d\n",
1837 Devel::Size::total_size($CPAN::META)/1024,
1839 for my $k (sort keys %$CPAN::META) {
1840 next unless substr($k,0,4) eq "read";
1841 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
1842 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
1843 warn sprintf " %-25s %6d %6d\n",
1845 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
1846 scalar keys %{$CPAN::META->{$k}{$k2}};
1851 #-> sub CPAN::Shell::autobundle ;
1854 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1855 my(@bundle) = $self->_u_r_common("a",@_);
1856 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1857 File::Path::mkpath($todir);
1858 unless (-d $todir) {
1859 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1862 my($y,$m,$d) = (localtime)[5,4,3];
1866 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1867 my($to) = File::Spec->catfile($todir,"$me.pm");
1869 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1870 $to = File::Spec->catfile($todir,"$me.pm");
1872 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1874 "package Bundle::$me;\n\n",
1875 "\$VERSION = '0.01';\n\n",
1879 "Bundle::$me - Snapshot of installation on ",
1880 $Config::Config{'myhostname'},
1883 "\n\n=head1 SYNOPSIS\n\n",
1884 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1885 "=head1 CONTENTS\n\n",
1886 join("\n", @bundle),
1887 "\n\n=head1 CONFIGURATION\n\n",
1889 "\n\n=head1 AUTHOR\n\n",
1890 "This Bundle has been generated automatically ",
1891 "by the autobundle routine in CPAN.pm.\n",
1894 $CPAN::Frontend->myprint("\nWrote bundle file
1898 #-> sub CPAN::Shell::expandany ;
1901 CPAN->debug("s[$s]") if $CPAN::DEBUG;
1902 if ($s =~ m|/|) { # looks like a file
1903 $s = CPAN::Distribution->normalize($s);
1904 return $CPAN::META->instance('CPAN::Distribution',$s);
1905 # Distributions spring into existence, not expand
1906 } elsif ($s =~ m|^Bundle::|) {
1907 $self->local_bundles; # scanning so late for bundles seems
1908 # both attractive and crumpy: always
1909 # current state but easy to forget
1911 return $self->expand('Bundle',$s);
1913 return $self->expand('Module',$s)
1914 if $CPAN::META->exists('CPAN::Module',$s);
1919 #-> sub CPAN::Shell::expand ;
1922 my($type,@args) = @_;
1923 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1924 my $class = "CPAN::$type";
1925 my $methods = ['id'];
1926 for my $meth (qw(name)) {
1927 next if $] < 5.00303; # no "can"
1928 next unless $class->can($meth);
1929 push @$methods, $meth;
1931 $self->expand_by_method($class,$methods,@args);
1934 sub expand_by_method {
1936 my($class,$methods,@args) = @_;
1939 my($regex,$command);
1940 if ($arg =~ m|^/(.*)/$|) {
1942 } elsif ($arg =~ m/=/) {
1946 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1948 defined $regex ? $regex : "UNDEFINED",
1949 defined $command ? $command : "UNDEFINED",
1951 if (defined $regex) {
1953 $CPAN::META->all_objects($class)
1956 # BUG, we got an empty object somewhere
1957 require Data::Dumper;
1958 CPAN->debug(sprintf(
1959 "Bug in CPAN: Empty id on obj[%s][%s]",
1961 Data::Dumper::Dumper($obj)
1965 for my $method (@$methods) {
1966 if ($obj->$method() =~ /$regex/i) {
1972 } elsif ($command) {
1973 die "equal sign in command disabled (immature interface), ".
1975 ! \$CPAN::Shell::ADVANCED_QUERY=1
1976 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1977 that may go away anytime.\n"
1978 unless $ADVANCED_QUERY;
1979 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1980 my($matchcrit) = $criterion =~ m/^~(.+)/;
1984 $CPAN::META->all_objects($class)
1986 my $lhs = $self->$method() or next; # () for 5.00503
1988 push @m, $self if $lhs =~ m/$matchcrit/;
1990 push @m, $self if $lhs eq $criterion;
1995 if ( $class eq 'CPAN::Bundle' ) {
1996 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1997 } elsif ($class eq "CPAN::Distribution") {
1998 $xarg = CPAN::Distribution->normalize($arg);
2002 if ($CPAN::META->exists($class,$xarg)) {
2003 $obj = $CPAN::META->instance($class,$xarg);
2004 } elsif ($CPAN::META->exists($class,$arg)) {
2005 $obj = $CPAN::META->instance($class,$arg);
2012 @m = sort {$a->id cmp $b->id} @m;
2013 if ( $CPAN::DEBUG ) {
2014 my $wantarray = wantarray;
2015 my $join_m = join ",", map {$_->id} @m;
2016 $self->debug("wantarray[$wantarray]join_m[$join_m]");
2018 return wantarray ? @m : $m[0];
2021 #-> sub CPAN::Shell::format_result ;
2024 my($type,@args) = @_;
2025 @args = '/./' unless @args;
2026 my(@result) = $self->expand($type,@args);
2027 my $result = @result == 1 ?
2028 $result[0]->as_string :
2030 "No objects of type $type found for argument @args\n" :
2032 (map {$_->as_glimpse} @result),
2033 scalar @result, " items found\n",
2038 #-> sub CPAN::Shell::report_fh ;
2040 my $installation_report_fh;
2041 my $previously_noticed = 0;
2044 return $installation_report_fh if $installation_report_fh;
2045 if ($CPAN::META->has_inst("File::Temp")) {
2046 $installation_report_fh
2048 template => 'cpan_install_XXXX',
2053 unless ( $installation_report_fh ) {
2054 warn("Couldn't open installation report file; " .
2055 "no report file will be generated."
2056 ) unless $previously_noticed++;
2062 # The only reason for this method is currently to have a reliable
2063 # debugging utility that reveals which output is going through which
2064 # channel. No, I don't like the colors ;-)
2066 #-> sub CPAN::Shell::print_ornameted ;
2067 sub print_ornamented {
2068 my($self,$what,$ornament) = @_;
2070 return unless defined $what;
2072 local $| = 1; # Flush immediately
2073 if ( $CPAN::Be_Silent ) {
2074 print {report_fh()} $what;
2078 if ($CPAN::Config->{term_is_latin}){
2081 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
2083 if ($PRINT_ORNAMENTING) {
2084 unless (defined &color) {
2085 if ($CPAN::META->has_inst("Term::ANSIColor")) {
2086 import Term::ANSIColor "color";
2088 *color = sub { return "" };
2092 for $line (split /\n/, $what) {
2093 $longest = length($line) if length($line) > $longest;
2095 my $sprintf = "%-" . $longest . "s";
2097 $what =~ s/(.*\n?)//m;
2100 my($nl) = chomp $line ? "\n" : "";
2101 # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
2102 print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
2106 # $what .= "\n"; # newlines unless $PRINT_ORNAMENTING
2112 my($self,$what) = @_;
2114 $self->print_ornamented($what, 'bold blue on_yellow');
2118 my($self,$what) = @_;
2119 $self->myprint($what);
2124 my($self,$what) = @_;
2125 $self->print_ornamented($what, 'bold red on_yellow');
2129 # my($self,$what) = @_;
2130 # $self->print_ornamented($what, 'bold red on_white');
2131 # Carp::confess "died";
2135 my($self,$what) = @_;
2136 $self->print_ornamented($what, 'bold red on_white');
2140 # use this only for unrecoverable errors!
2141 sub unrecoverable_error {
2142 my($self,$what) = @_;
2143 my @lines = split /\n/, $what;
2145 for my $l (@lines) {
2146 $longest = length $l if length $l > $longest;
2148 $longest = 62 if $longest > 62;
2149 for my $l (@lines) {
2155 if (length $l < 66) {
2156 $l = pack "A66 A*", $l, "<==";
2160 unshift @lines, "\n";
2161 $self->mydie(join "", @lines);
2166 my($self, $sleep) = @_;
2171 return if -t STDOUT;
2172 my $odef = select STDERR;
2179 #-> sub CPAN::Shell::rematein ;
2180 # RE-adme||MA-ke||TE-st||IN-stall
2183 my($meth,@some) = @_;
2185 while($meth =~ /^(force|notest)$/) {
2186 push @pragma, $meth;
2187 $meth = shift @some or
2188 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
2192 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
2194 # Here is the place to set "test_count" on all involved parties to
2195 # 0. We then can pass this counter on to the involved
2196 # distributions and those can refuse to test if test_count > X. In
2197 # the first stab at it we could use a 1 for "X".
2199 # But when do I reset the distributions to start with 0 again?
2200 # Jost suggested to have a random or cycling interaction ID that
2201 # we pass through. But the ID is something that is just left lying
2202 # around in addition to the counter, so I'd prefer to set the
2203 # counter to 0 now, and repeat at the end of the loop. But what
2204 # about dependencies? They appear later and are not reset, they
2205 # enter the queue but not its copy. How do they get a sensible
2208 # construct the queue
2210 STHING: foreach $s (@some) {
2213 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
2215 } elsif ($s =~ m|^/|) { # looks like a regexp
2216 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
2220 } elsif ($meth eq "ls") {
2221 $self->globls($s,\@pragma);
2224 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
2225 $obj = CPAN::Shell->expandany($s);
2228 $obj->color_cmd_tmps(0,1);
2229 CPAN::Queue->new($obj->id);
2231 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
2232 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
2233 if ($meth =~ /^(dump|ls)$/) {
2236 $CPAN::Frontend->myprint(
2238 "Don't be silly, you can't $meth ",
2246 ->myprint(qq{Warning: Cannot $meth $s, }.
2247 qq{don\'t know what it is.
2252 to find objects with matching identifiers.
2258 # queuerunner (please be warned: when I started to change the
2259 # queue to hold objects instead of names, I made one or two
2260 # mistakes and never found which. I reverted back instead)
2261 while ($s = CPAN::Queue->first) {
2264 $obj = $s; # I do not believe, we would survive if this happened
2266 $obj = CPAN::Shell->expandany($s);
2268 for my $pragma (@pragma) {
2271 ($] < 5.00303 || $obj->can($pragma))){
2272 ### compatibility with 5.003
2273 $obj->$pragma($meth); # the pragma "force" in
2274 # "CPAN::Distribution" must know
2275 # what we are intending
2278 if ($]>=5.00303 && $obj->can('called_for')) {
2279 $obj->called_for($s);
2282 qq{pragma[@pragma]meth[$meth]obj[$obj]as_string\[}.
2288 CPAN::Queue->delete($s);
2290 CPAN->debug("failed");
2294 CPAN::Queue->delete_first($s);
2296 for my $obj (@qcopy) {
2297 $obj->color_cmd_tmps(0,0);
2298 delete $obj->{incommandcolor};
2302 #-> sub CPAN::Shell::recent ;
2306 CPAN::Distribution::_display_url( $self, $CPAN::Defaultrecent );
2311 # set up the dispatching methods
2313 for my $command (qw(
2328 *$command = sub { shift->rematein($command, @_); };
2332 package CPAN::LWP::UserAgent;
2336 return if $SETUPDONE;
2337 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2338 require LWP::UserAgent;
2339 @ISA = qw(Exporter LWP::UserAgent);
2342 $CPAN::Frontend->mywarn("LWP::UserAgent not available\n");
2346 sub get_basic_credentials {
2347 my($self, $realm, $uri, $proxy) = @_;
2348 return unless $proxy;
2349 if ($USER && $PASSWD) {
2350 } elsif (defined $CPAN::Config->{proxy_user} &&
2351 defined $CPAN::Config->{proxy_pass}) {
2352 $USER = $CPAN::Config->{proxy_user};
2353 $PASSWD = $CPAN::Config->{proxy_pass};
2355 require ExtUtils::MakeMaker;
2356 ExtUtils::MakeMaker->import(qw(prompt));
2357 $USER = prompt("Proxy authentication needed!
2358 (Note: to permanently configure username and password run
2359 o conf proxy_user your_username
2360 o conf proxy_pass your_password
2362 if ($CPAN::META->has_inst("Term::ReadKey")) {
2363 Term::ReadKey::ReadMode("noecho");
2365 $CPAN::Frontend->mywarn("Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n");
2367 $PASSWD = prompt("Password:");
2368 if ($CPAN::META->has_inst("Term::ReadKey")) {
2369 Term::ReadKey::ReadMode("restore");
2371 $CPAN::Frontend->myprint("\n\n");
2373 return($USER,$PASSWD);
2376 # mirror(): Its purpose is to deal with proxy authentication. When we
2377 # call SUPER::mirror, we relly call the mirror method in
2378 # LWP::UserAgent. LWP::UserAgent will then call
2379 # $self->get_basic_credentials or some equivalent and this will be
2380 # $self->dispatched to our own get_basic_credentials method.
2382 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2384 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2385 # although we have gone through our get_basic_credentials, the proxy
2386 # server refuses to connect. This could be a case where the username or
2387 # password has changed in the meantime, so I'm trying once again without
2388 # $USER and $PASSWD to give the get_basic_credentials routine another
2389 # chance to set $USER and $PASSWD.
2391 # mirror(): Its purpose is to deal with proxy authentication. When we
2392 # call SUPER::mirror, we relly call the mirror method in
2393 # LWP::UserAgent. LWP::UserAgent will then call
2394 # $self->get_basic_credentials or some equivalent and this will be
2395 # $self->dispatched to our own get_basic_credentials method.
2397 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2399 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2400 # although we have gone through our get_basic_credentials, the proxy
2401 # server refuses to connect. This could be a case where the username or
2402 # password has changed in the meantime, so I'm trying once again without
2403 # $USER and $PASSWD to give the get_basic_credentials routine another
2404 # chance to set $USER and $PASSWD.
2407 my($self,$url,$aslocal) = @_;
2408 my $result = $self->SUPER::mirror($url,$aslocal);
2409 if ($result->code == 407) {
2412 $result = $self->SUPER::mirror($url,$aslocal);
2420 #-> sub CPAN::FTP::ftp_get ;
2422 my($class,$host,$dir,$file,$target) = @_;
2424 qq[Going to fetch file [$file] from dir [$dir]
2425 on host [$host] as local [$target]\n]
2427 my $ftp = Net::FTP->new($host);
2429 $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
2432 return 0 unless defined $ftp;
2433 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
2434 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
2435 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
2436 my $msg = $ftp->message;
2437 $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
2440 unless ( $ftp->cwd($dir) ){
2441 my $msg = $ftp->message;
2442 $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
2446 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
2447 unless ( $ftp->get($file,$target) ){
2448 my $msg = $ftp->message;
2449 $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
2452 $ftp->quit; # it's ok if this fails
2456 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
2458 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
2459 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
2461 # > *** 1562,1567 ****
2462 # > --- 1562,1580 ----
2463 # > return 1 if substr($url,0,4) eq "file";
2464 # > return 1 unless $url =~ m|://([^/]+)|;
2466 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
2468 # > + $proxy =~ m|://([^/:]+)|;
2470 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
2471 # > + if ($noproxy) {
2472 # > + if ($host !~ /$noproxy$/) {
2473 # > + $host = $proxy;
2476 # > + $host = $proxy;
2479 # > require Net::Ping;
2480 # > return 1 unless $Net::Ping::VERSION >= 2;
2484 #-> sub CPAN::FTP::localize ;
2486 my($self,$file,$aslocal,$force) = @_;
2488 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
2489 unless defined $aslocal;
2490 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
2493 if ($^O eq 'MacOS') {
2494 # Comment by AK on 2000-09-03: Uniq short filenames would be
2495 # available in CHECKSUMS file
2496 my($name, $path) = File::Basename::fileparse($aslocal, '');
2497 if (length($name) > 31) {
2508 my $size = 31 - length($suf);
2509 while (length($name) > $size) {
2513 $aslocal = File::Spec->catfile($path, $name);
2517 if (-f $aslocal && -r _ && !($force & 1)){
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
3586 install Bundle::CPAN
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::set ;
3818 my($self,%att) = @_;
3819 my $class = ref $self;
3821 # This must be ||=, not ||, because only if we write an empty
3822 # reference, only then the set method will write into the readonly
3823 # area. But for Distributions that spring into existence, maybe
3824 # because of a typo, we do not like it that they are written into
3825 # the readonly area and made permanent (at least for a while) and
3826 # that is why we do not "allow" other places to call ->set.
3827 unless ($self->id) {
3828 CPAN->debug("Bug? Empty ID, rejecting");
3831 my $ro = $self->{RO} =
3832 $CPAN::META->{readonly}{$class}{$self->id} ||= {};
3834 while (my($k,$v) = each %att) {
3839 #-> sub CPAN::InfoObj::as_glimpse ;
3843 my $class = ref($self);
3844 $class =~ s/^CPAN:://;
3845 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
3849 #-> sub CPAN::InfoObj::as_string ;
3853 my $class = ref($self);
3854 $class =~ s/^CPAN:://;
3855 push @m, $class, " id = $self->{ID}\n";
3857 unless ($ro = $self->ro) {
3858 $CPAN::Frontend->mydie("Unknown distribution $self->{ID}");
3860 for (sort keys %$ro) {
3861 # next if m/^(ID|RO)$/;
3863 if ($_ eq "CPAN_USERID") {
3865 $extra .= $self->fullname;
3866 my $email; # old perls!
3867 if ($email = $CPAN::META->instance("CPAN::Author",
3870 $extra .= " <$email>";
3872 $extra .= " <no email>";
3875 } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
3876 push @m, sprintf " %-12s %s\n", $_, $self->fullname;
3879 next unless defined $ro->{$_};
3880 push @m, sprintf " %-12s %s%s\n", $_, $ro->{$_}, $extra;
3882 for (sort keys %$self) {
3883 next if m/^(ID|RO)$/;
3884 if (ref($self->{$_}) eq "ARRAY") {
3885 push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
3886 } elsif (ref($self->{$_}) eq "HASH") {
3890 join(" ",sort keys %{$self->{$_}}),
3893 push @m, sprintf " %-12s %s\n", $_, $self->{$_};
3899 #-> sub CPAN::InfoObj::fullname ;
3902 $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
3905 #-> sub CPAN::InfoObj::dump ;
3908 require Data::Dumper;
3909 local $Data::Dumper::Sortkeys;
3910 $Data::Dumper::Sortkeys = 1;
3911 print Data::Dumper::Dumper($self);
3914 package CPAN::Author;
3917 #-> sub CPAN::Author::force
3923 #-> sub CPAN::Author::force
3926 delete $self->{force};
3929 #-> sub CPAN::Author::id
3932 my $id = $self->{ID};
3933 $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
3937 #-> sub CPAN::Author::as_glimpse ;
3941 my $class = ref($self);
3942 $class =~ s/^CPAN:://;
3943 push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
3951 #-> sub CPAN::Author::fullname ;
3953 shift->ro->{FULLNAME};
3957 #-> sub CPAN::Author::email ;
3958 sub email { shift->ro->{EMAIL}; }
3960 #-> sub CPAN::Author::ls ;
3963 my $glob = shift || "";
3964 my $silent = shift || 0;
3967 # adapted from CPAN::Distribution::verifyCHECKSUM ;
3968 my(@csf); # chksumfile
3969 @csf = $self->id =~ /(.)(.)(.*)/;
3970 $csf[1] = join "", @csf[0,1];
3971 $csf[2] = join "", @csf[1,2]; # ("A","AN","ANDK")
3973 @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0, 1);
3974 unless (grep {$_->[2] eq $csf[1]} @dl) {
3975 $CPAN::Frontend->myprint("Directory $csf[1]/ does not exist\n") unless $silent ;
3978 @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0, 1);
3979 unless (grep {$_->[2] eq $csf[2]} @dl) {
3980 $CPAN::Frontend->myprint("Directory $id/ does not exist\n") unless $silent;
3983 @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1, 1);
3985 if ($CPAN::META->has_inst("Text::Glob")) {
3986 my $rglob = Text::Glob::glob_to_regex($glob);
3987 @dl = grep { $_->[2] =~ /$rglob/ } @dl;
3989 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
3992 $CPAN::Frontend->myprint(join "", map {
3993 sprintf("%8d %10s %s/%s\n", $_->[0], $_->[1], $id, $_->[2])
3994 } sort { $a->[2] cmp $b->[2] } @dl);
3998 # returns an array of arrays, the latter contain (size,mtime,filename)
3999 #-> sub CPAN::Author::dir_listing ;
4002 my $chksumfile = shift;
4003 my $recursive = shift;
4004 my $may_ftp = shift;
4006 File::Spec->catfile($CPAN::Config->{keep_source_where},
4007 "authors", "id", @$chksumfile);
4011 # Purge and refetch old (pre-PGP) CHECKSUMS; they are a security
4012 # hazard. (Without GPG installed they are not that much better,
4014 $fh = FileHandle->new;
4015 if (open($fh, $lc_want)) {
4016 my $line = <$fh>; close $fh;
4017 unlink($lc_want) unless $line =~ /PGP/;
4021 # connect "force" argument with "index_expire".
4022 my $force = $self->{force};
4023 if (my @stat = stat $lc_want) {
4024 $force ||= $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
4028 $lc_file = CPAN::FTP->localize(
4029 "authors/id/@$chksumfile",
4034 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
4035 $chksumfile->[-1] .= ".gz";
4036 $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
4039 $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
4040 CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file);
4046 $lc_file = $lc_want;
4047 # we *could* second-guess and if the user has a file: URL,
4048 # then we could look there. But on the other hand, if they do
4049 # have a file: URL, wy did they choose to set
4050 # $CPAN::Config->{show_upload_date} to false?
4053 # adapted from CPAN::Distribution::CHECKSUM_check_file ;
4054 $fh = FileHandle->new;
4056 if (open $fh, $lc_file){
4059 $eval =~ s/\015?\012/\n/g;
4061 my($comp) = Safe->new();
4062 $cksum = $comp->reval($eval);
4064 rename $lc_file, "$lc_file.bad";
4065 Carp::confess($@) if $@;
4067 } elsif ($may_ftp) {
4068 Carp::carp "Could not open $lc_file for reading.";
4070 # Maybe should warn: "You may want to set show_upload_date to a true value"
4074 for $f (sort keys %$cksum) {
4075 if (exists $cksum->{$f}{isdir}) {
4077 my(@dir) = @$chksumfile;
4079 push @dir, $f, "CHECKSUMS";
4081 [$_->[0], $_->[1], "$f/$_->[2]"]
4082 } $self->dir_listing(\@dir,1,$may_ftp);
4084 push @result, [ 0, "-", $f ];
4088 ($cksum->{$f}{"size"}||0),
4089 $cksum->{$f}{"mtime"}||"---",
4097 package CPAN::Distribution;
4103 my $ro = $self->ro or return;
4107 # CPAN::Distribution::undelay
4110 delete $self->{later};
4113 # add the A/AN/ stuff
4114 # CPAN::Distribution::normalize
4117 $s = $self->id unless defined $s;
4121 $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
4123 return $s if $s =~ m:^N/A|^Contact Author: ;
4124 $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4| or
4125 $CPAN::Frontend->mywarn("Strange distribution name [$s]\n");
4126 CPAN->debug("s[$s]") if $CPAN::DEBUG;
4131 #-> sub CPAN::Distribution::author ;
4134 my($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
4135 CPAN::Shell->expand("Author",$authorid);
4138 # tries to get the yaml from CPAN instead of the distro itself:
4139 # EXPERIMENTAL, UNDOCUMENTED AND UNTESTED, for Tels
4142 my $meta = $self->pretty_id;
4143 $meta =~ s/\.(tar.gz|tgz|zip|tar.bz2)/.meta/;
4144 my(@ls) = CPAN::Shell->globls($meta);
4145 my $norm = $self->normalize($meta);
4149 File::Spec->catfile(
4150 $CPAN::Config->{keep_source_where},
4155 $self->debug("Doing localize") if $CPAN::DEBUG;
4156 unless ($local_file =
4157 CPAN::FTP->localize("authors/id/$norm",
4159 $CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n");
4161 if ($CPAN::META->has_inst("YAML")) {
4162 my $yaml = YAML::LoadFile($local_file);
4165 $CPAN::Frontend->mydie("Yaml not installed, cannot parse '$local_file'\n");
4172 return $id unless $id =~ m|^./../|;
4176 # mark as dirty/clean
4177 #-> sub CPAN::Distribution::color_cmd_tmps ;
4178 sub color_cmd_tmps {
4180 my($depth) = shift || 0;
4181 my($color) = shift || 0;
4182 my($ancestors) = shift || [];
4183 # a distribution needs to recurse into its prereq_pms
4185 return if exists $self->{incommandcolor}
4186 && $self->{incommandcolor}==$color;
4188 $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
4190 # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
4191 my $prereq_pm = $self->prereq_pm;
4192 if (defined $prereq_pm) {
4193 PREREQ: for my $pre (keys %$prereq_pm) {
4195 unless ($premo = CPAN::Shell->expand("Module",$pre)) {
4196 $CPAN::Frontend->mywarn("prerequisite module[$pre] not known\n");
4197 $CPAN::Frontend->mysleep(2);
4200 $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
4204 delete $self->{sponsored_mods};
4205 delete $self->{badtestcnt};
4207 $self->{incommandcolor} = $color;
4210 #-> sub CPAN::Distribution::as_string ;
4213 $self->containsmods;
4215 $self->SUPER::as_string(@_);
4218 #-> sub CPAN::Distribution::containsmods ;
4221 return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
4222 my $dist_id = $self->{ID};
4223 for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
4224 my $mod_file = $mod->cpan_file or next;
4225 my $mod_id = $mod->{ID} or next;
4226 # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
4228 $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
4230 keys %{$self->{CONTAINSMODS}};
4233 #-> sub CPAN::Distribution::upload_date ;
4236 return $self->{UPLOAD_DATE} if exists $self->{UPLOAD_DATE};
4237 my(@local_wanted) = split(/\//,$self->id);
4238 my $filename = pop @local_wanted;
4239 push @local_wanted, "CHECKSUMS";
4240 my $author = CPAN::Shell->expand("Author",$self->cpan_userid);
4241 return unless $author;
4242 my @dl = $author->dir_listing(\@local_wanted,0,$CPAN::Config->{show_upload_date});
4244 my($dirent) = grep { $_->[2] eq $filename } @dl;
4245 # warn sprintf "dirent[%s]id[%s]", $dirent, $self->id;
4246 return unless $dirent->[1];
4247 return $self->{UPLOAD_DATE} = $dirent->[1];
4250 #-> sub CPAN::Distribution::uptodate ;
4254 foreach $c ($self->containsmods) {
4255 my $obj = CPAN::Shell->expandany($c);
4256 return 0 unless $obj->uptodate;
4261 #-> sub CPAN::Distribution::called_for ;
4264 $self->{CALLED_FOR} = $id if defined $id;
4265 return $self->{CALLED_FOR};
4268 #-> sub CPAN::Distribution::safe_chdir ;
4270 my($self,$todir) = @_;
4271 # we die if we cannot chdir and we are debuggable
4272 Carp::confess("safe_chdir called without todir argument")
4273 unless defined $todir and length $todir;
4275 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
4279 unless (-x $todir) {
4280 unless (chmod 0755, $todir) {
4281 my $cwd = CPAN::anycwd();
4282 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
4283 "permission to change the permission; cannot ".
4284 "chdir to '$todir'\n");
4285 $CPAN::Frontend->mysleep(5);
4286 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
4287 qq{to todir[$todir]: $!});
4291 $CPAN::Frontend->mydie("Directory '$todir' has gone. Cannot continue.\n");
4294 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
4297 my $cwd = CPAN::anycwd();
4298 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
4299 qq{to todir[$todir] (a chmod has been issued): $!});
4304 #-> sub CPAN::Distribution::get ;
4309 exists $self->{'build_dir'} and push @e,
4310 "Is already unwrapped into directory $self->{'build_dir'}";
4311 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4313 my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
4316 # Get the file on local disk
4321 File::Spec->catfile(
4322 $CPAN::Config->{keep_source_where},
4325 split(/\//,$self->id)
4328 $self->debug("Doing localize") if $CPAN::DEBUG;
4329 unless ($local_file =
4330 CPAN::FTP->localize("authors/id/$self->{ID}",
4333 if ($CPAN::Index::DATE_OF_02) {
4334 $note = "Note: Current database in memory was generated ".
4335 "on $CPAN::Index::DATE_OF_02\n";
4337 $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
4339 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
4340 $self->{localfile} = $local_file;
4341 return if $CPAN::Signal;
4346 if ($CPAN::META->has_inst("Digest::SHA")) {
4347 $self->debug("Digest::SHA is installed, verifying");
4348 $self->verifyCHECKSUM;
4350 $self->debug("Digest::SHA is NOT installed");
4352 return if $CPAN::Signal;
4355 # Create a clean room and go there
4357 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
4358 my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
4359 $self->safe_chdir($builddir);
4360 $self->debug("Removing tmp") if $CPAN::DEBUG;
4361 File::Path::rmtree("tmp");
4362 unless (mkdir "tmp", 0755) {
4363 $CPAN::Frontend->unrecoverable_error(<<EOF);
4364 Couldn't mkdir '$builddir/tmp': $!
4366 Cannot continue: Please find the reason why I cannot make the
4369 and fix the problem, then retry.
4374 $self->safe_chdir($sub_wd);
4377 $self->safe_chdir("tmp");
4382 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
4383 my $ct = CPAN::Tarzip->new($local_file);
4384 if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i){
4385 $self->{was_uncompressed}++ unless $ct->gtest();
4386 $self->untar_me($ct);
4387 } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
4388 $self->unzip_me($ct);
4389 } elsif ( $local_file =~ /\.pm(\.(gz|Z))?(?!\n)\Z/) {
4390 $self->{was_uncompressed}++ unless $ct->gtest();
4391 $self->debug("calling pm2dir for local_file[$local_file]") if $CPAN::DEBUG;
4392 $self->pm2dir_me($local_file);
4394 $self->{archived} = "NO";
4395 $self->safe_chdir($sub_wd);
4399 # we are still in the tmp directory!
4400 # Let's check if the package has its own directory.
4401 my $dh = DirHandle->new(File::Spec->curdir)
4402 or Carp::croak("Couldn't opendir .: $!");
4403 my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
4405 my ($distdir,$packagedir);
4406 if (@readdir == 1 && -d $readdir[0]) {
4407 $distdir = $readdir[0];
4408 $packagedir = File::Spec->catdir($builddir,$distdir);
4409 $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]")
4411 -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
4413 File::Path::rmtree($packagedir);
4414 unless (File::Copy::move($distdir,$packagedir)) {
4415 $CPAN::Frontend->unrecoverable_error(<<EOF);
4416 Couldn't move '$distdir' to '$packagedir': $!
4418 Cannot continue: Please find the reason why I cannot move
4419 $builddir/tmp/$distdir
4422 and fix the problem, then retry
4426 $self->debug(sprintf("moved distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
4433 my $userid = $self->cpan_userid;
4435 CPAN->debug("no userid? self[$self]");
4438 my $pragmatic_dir = $userid . '000';
4439 $pragmatic_dir =~ s/\W_//g;
4440 $pragmatic_dir++ while -d "../$pragmatic_dir";
4441 $packagedir = File::Spec->catdir($builddir,$pragmatic_dir);
4442 $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG;
4443 File::Path::mkpath($packagedir);
4445 for $f (@readdir) { # is already without "." and ".."
4446 my $to = File::Spec->catdir($packagedir,$f);
4447 File::Copy::move($f,$to) or Carp::confess("Couldn't move $f to $to: $!");
4451 $self->safe_chdir($sub_wd);
4455 $self->{'build_dir'} = $packagedir;
4456 $self->safe_chdir($builddir);
4457 File::Path::rmtree("tmp");
4459 $self->safe_chdir($packagedir);
4460 if ($CPAN::META->has_inst("Module::Signature")) {
4461 if (-f "SIGNATURE") {
4462 $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
4463 my $rv = Module::Signature::verify();
4464 if ($rv != Module::Signature::SIGNATURE_OK() and
4465 $rv != Module::Signature::SIGNATURE_MISSING()) {
4466 $CPAN::Frontend->myprint(
4467 qq{\nSignature invalid for }.
4468 qq{distribution file. }.
4469 qq{Please investigate.\n\n}.
4471 $CPAN::META->instance(
4478 sprintf(qq{I'd recommend removing %s. Its signature
4479 is invalid. Maybe you have configured your 'urllist' with
4480 a bad URL. Please check this array with 'o conf urllist', and
4481 retry. For more information, try opening a subshell with
4489 $self->{signature_verify} = CPAN::Distrostatus->new("NO");