1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 $VERSION = eval $VERSION;
5 # $Id: CPAN.pm,v 1.412 2003/07/31 14:53:04 k Exp $
7 # only used during development:
9 # $Revision = "[".substr(q$Revision: 1.412 $, 10)."]";
16 use ExtUtils::MakeMaker (); # $SelfLoader::DEBUG=1;
17 use File::Basename ();
23 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 { $End++; &cleanup; }
55 $CPAN::Frontend ||= "CPAN::Shell";
56 $CPAN::Defaultsite ||= "ftp://ftp.perl.org/pub/CPAN";
61 use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $HAS_USABLE $term
62 $Revision $Signal $End $Suppress_readline $Frontend
63 $Defaultsite $Have_warned);
65 @CPAN::ISA = qw(CPAN::Debug Exporter);
68 autobundle bundle expand force get cvs_import
69 install make readme recompile shell test clean
72 #-> sub CPAN::AUTOLOAD ;
77 @EXPORT{@EXPORT} = '';
78 CPAN::Config->load unless $CPAN::Config_loaded++;
79 if (exists $EXPORT{$l}){
82 $CPAN::Frontend->mywarn(qq{Unknown command "$AUTOLOAD". }.
91 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
92 CPAN::Config->load unless $CPAN::Config_loaded++;
94 my $oprompt = shift || "cpan> ";
95 my $prompt = $oprompt;
96 my $commandline = shift || "";
99 unless ($Suppress_readline) {
100 require Term::ReadLine;
103 $term->ReadLine eq "Term::ReadLine::Stub"
105 $term = Term::ReadLine->new('CPAN Monitor');
107 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
108 my $attribs = $term->Attribs;
109 $attribs->{attempted_completion_function} = sub {
110 &CPAN::Complete::gnu_cpl;
113 $readline::rl_completion_function =
114 $readline::rl_completion_function = 'CPAN::Complete::cpl';
116 if (my $histfile = $CPAN::Config->{'histfile'}) {{
117 unless ($term->can("AddHistory")) {
118 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
121 my($fh) = FileHandle->new;
122 open $fh, "<$histfile" or last;
126 $term->AddHistory($_);
130 # $term->OUT is autoflushed anyway
131 my $odef = select STDERR;
138 # no strict; # I do not recall why no strict was here (2000-09-03)
140 my $cwd = CPAN::anycwd();
141 my $try_detect_readline;
142 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
143 my $rl_avail = $Suppress_readline ? "suppressed" :
144 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
145 "available (try 'install Bundle::CPAN')";
147 $CPAN::Frontend->myprint(
149 cpan shell -- CPAN exploration and modules installation (v%s%s)
157 unless $CPAN::Config->{'inhibit_startup_message'} ;
158 my($continuation) = "";
159 SHELLCOMMAND: while () {
160 if ($Suppress_readline) {
162 last SHELLCOMMAND unless defined ($_ = <> );
165 last SHELLCOMMAND unless
166 defined ($_ = $term->readline($prompt, $commandline));
168 $_ = "$continuation$_" if $continuation;
170 next SHELLCOMMAND if /^$/;
171 $_ = 'h' if /^\s*\?/;
172 if (/^(?:q(?:uit)?|bye|exit)$/i) {
182 use vars qw($import_done);
183 CPAN->import(':DEFAULT') unless $import_done++;
184 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
191 if ($] < 5.00322) { # parsewords had a bug until recently
194 eval { @line = Text::ParseWords::shellwords($_) };
195 warn($@), next SHELLCOMMAND if $@;
196 warn("Text::Parsewords could not parse the line [$_]"),
197 next SHELLCOMMAND unless @line;
199 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
200 my $command = shift @line;
201 eval { CPAN::Shell->$command(@line) };
203 chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
204 $CPAN::Frontend->myprint("\n");
209 $commandline = ""; # I do want to be able to pass a default to
210 # shell, but on the second command I see no
213 CPAN::Queue->nullify_queue;
214 if ($try_detect_readline) {
215 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
217 $CPAN::META->has_inst("Term::ReadLine::Perl")
219 delete $INC{"Term/ReadLine.pm"};
221 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
222 require Term::ReadLine;
223 $CPAN::Frontend->myprint("\n$redef subroutines in ".
224 "Term::ReadLine redefined\n");
230 chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
233 package CPAN::CacheMgr;
234 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
237 package CPAN::Config;
238 use vars qw(%can $dot_cpan);
241 'commit' => "Commit changes to disk",
242 'defaults' => "Reload defaults from disk",
243 'init' => "Interactive setting of all options",
247 use vars qw($Ua $Thesite $Themethod);
248 @CPAN::FTP::ISA = qw(CPAN::Debug);
250 package CPAN::LWP::UserAgent;
251 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
252 # we delay requiring LWP::UserAgent and setting up inheritence until we need it
254 package CPAN::Complete;
255 @CPAN::Complete::ISA = qw(CPAN::Debug);
256 @CPAN::Complete::COMMANDS = sort qw(
257 ! a b d h i m o q r u autobundle clean dump
258 make test install force readme reload look
260 ) unless @CPAN::Complete::COMMANDS;
263 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
264 @CPAN::Index::ISA = qw(CPAN::Debug);
267 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
270 package CPAN::InfoObj;
271 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
273 package CPAN::Author;
274 @CPAN::Author::ISA = qw(CPAN::InfoObj);
276 package CPAN::Distribution;
277 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
279 package CPAN::Bundle;
280 @CPAN::Bundle::ISA = qw(CPAN::Module);
282 package CPAN::Module;
283 @CPAN::Module::ISA = qw(CPAN::InfoObj);
285 package CPAN::Exception::RecursiveDependency;
286 use overload '""' => "as_string";
293 for my $dep (@$deps) {
295 last if $seen{$dep}++;
297 bless { deps => \@deps }, $class;
302 "\nRecursive dependency detected:\n " .
303 join("\n => ", @{$self->{deps}}) .
304 ".\nCannot continue.\n";
308 use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
309 @CPAN::Shell::ISA = qw(CPAN::Debug);
310 $COLOR_REGISTERED ||= 0;
311 $PRINT_ORNAMENTING ||= 0;
313 #-> sub CPAN::Shell::AUTOLOAD ;
315 my($autoload) = $AUTOLOAD;
316 my $class = shift(@_);
317 # warn "autoload[$autoload] class[$class]";
318 $autoload =~ s/.*:://;
319 if ($autoload =~ /^w/) {
320 if ($CPAN::META->has_inst('CPAN::WAIT')) {
321 CPAN::WAIT->$autoload(@_);
323 $CPAN::Frontend->mywarn(qq{
324 Commands starting with "w" require CPAN::WAIT to be installed.
325 Please consider installing CPAN::WAIT to use the fulltext index.
326 For this you just need to type
331 $CPAN::Frontend->mywarn(qq{Unknown command '$autoload'. }.
337 package CPAN::Tarzip;
338 use vars qw($AUTOLOAD @ISA $BUGHUNTING);
339 @CPAN::Tarzip::ISA = qw(CPAN::Debug);
340 $BUGHUNTING = 0; # released code must have turned off
344 # One use of the queue is to determine if we should or shouldn't
345 # announce the availability of a new CPAN module
347 # Now we try to use it for dependency tracking. For that to happen
348 # we need to draw a dependency tree and do the leaves first. This can
349 # easily be reached by running CPAN.pm recursively, but we don't want
350 # to waste memory and run into deep recursion. So what we can do is
353 # CPAN::Queue is the package where the queue is maintained. Dependencies
354 # often have high priority and must be brought to the head of the queue,
355 # possibly by jumping the queue if they are already there. My first code
356 # attempt tried to be extremely correct. Whenever a module needed
357 # immediate treatment, I either unshifted it to the front of the queue,
358 # or, if it was already in the queue, I spliced and let it bypass the
359 # others. This became a too correct model that made it impossible to put
360 # an item more than once into the queue. Why would you need that? Well,
361 # you need temporary duplicates as the manager of the queue is a loop
364 # (1) looks at the first item in the queue without shifting it off
366 # (2) cares for the item
368 # (3) removes the item from the queue, *even if its agenda failed and
369 # even if the item isn't the first in the queue anymore* (that way
370 # protecting against never ending queues)
372 # So if an item has prerequisites, the installation fails now, but we
373 # want to retry later. That's easy if we have it twice in the queue.
375 # I also expect insane dependency situations where an item gets more
376 # than two lives in the queue. Simplest example is triggered by 'install
377 # Foo Foo Foo'. People make this kind of mistakes and I don't want to
378 # get in the way. I wanted the queue manager to be a dumb servant, not
379 # one that knows everything.
381 # Who would I tell in this model that the user wants to be asked before
382 # processing? I can't attach that information to the module object,
383 # because not modules are installed but distributions. So I'd have to
384 # tell the distribution object that it should ask the user before
385 # processing. Where would the question be triggered then? Most probably
386 # in CPAN::Distribution::rematein.
387 # Hope that makes sense, my head is a bit off:-) -- AK
394 my $self = bless { qmod => $s }, $class;
399 # CPAN::Queue::first ;
405 # CPAN::Queue::delete_first ;
407 my($class,$what) = @_;
409 for my $i (0..$#All) {
410 if ( $All[$i]->{qmod} eq $what ) {
417 # CPAN::Queue::jumpqueue ;
421 CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
422 join(",",map {$_->{qmod}} @All),
425 WHAT: for my $what (reverse @what) {
427 for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
428 CPAN->debug("i[$All[$i]]what[$what]") if $CPAN::DEBUG;
429 if ($All[$i]->{qmod} eq $what){
431 if ($jumped > 100) { # one's OK if e.g. just
432 # processing now; more are OK if
433 # user typed it several times
434 $CPAN::Frontend->mywarn(
435 qq{Object [$what] queued more than 100 times, ignoring}
441 my $obj = bless { qmod => $what }, $class;
444 CPAN->debug(sprintf("after jumpqueue All[%s] what[%s]",
445 join(",",map {$_->{qmod}} @All),
450 # CPAN::Queue::exists ;
452 my($self,$what) = @_;
453 my @all = map { $_->{qmod} } @All;
454 my $exists = grep { $_->{qmod} eq $what } @All;
455 # warn "in exists what[$what] all[@all] exists[$exists]";
459 # CPAN::Queue::delete ;
462 @All = grep { $_->{qmod} ne $mod } @All;
465 # CPAN::Queue::nullify_queue ;
474 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
476 # from here on only subs.
477 ################################################################################
479 #-> sub CPAN::all_objects ;
481 my($mgr,$class) = @_;
482 CPAN::Config->load unless $CPAN::Config_loaded++;
483 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
485 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
487 *all = \&all_objects;
489 # Called by shell, not in batch mode. In batch mode I see no risk in
490 # having many processes updating something as installations are
491 # continually checked at runtime. In shell mode I suspect it is
492 # unintentional to open more than one shell at a time
494 #-> sub CPAN::checklock ;
497 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
498 if (-f $lockfile && -M _ > 0) {
499 my $fh = FileHandle->new($lockfile) or
500 $CPAN::Frontend->mydie("Could not open $lockfile: $!");
501 my $otherpid = <$fh>;
502 my $otherhost = <$fh>;
504 if (defined $otherpid && $otherpid) {
507 if (defined $otherhost && $otherhost) {
510 my $thishost = hostname();
511 if (defined $otherhost && defined $thishost &&
512 $otherhost ne '' && $thishost ne '' &&
513 $otherhost ne $thishost) {
514 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
515 "reports other host $otherhost and other process $otherpid.\n".
516 "Cannot proceed.\n"));
518 elsif (defined $otherpid && $otherpid) {
519 return if $$ == $otherpid; # should never happen
520 $CPAN::Frontend->mywarn(
522 There seems to be running another CPAN process (pid $otherpid). Contacting...
524 if (kill 0, $otherpid) {
525 $CPAN::Frontend->mydie(qq{Other job is running.
526 You may want to kill it and delete the lockfile, maybe. On UNIX try:
530 } elsif (-w $lockfile) {
532 ExtUtils::MakeMaker::prompt
533 (qq{Other job not responding. Shall I overwrite }.
534 qq{the lockfile? (Y/N)},"y");
535 $CPAN::Frontend->myexit("Ok, bye\n")
536 unless $ans =~ /^y/i;
539 qq{Lockfile $lockfile not writeable by you. }.
540 qq{Cannot proceed.\n}.
543 qq{ and then rerun us.\n}
547 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
548 "reports other process with ID ".
549 "$otherpid. Cannot proceed.\n"));
552 my $dotcpan = $CPAN::Config->{cpan_home};
553 eval { File::Path::mkpath($dotcpan);};
555 # A special case at least for Jarkko.
560 $symlinkcpan = readlink $dotcpan;
561 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
562 eval { File::Path::mkpath($symlinkcpan); };
566 $CPAN::Frontend->mywarn(qq{
567 Working directory $symlinkcpan created.
571 unless (-d $dotcpan) {
573 Your configuration suggests "$dotcpan" as your
574 CPAN.pm working directory. I could not create this directory due
575 to this error: $firsterror\n};
577 As "$dotcpan" is a symlink to "$symlinkcpan",
578 I tried to create that, but I failed with this error: $seconderror
581 Please make sure the directory exists and is writable.
583 $CPAN::Frontend->mydie($diemess);
587 unless ($fh = FileHandle->new(">$lockfile")) {
588 if ($! =~ /Permission/) {
589 my $incc = $INC{'CPAN/Config.pm'};
590 my $myincc = File::Spec->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
591 $CPAN::Frontend->myprint(qq{
593 Your configuration suggests that CPAN.pm should use a working
595 $CPAN::Config->{cpan_home}
596 Unfortunately we could not create the lock file
598 due to permission problems.
600 Please make sure that the configuration variable
601 \$CPAN::Config->{cpan_home}
602 points to a directory where you can write a .lock file. You can set
603 this variable in either
610 $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
612 $fh->print($$, "\n");
613 $fh->print(hostname(), "\n");
614 $self->{LOCK} = $lockfile;
618 $CPAN::Frontend->mydie("Got SIGTERM, leaving");
623 $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
624 print "Caught SIGINT\n";
628 # From: Larry Wall <larry@wall.org>
629 # Subject: Re: deprecating SIGDIE
630 # To: perl5-porters@perl.org
631 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
633 # The original intent of __DIE__ was only to allow you to substitute one
634 # kind of death for another on an application-wide basis without respect
635 # to whether you were in an eval or not. As a global backstop, it should
636 # not be used any more lightly (or any more heavily :-) than class
637 # UNIVERSAL. Any attempt to build a general exception model on it should
638 # be politely squashed. Any bug that causes every eval {} to have to be
639 # modified should be not so politely squashed.
641 # Those are my current opinions. It is also my optinion that polite
642 # arguments degenerate to personal arguments far too frequently, and that
643 # when they do, it's because both people wanted it to, or at least didn't
644 # sufficiently want it not to.
648 # global backstop to cleanup if we should really die
649 $SIG{__DIE__} = \&cleanup;
650 $self->debug("Signal handler set.") if $CPAN::DEBUG;
653 #-> sub CPAN::DESTROY ;
655 &cleanup; # need an eval?
658 #-> sub CPAN::anycwd ;
661 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
666 sub cwd {Cwd::cwd();}
668 #-> sub CPAN::getcwd ;
669 sub getcwd {Cwd::getcwd();}
671 #-> sub CPAN::exists ;
673 my($mgr,$class,$id) = @_;
674 CPAN::Config->load unless $CPAN::Config_loaded++;
676 ### Carp::croak "exists called without class argument" unless $class;
678 exists $META->{readonly}{$class}{$id} or
679 exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
682 #-> sub CPAN::delete ;
684 my($mgr,$class,$id) = @_;
685 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
686 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
689 #-> sub CPAN::has_usable
690 # has_inst is sometimes too optimistic, we should replace it with this
691 # has_usable whenever a case is given
693 my($self,$mod,$message) = @_;
694 return 1 if $HAS_USABLE->{$mod};
695 my $has_inst = $self->has_inst($mod,$message);
696 return unless $has_inst;
699 LWP => [ # we frequently had "Can't locate object
700 # method "new" via package "LWP::UserAgent" at
701 # (eval 69) line 2006
703 sub {require LWP::UserAgent},
704 sub {require HTTP::Request},
705 sub {require URI::URL},
708 sub {require Net::FTP},
709 sub {require Net::Config},
712 if ($usable->{$mod}) {
713 for my $c (0..$#{$usable->{$mod}}) {
714 my $code = $usable->{$mod}[$c];
715 my $ret = eval { &$code() };
717 warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
722 return $HAS_USABLE->{$mod} = 1;
725 #-> sub CPAN::has_inst
727 my($self,$mod,$message) = @_;
728 Carp::croak("CPAN->has_inst() called without an argument")
730 if (defined $message && $message eq "no"
732 exists $CPAN::META->{dontload_hash}{$mod} # unsafe meta access, ok
734 exists $CPAN::Config->{dontload_hash}{$mod}
736 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
742 $file =~ s|/|\\|g if $^O eq 'MSWin32';
745 # checking %INC is wrong, because $INC{LWP} may be true
746 # although $INC{"URI/URL.pm"} may have failed. But as
747 # I really want to say "bla loaded OK", I have to somehow
749 ### warn "$file in %INC"; #debug
751 } elsif (eval { require $file }) {
752 # eval is good: if we haven't yet read the database it's
753 # perfect and if we have installed the module in the meantime,
754 # it tries again. The second require is only a NOOP returning
755 # 1 if we had success, otherwise it's retrying
757 $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
758 if ($mod eq "CPAN::WAIT") {
759 push @CPAN::Shell::ISA, CPAN::WAIT;
762 } elsif ($mod eq "Net::FTP") {
763 $CPAN::Frontend->mywarn(qq{
764 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
766 install Bundle::libnet
768 }) unless $Have_warned->{"Net::FTP"}++;
770 } elsif ($mod eq "Digest::MD5"){
771 $CPAN::Frontend->myprint(qq{
772 CPAN: MD5 security checks disabled because Digest::MD5 not installed.
773 Please consider installing the Digest::MD5 module.
778 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
783 #-> sub CPAN::instance ;
785 my($mgr,$class,$id) = @_;
788 # unsafe meta access, ok?
789 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
790 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
798 #-> sub CPAN::cleanup ;
800 # warn "cleanup called with arg[@_] End[$End] Signal[$Signal]";
801 local $SIG{__DIE__} = '';
806 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
808 $subroutine eq '(eval)';
810 return if $ineval && !$End;
811 return unless defined $META->{LOCK};
812 return unless -f $META->{LOCK};
814 unlink $META->{LOCK};
816 # Carp::cluck("DEBUGGING");
817 $CPAN::Frontend->mywarn("Lockfile removed.\n");
820 #-> sub CPAN::savehist
823 my($histfile,$histsize);
824 unless ($histfile = $CPAN::Config->{'histfile'}){
825 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
828 $histsize = $CPAN::Config->{'histsize'} || 100;
830 unless ($CPAN::term->can("GetHistory")) {
831 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
837 my @h = $CPAN::term->GetHistory;
838 splice @h, 0, @h-$histsize if @h>$histsize;
839 my($fh) = FileHandle->new;
840 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
841 local $\ = local $, = "\n";
847 my($self,$what) = @_;
848 $self->{is_tested}{$what} = 1;
852 my($self,$what) = @_;
853 delete $self->{is_tested}{$what};
858 $self->{is_tested} ||= {};
859 return unless %{$self->{is_tested}};
860 my $env = $ENV{PERL5LIB};
861 $env = $ENV{PERLLIB} unless defined $env;
863 push @env, $env if defined $env and length $env;
864 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
865 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
866 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
869 package CPAN::CacheMgr;
871 #-> sub CPAN::CacheMgr::as_string ;
873 eval { require Data::Dumper };
875 return shift->SUPER::as_string;
877 return Data::Dumper::Dumper(shift);
881 #-> sub CPAN::CacheMgr::cachesize ;
886 #-> sub CPAN::CacheMgr::tidyup ;
889 return unless -d $self->{ID};
890 while ($self->{DU} > $self->{'MAX'} ) {
891 my($toremove) = shift @{$self->{FIFO}};
892 $CPAN::Frontend->myprint(sprintf(
893 "Deleting from cache".
894 ": $toremove (%.1f>%.1f MB)\n",
895 $self->{DU}, $self->{'MAX'})
897 return if $CPAN::Signal;
898 $self->force_clean_cache($toremove);
899 return if $CPAN::Signal;
903 #-> sub CPAN::CacheMgr::dir ;
908 #-> sub CPAN::CacheMgr::entries ;
911 return unless defined $dir;
912 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
913 $dir ||= $self->{ID};
914 my($cwd) = CPAN::anycwd();
915 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
916 my $dh = DirHandle->new(File::Spec->curdir)
917 or Carp::croak("Couldn't opendir $dir: $!");
920 next if $_ eq "." || $_ eq "..";
922 push @entries, File::Spec->catfile($dir,$_);
924 push @entries, File::Spec->catdir($dir,$_);
926 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
929 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
930 sort { -M $b <=> -M $a} @entries;
933 #-> sub CPAN::CacheMgr::disk_usage ;
936 return if exists $self->{SIZE}{$dir};
937 return if $CPAN::Signal;
941 $File::Find::prune++ if $CPAN::Signal;
943 if ($^O eq 'MacOS') {
945 my $cat = Mac::Files::FSpGetCatInfo($_);
946 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
953 return if $CPAN::Signal;
954 $self->{SIZE}{$dir} = $Du/1024/1024;
955 push @{$self->{FIFO}}, $dir;
956 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
957 $self->{DU} += $Du/1024/1024;
961 #-> sub CPAN::CacheMgr::force_clean_cache ;
962 sub force_clean_cache {
964 return unless -e $dir;
965 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
967 File::Path::rmtree($dir);
968 $self->{DU} -= $self->{SIZE}{$dir};
969 delete $self->{SIZE}{$dir};
972 #-> sub CPAN::CacheMgr::new ;
979 ID => $CPAN::Config->{'build_dir'},
980 MAX => $CPAN::Config->{'build_cache'},
981 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
984 File::Path::mkpath($self->{ID});
985 my $dh = DirHandle->new($self->{ID});
989 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
991 CPAN->debug($debug) if $CPAN::DEBUG;
995 #-> sub CPAN::CacheMgr::scan_cache ;
998 return if $self->{SCAN} eq 'never';
999 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1000 unless $self->{SCAN} eq 'atstart';
1001 $CPAN::Frontend->myprint(
1002 sprintf("Scanning cache %s for sizes\n",
1005 for $e ($self->entries($self->{ID})) {
1006 next if $e eq ".." || $e eq ".";
1007 $self->disk_usage($e);
1008 return if $CPAN::Signal;
1013 package CPAN::Debug;
1015 #-> sub CPAN::Debug::debug ;
1017 my($self,$arg) = @_;
1018 my($caller,$func,$line,@rest) = caller(1); # caller(0) eg
1019 # Complete, caller(1)
1021 ($caller) = caller(0);
1022 $caller =~ s/.*:://;
1023 $arg = "" unless defined $arg;
1024 my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest;
1025 if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){
1026 if ($arg and ref $arg) {
1027 eval { require Data::Dumper };
1029 $CPAN::Frontend->myprint($arg->as_string);
1031 $CPAN::Frontend->myprint(Data::Dumper::Dumper($arg));
1034 $CPAN::Frontend->myprint("Debug($caller:$func,$line,[$rest]): $arg\n");
1039 package CPAN::Config;
1041 #-> sub CPAN::Config::edit ;
1042 # returns true on successful action
1044 my($self,@args) = @_;
1045 return unless @args;
1046 CPAN->debug("self[$self]args[".join(" | ",@args)."]");
1047 my($o,$str,$func,$args,$key_exists);
1053 CPAN->debug("o[$o]") if $CPAN::DEBUG;
1054 if ($o =~ /list$/) {
1055 $func = shift @args;
1057 CPAN->debug("func[$func]") if $CPAN::DEBUG;
1059 # Let's avoid eval, it's easier to comprehend without.
1060 if ($func eq "push") {
1061 push @{$CPAN::Config->{$o}}, @args;
1063 } elsif ($func eq "pop") {
1064 pop @{$CPAN::Config->{$o}};
1066 } elsif ($func eq "shift") {
1067 shift @{$CPAN::Config->{$o}};
1069 } elsif ($func eq "unshift") {
1070 unshift @{$CPAN::Config->{$o}}, @args;
1072 } elsif ($func eq "splice") {
1073 splice @{$CPAN::Config->{$o}}, @args;
1076 $CPAN::Config->{$o} = [@args];
1079 $self->prettyprint($o);
1081 if ($o eq "urllist" && $changed) {
1082 # reset the cached values
1083 undef $CPAN::FTP::Thesite;
1084 undef $CPAN::FTP::Themethod;
1088 $CPAN::Config->{$o} = $args[0] if defined $args[0];
1089 $self->prettyprint($o);
1096 my $v = $CPAN::Config->{$k};
1098 my(@report) = ref $v eq "ARRAY" ?
1100 map { sprintf(" %-18s => %s\n",
1102 defined $v->{$_} ? $v->{$_} : "UNDEFINED"
1104 $CPAN::Frontend->myprint(
1111 map {"\t$_\n"} @report
1114 } elsif (defined $v) {
1115 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1117 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, "UNDEFINED");
1121 #-> sub CPAN::Config::commit ;
1123 my($self,$configpm) = @_;
1124 unless (defined $configpm){
1125 $configpm ||= $INC{"CPAN/MyConfig.pm"};
1126 $configpm ||= $INC{"CPAN/Config.pm"};
1127 $configpm || Carp::confess(q{
1128 CPAN::Config::commit called without an argument.
1129 Please specify a filename where to save the configuration or try
1130 "o conf init" to have an interactive course through configing.
1135 $mode = (stat $configpm)[2];
1136 if ($mode && ! -w _) {
1137 Carp::confess("$configpm is not writable");
1142 $msg = <<EOF unless $configpm =~ /MyConfig/;
1144 # This is CPAN.pm's systemwide configuration file. This file provides
1145 # defaults for users, and the values can be changed in a per-user
1146 # configuration file. The user-config file is being looked for as
1147 # ~/.cpan/CPAN/MyConfig.pm.
1151 my($fh) = FileHandle->new;
1152 rename $configpm, "$configpm~" if -f $configpm;
1153 open $fh, ">$configpm" or
1154 $CPAN::Frontend->mydie("Couldn't open >$configpm: $!");
1155 $fh->print(qq[$msg\$CPAN::Config = \{\n]);
1156 foreach (sort keys %$CPAN::Config) {
1159 ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$_}),
1164 $fh->print("};\n1;\n__END__\n");
1167 #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
1168 #chmod $mode, $configpm;
1169 ###why was that so? $self->defaults;
1170 $CPAN::Frontend->myprint("commit: wrote $configpm\n");
1174 *default = \&defaults;
1175 #-> sub CPAN::Config::defaults ;
1185 undef $CPAN::Config->{'inhibit_startup_message'}; # lazy trick to
1194 # This is a piece of repeated code that is abstracted here for
1195 # maintainability. RMB
1198 my($configpmdir, $configpmtest) = @_;
1199 if (-w $configpmtest) {
1200 return $configpmtest;
1201 } elsif (-w $configpmdir) {
1202 #_#_# following code dumped core on me with 5.003_11, a.k.
1203 my $configpm_bak = "$configpmtest.bak";
1204 unlink $configpm_bak if -f $configpm_bak;
1205 if( -f $configpmtest ) {
1206 if( rename $configpmtest, $configpm_bak ) {
1207 $CPAN::Frontend->mywarn(<<END)
1208 Old configuration file $configpmtest
1209 moved to $configpm_bak
1213 my $fh = FileHandle->new;
1214 if ($fh->open(">$configpmtest")) {
1216 return $configpmtest;
1218 # Should never happen
1219 Carp::confess("Cannot open >$configpmtest");
1224 #-> sub CPAN::Config::load ;
1229 eval {require CPAN::Config;}; # We eval because of some
1230 # MakeMaker problems
1231 unless ($dot_cpan++){
1232 unshift @INC, File::Spec->catdir($ENV{HOME},".cpan");
1233 eval {require CPAN::MyConfig;}; # where you can override
1234 # system wide settings
1237 return unless @miss = $self->missing_config_data;
1239 require CPAN::FirstTime;
1240 my($configpm,$fh,$redo,$theycalled);
1242 $theycalled++ if @miss==1 && $miss[0] eq 'inhibit_startup_message';
1243 if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
1244 $configpm = $INC{"CPAN/Config.pm"};
1246 } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
1247 $configpm = $INC{"CPAN/MyConfig.pm"};
1250 my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
1251 my($configpmdir) = File::Spec->catdir($path_to_cpan,"CPAN");
1252 my($configpmtest) = File::Spec->catfile($configpmdir,"Config.pm");
1253 if (-d $configpmdir or File::Path::mkpath($configpmdir)) {
1254 $configpm = _configpmtest($configpmdir,$configpmtest);
1256 unless ($configpm) {
1257 $configpmdir = File::Spec->catdir($ENV{HOME},".cpan","CPAN");
1258 File::Path::mkpath($configpmdir);
1259 $configpmtest = File::Spec->catfile($configpmdir,"MyConfig.pm");
1260 $configpm = _configpmtest($configpmdir,$configpmtest);
1261 unless ($configpm) {
1262 Carp::confess(qq{WARNING: CPAN.pm is unable to }.
1263 qq{create a configuration file.});
1268 $CPAN::Frontend->myprint(<<END) if $redo && ! $theycalled;
1269 We have to reconfigure CPAN.pm due to following uninitialized parameters:
1273 $CPAN::Frontend->myprint(qq{
1274 $configpm initialized.
1277 CPAN::FirstTime::init($configpm);
1280 #-> sub CPAN::Config::missing_config_data ;
1281 sub missing_config_data {
1284 "cpan_home", "keep_source_where", "build_dir", "build_cache",
1285 "scan_cache", "index_expire", "gzip", "tar", "unzip", "make",
1287 "makepl_arg", "make_arg", "make_install_arg", "urllist",
1288 "inhibit_startup_message", "ftp_proxy", "http_proxy", "no_proxy",
1289 "prerequisites_policy",
1292 push @miss, $_ unless defined $CPAN::Config->{$_};
1297 #-> sub CPAN::Config::unload ;
1299 delete $INC{'CPAN/MyConfig.pm'};
1300 delete $INC{'CPAN/Config.pm'};
1303 #-> sub CPAN::Config::help ;
1305 $CPAN::Frontend->myprint(q[
1307 defaults reload default config values from disk
1308 commit commit session changes to disk
1309 init go through a dialog to set all parameters
1311 You may edit key values in the follow fashion (the "o" is a literal
1314 o conf build_cache 15
1316 o conf build_dir "/foo/bar"
1318 o conf urllist shift
1320 o conf urllist unshift ftp://ftp.foo.bar/
1323 undef; #don't reprint CPAN::Config
1326 #-> sub CPAN::Config::cpl ;
1328 my($word,$line,$pos) = @_;
1330 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1331 my(@words) = split " ", substr($line,0,$pos+1);
1336 $words[2] =~ /list$/ && @words == 3
1338 $words[2] =~ /list$/ && @words == 4 && length($word)
1341 return grep /^\Q$word\E/, qw(splice shift unshift pop push);
1342 } elsif (@words >= 4) {
1345 my(@o_conf) = (keys %CPAN::Config::can, keys %$CPAN::Config);
1346 return grep /^\Q$word\E/, @o_conf;
1349 package CPAN::Shell;
1351 #-> sub CPAN::Shell::h ;
1353 my($class,$about) = @_;
1354 if (defined $about) {
1355 $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
1357 $CPAN::Frontend->myprint(q{
1359 command argument description
1360 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1361 i WORD or /REGEXP/ about anything of above
1362 r NONE reinstall recommendations
1363 ls AUTHOR about files in the author's directory
1365 Download, Test, Make, Install...
1367 make make (implies get)
1368 test MODULES, make test (implies make)
1369 install DISTS, BUNDLES make install (implies test)
1371 look open subshell in these dists' directories
1372 readme display these dists' README files
1375 h,? display this menu ! perl-code eval a perl command
1376 o conf [opt] set and query options q quit the cpan shell
1377 reload cpan load CPAN.pm again reload index load newer indices
1378 autobundle Snapshot force cmd unconditionally do cmd});
1384 #-> sub CPAN::Shell::a ;
1386 my($self,@arg) = @_;
1387 # authors are always UPPERCASE
1389 $_ = uc $_ unless /=/;
1391 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1394 #-> sub CPAN::Shell::ls ;
1396 my($self,@arg) = @_;
1399 unless (/^[A-Z\-]+$/i) {
1400 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1403 push @accept, uc $_;
1405 for my $a (@accept){
1406 my $author = $self->expand('Author',$a) or die "No author found for $a";
1411 #-> sub CPAN::Shell::local_bundles ;
1413 my($self,@which) = @_;
1414 my($incdir,$bdir,$dh);
1415 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1416 my @bbase = "Bundle";
1417 while (my $bbase = shift @bbase) {
1418 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1419 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1420 if ($dh = DirHandle->new($bdir)) { # may fail
1422 for $entry ($dh->read) {
1423 next if $entry =~ /^\./;
1424 if (-d File::Spec->catdir($bdir,$entry)){
1425 push @bbase, "$bbase\::$entry";
1427 next unless $entry =~ s/\.pm(?!\n)\Z//;
1428 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1436 #-> sub CPAN::Shell::b ;
1438 my($self,@which) = @_;
1439 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1440 $self->local_bundles;
1441 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1444 #-> sub CPAN::Shell::d ;
1445 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1447 #-> sub CPAN::Shell::m ;
1448 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1450 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1453 #-> sub CPAN::Shell::i ;
1458 @type = qw/Author Bundle Distribution Module/;
1459 @args = '/./' unless @args;
1462 push @result, $self->expand($type,@args);
1464 my $result = @result == 1 ?
1465 $result[0]->as_string :
1467 "No objects found of any type for argument @args\n" :
1469 (map {$_->as_glimpse} @result),
1470 scalar @result, " items found\n",
1472 $CPAN::Frontend->myprint($result);
1475 #-> sub CPAN::Shell::o ;
1477 # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf'
1478 # should have been called set and 'o debug' maybe 'set debug'
1480 my($self,$o_type,@o_what) = @_;
1482 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1483 if ($o_type eq 'conf') {
1484 shift @o_what if @o_what && $o_what[0] eq 'help';
1485 if (!@o_what) { # print all things, "o conf"
1487 $CPAN::Frontend->myprint("CPAN::Config options");
1488 if (exists $INC{'CPAN/Config.pm'}) {
1489 $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1491 if (exists $INC{'CPAN/MyConfig.pm'}) {
1492 $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1494 $CPAN::Frontend->myprint(":\n");
1495 for $k (sort keys %CPAN::Config::can) {
1496 $v = $CPAN::Config::can{$k};
1497 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1499 $CPAN::Frontend->myprint("\n");
1500 for $k (sort keys %$CPAN::Config) {
1501 CPAN::Config->prettyprint($k);
1503 $CPAN::Frontend->myprint("\n");
1504 } elsif (!CPAN::Config->edit(@o_what)) {
1505 $CPAN::Frontend->myprint(qq{Type 'o conf' to view configuration }.
1506 qq{edit options\n\n});
1508 } elsif ($o_type eq 'debug') {
1510 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1513 my($what) = shift @o_what;
1514 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
1515 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
1518 if ( exists $CPAN::DEBUG{$what} ) {
1519 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1520 } elsif ($what =~ /^\d/) {
1521 $CPAN::DEBUG = $what;
1522 } elsif (lc $what eq 'all') {
1524 for (values %CPAN::DEBUG) {
1527 $CPAN::DEBUG = $max;
1530 for (keys %CPAN::DEBUG) {
1531 next unless lc($_) eq lc($what);
1532 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
1535 $CPAN::Frontend->myprint("unknown argument [$what]\n")
1540 my $raw = "Valid options for debug are ".
1541 join(", ",sort(keys %CPAN::DEBUG), 'all').
1542 qq{ or a number. Completion works on the options. }.
1543 qq{Case is ignored.};
1545 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
1546 $CPAN::Frontend->myprint("\n\n");
1549 $CPAN::Frontend->myprint("Options set for debugging:\n");
1551 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1552 $v = $CPAN::DEBUG{$k};
1553 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
1554 if $v & $CPAN::DEBUG;
1557 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
1560 $CPAN::Frontend->myprint(qq{
1562 conf set or get configuration variables
1563 debug set or get debugging options
1568 sub paintdots_onreload {
1571 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
1575 # $CPAN::Frontend->myprint(".($subr)");
1576 $CPAN::Frontend->myprint(".");
1583 #-> sub CPAN::Shell::reload ;
1585 my($self,$command,@arg) = @_;
1587 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1588 if ($command =~ /cpan/i) {
1589 for my $f (qw(CPAN.pm CPAN/FirstTime.pm)) {
1590 next unless $INC{$f};
1591 CPAN->debug("reloading the whole $f") if $CPAN::DEBUG;
1592 my $fh = FileHandle->new($INC{$f});
1595 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
1598 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
1600 } elsif ($command =~ /index/) {
1601 CPAN::Index->force_reload;
1603 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
1604 index re-reads the index files\n});
1608 #-> sub CPAN::Shell::_binary_extensions ;
1609 sub _binary_extensions {
1610 my($self) = shift @_;
1611 my(@result,$module,%seen,%need,$headerdone);
1612 for $module ($self->expand('Module','/./')) {
1613 my $file = $module->cpan_file;
1614 next if $file eq "N/A";
1615 next if $file =~ /^Contact Author/;
1616 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
1617 next if $dist->isa_perl;
1618 next unless $module->xs_file;
1620 $CPAN::Frontend->myprint(".");
1621 push @result, $module;
1623 # print join " | ", @result;
1624 $CPAN::Frontend->myprint("\n");
1628 #-> sub CPAN::Shell::recompile ;
1630 my($self) = shift @_;
1631 my($module,@module,$cpan_file,%dist);
1632 @module = $self->_binary_extensions();
1633 for $module (@module){ # we force now and compile later, so we
1635 $cpan_file = $module->cpan_file;
1636 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1638 $dist{$cpan_file}++;
1640 for $cpan_file (sort keys %dist) {
1641 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
1642 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1644 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1645 # stop a package from recompiling,
1646 # e.g. IO-1.12 when we have perl5.003_10
1650 #-> sub CPAN::Shell::_u_r_common ;
1652 my($self) = shift @_;
1653 my($what) = shift @_;
1654 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1655 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
1656 $what && $what =~ /^[aru]$/;
1658 @args = '/./' unless @args;
1659 my(@result,$module,%seen,%need,$headerdone,
1660 $version_undefs,$version_zeroes);
1661 $version_undefs = $version_zeroes = 0;
1662 my $sprintf = "%s%-25s%s %9s %9s %s\n";
1663 my @expand = $self->expand('Module',@args);
1664 my $expand = scalar @expand;
1665 if (0) { # Looks like noise to me, was very useful for debugging
1666 # for metadata cache
1667 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
1669 for $module (@expand) {
1670 my $file = $module->cpan_file;
1671 next unless defined $file; # ??
1672 my($latest) = $module->cpan_version;
1673 my($inst_file) = $module->inst_file;
1675 return if $CPAN::Signal;
1678 $have = $module->inst_version;
1679 } elsif ($what eq "r") {
1680 $have = $module->inst_version;
1682 if ($have eq "undef"){
1684 } elsif ($have == 0){
1687 next unless CPAN::Version->vgt($latest, $have);
1688 # to be pedantic we should probably say:
1689 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1690 # to catch the case where CPAN has a version 0 and we have a version undef
1691 } elsif ($what eq "u") {
1697 } elsif ($what eq "r") {
1699 } elsif ($what eq "u") {
1703 return if $CPAN::Signal; # this is sometimes lengthy
1706 push @result, sprintf "%s %s\n", $module->id, $have;
1707 } elsif ($what eq "r") {
1708 push @result, $module->id;
1709 next if $seen{$file}++;
1710 } elsif ($what eq "u") {
1711 push @result, $module->id;
1712 next if $seen{$file}++;
1713 next if $file =~ /^Contact/;
1715 unless ($headerdone++){
1716 $CPAN::Frontend->myprint("\n");
1717 $CPAN::Frontend->myprint(sprintf(
1720 "Package namespace",
1732 $CPAN::META->has_inst("Term::ANSIColor")
1734 $module->{RO}{description}
1736 $color_on = Term::ANSIColor::color("green");
1737 $color_off = Term::ANSIColor::color("reset");
1739 $CPAN::Frontend->myprint(sprintf $sprintf,
1746 $need{$module->id}++;
1750 $CPAN::Frontend->myprint("No modules found for @args\n");
1751 } elsif ($what eq "r") {
1752 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
1756 if ($version_zeroes) {
1757 my $s_has = $version_zeroes > 1 ? "s have" : " has";
1758 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1759 qq{a version number of 0\n});
1761 if ($version_undefs) {
1762 my $s_has = $version_undefs > 1 ? "s have" : " has";
1763 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1764 qq{parseable version number\n});
1770 #-> sub CPAN::Shell::r ;
1772 shift->_u_r_common("r",@_);
1775 #-> sub CPAN::Shell::u ;
1777 shift->_u_r_common("u",@_);
1780 #-> sub CPAN::Shell::autobundle ;
1783 CPAN::Config->load unless $CPAN::Config_loaded++;
1784 my(@bundle) = $self->_u_r_common("a",@_);
1785 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1786 File::Path::mkpath($todir);
1787 unless (-d $todir) {
1788 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1791 my($y,$m,$d) = (localtime)[5,4,3];
1795 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1796 my($to) = File::Spec->catfile($todir,"$me.pm");
1798 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1799 $to = File::Spec->catfile($todir,"$me.pm");
1801 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1803 "package Bundle::$me;\n\n",
1804 "\$VERSION = '0.01';\n\n",
1808 "Bundle::$me - Snapshot of installation on ",
1809 $Config::Config{'myhostname'},
1812 "\n\n=head1 SYNOPSIS\n\n",
1813 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1814 "=head1 CONTENTS\n\n",
1815 join("\n", @bundle),
1816 "\n\n=head1 CONFIGURATION\n\n",
1818 "\n\n=head1 AUTHOR\n\n",
1819 "This Bundle has been generated automatically ",
1820 "by the autobundle routine in CPAN.pm.\n",
1823 $CPAN::Frontend->myprint("\nWrote bundle file
1827 #-> sub CPAN::Shell::expandany ;
1830 CPAN->debug("s[$s]") if $CPAN::DEBUG;
1831 if ($s =~ m|/|) { # looks like a file
1832 $s = CPAN::Distribution->normalize($s);
1833 return $CPAN::META->instance('CPAN::Distribution',$s);
1834 # Distributions spring into existence, not expand
1835 } elsif ($s =~ m|^Bundle::|) {
1836 $self->local_bundles; # scanning so late for bundles seems
1837 # both attractive and crumpy: always
1838 # current state but easy to forget
1840 return $self->expand('Bundle',$s);
1842 return $self->expand('Module',$s)
1843 if $CPAN::META->exists('CPAN::Module',$s);
1848 #-> sub CPAN::Shell::expand ;
1851 my($type,@args) = @_;
1853 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1855 my($regex,$command);
1856 if ($arg =~ m|^/(.*)/$|) {
1858 } elsif ($arg =~ m/=/) {
1861 my $class = "CPAN::$type";
1863 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1865 defined $regex ? $regex : "UNDEFINED",
1866 $command || "UNDEFINED",
1868 if (defined $regex) {
1872 $CPAN::META->all_objects($class)
1875 # BUG, we got an empty object somewhere
1876 require Data::Dumper;
1877 CPAN->debug(sprintf(
1878 "Bug in CPAN: Empty id on obj[%s][%s]",
1880 Data::Dumper::Dumper($obj)
1885 if $obj->id =~ /$regex/i
1889 $] < 5.00303 ### provide sort of
1890 ### compatibility with 5.003
1895 $obj->name =~ /$regex/i
1898 } elsif ($command) {
1899 die "equal sign in command disabled (immature interface), ".
1901 ! \$CPAN::Shell::ADVANCED_QUERY=1
1902 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1903 that may go away anytime.\n"
1904 unless $ADVANCED_QUERY;
1905 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1906 my($matchcrit) = $criterion =~ m/^~(.+)/;
1910 $CPAN::META->all_objects($class)
1912 my $lhs = $self->$method() or next; # () for 5.00503
1914 push @m, $self if $lhs =~ m/$matchcrit/;
1916 push @m, $self if $lhs eq $criterion;
1921 if ( $type eq 'Bundle' ) {
1922 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1923 } elsif ($type eq "Distribution") {
1924 $xarg = CPAN::Distribution->normalize($arg);
1926 if ($CPAN::META->exists($class,$xarg)) {
1927 $obj = $CPAN::META->instance($class,$xarg);
1928 } elsif ($CPAN::META->exists($class,$arg)) {
1929 $obj = $CPAN::META->instance($class,$arg);
1936 return wantarray ? @m : $m[0];
1939 #-> sub CPAN::Shell::format_result ;
1942 my($type,@args) = @_;
1943 @args = '/./' unless @args;
1944 my(@result) = $self->expand($type,@args);
1945 my $result = @result == 1 ?
1946 $result[0]->as_string :
1948 "No objects of type $type found for argument @args\n" :
1950 (map {$_->as_glimpse} @result),
1951 scalar @result, " items found\n",
1956 # The only reason for this method is currently to have a reliable
1957 # debugging utility that reveals which output is going through which
1958 # channel. No, I don't like the colors ;-)
1960 #-> sub CPAN::Shell::print_ornameted ;
1961 sub print_ornamented {
1962 my($self,$what,$ornament) = @_;
1964 return unless defined $what;
1966 if ($CPAN::Config->{term_is_latin}){
1969 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
1971 if ($PRINT_ORNAMENTING) {
1972 unless (defined &color) {
1973 if ($CPAN::META->has_inst("Term::ANSIColor")) {
1974 import Term::ANSIColor "color";
1976 *color = sub { return "" };
1980 for $line (split /\n/, $what) {
1981 $longest = length($line) if length($line) > $longest;
1983 my $sprintf = "%-" . $longest . "s";
1985 $what =~ s/(.*\n?)//m;
1988 my($nl) = chomp $line ? "\n" : "";
1989 # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
1990 print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
1994 # $what .= "\n"; # newlines unless $PRINT_ORNAMENTING
2000 my($self,$what) = @_;
2002 $self->print_ornamented($what, 'bold blue on_yellow');
2006 my($self,$what) = @_;
2007 $self->myprint($what);
2012 my($self,$what) = @_;
2013 $self->print_ornamented($what, 'bold red on_yellow');
2017 my($self,$what) = @_;
2018 $self->print_ornamented($what, 'bold red on_white');
2019 Carp::confess "died";
2023 my($self,$what) = @_;
2024 $self->print_ornamented($what, 'bold red on_white');
2029 return if -t STDOUT;
2030 my $odef = select STDERR;
2037 #-> sub CPAN::Shell::rematein ;
2038 # RE-adme||MA-ke||TE-st||IN-stall
2041 my($meth,@some) = @_;
2043 if ($meth eq 'force') {
2045 $meth = shift @some;
2048 CPAN->debug("pragma[$pragma]meth[$meth] some[@some]") if $CPAN::DEBUG;
2050 # Here is the place to set "test_count" on all involved parties to
2051 # 0. We then can pass this counter on to the involved
2052 # distributions and those can refuse to test if test_count > X. In
2053 # the first stab at it we could use a 1 for "X".
2055 # But when do I reset the distributions to start with 0 again?
2056 # Jost suggested to have a random or cycling interaction ID that
2057 # we pass through. But the ID is something that is just left lying
2058 # around in addition to the counter, so I'd prefer to set the
2059 # counter to 0 now, and repeat at the end of the loop. But what
2060 # about dependencies? They appear later and are not reset, they
2061 # enter the queue but not its copy. How do they get a sensible
2064 # construct the queue
2066 foreach $s (@some) {
2069 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
2071 } elsif ($s =~ m|^/|) { # looks like a regexp
2072 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
2077 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
2078 $obj = CPAN::Shell->expandany($s);
2081 $obj->color_cmd_tmps(0,1);
2082 CPAN::Queue->new($obj->id);
2084 } elsif ($CPAN::META->exists('CPAN::Author',$s)) {
2085 $obj = $CPAN::META->instance('CPAN::Author',$s);
2086 if ($meth =~ /^(dump|ls)$/) {
2089 $CPAN::Frontend->myprint(
2091 "Don't be silly, you can't $meth ",
2099 ->myprint(qq{Warning: Cannot $meth $s, }.
2100 qq{don\'t know what it is.
2105 to find objects with matching identifiers.
2111 # queuerunner (please be warned: when I started to change the
2112 # queue to hold objects instead of names, I made one or two
2113 # mistakes and never found which. I reverted back instead)
2114 while ($s = CPAN::Queue->first) {
2117 $obj = $s; # I do not believe, we would survive if this happened
2119 $obj = CPAN::Shell->expandany($s);
2123 ($] < 5.00303 || $obj->can($pragma))){
2124 ### compatibility with 5.003
2125 $obj->$pragma($meth); # the pragma "force" in
2126 # "CPAN::Distribution" must know
2127 # what we are intending
2129 if ($]>=5.00303 && $obj->can('called_for')) {
2130 $obj->called_for($s);
2133 qq{pragma[$pragma]meth[$meth]obj[$obj]as_string\[}.
2139 CPAN::Queue->delete($s);
2141 CPAN->debug("failed");
2145 CPAN::Queue->delete_first($s);
2147 for my $obj (@qcopy) {
2148 $obj->color_cmd_tmps(0,0);
2152 #-> sub CPAN::Shell::dump ;
2153 sub dump { shift->rematein('dump',@_); }
2154 #-> sub CPAN::Shell::force ;
2155 sub force { shift->rematein('force',@_); }
2156 #-> sub CPAN::Shell::get ;
2157 sub get { shift->rematein('get',@_); }
2158 #-> sub CPAN::Shell::readme ;
2159 sub readme { shift->rematein('readme',@_); }
2160 #-> sub CPAN::Shell::make ;
2161 sub make { shift->rematein('make',@_); }
2162 #-> sub CPAN::Shell::test ;
2163 sub test { shift->rematein('test',@_); }
2164 #-> sub CPAN::Shell::install ;
2165 sub install { shift->rematein('install',@_); }
2166 #-> sub CPAN::Shell::clean ;
2167 sub clean { shift->rematein('clean',@_); }
2168 #-> sub CPAN::Shell::look ;
2169 sub look { shift->rematein('look',@_); }
2170 #-> sub CPAN::Shell::cvs_import ;
2171 sub cvs_import { shift->rematein('cvs_import',@_); }
2173 package CPAN::LWP::UserAgent;
2176 return if $SETUPDONE;
2177 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2178 require LWP::UserAgent;
2179 @ISA = qw(Exporter LWP::UserAgent);
2182 $CPAN::Frontend->mywarn("LWP::UserAgent not available\n");
2186 sub get_basic_credentials {
2187 my($self, $realm, $uri, $proxy) = @_;
2188 return unless $proxy;
2189 if ($USER && $PASSWD) {
2190 } elsif (defined $CPAN::Config->{proxy_user} &&
2191 defined $CPAN::Config->{proxy_pass}) {
2192 $USER = $CPAN::Config->{proxy_user};
2193 $PASSWD = $CPAN::Config->{proxy_pass};
2195 require ExtUtils::MakeMaker;
2196 ExtUtils::MakeMaker->import(qw(prompt));
2197 $USER = prompt("Proxy authentication needed!
2198 (Note: to permanently configure username and password run
2199 o conf proxy_user your_username
2200 o conf proxy_pass your_password
2202 if ($CPAN::META->has_inst("Term::ReadKey")) {
2203 Term::ReadKey::ReadMode("noecho");
2205 $CPAN::Frontend->mywarn("Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n");
2207 $PASSWD = prompt("Password:");
2208 if ($CPAN::META->has_inst("Term::ReadKey")) {
2209 Term::ReadKey::ReadMode("restore");
2211 $CPAN::Frontend->myprint("\n\n");
2213 return($USER,$PASSWD);
2216 # mirror(): Its purpose is to deal with proxy authentication. When we
2217 # call SUPER::mirror, we relly call the mirror method in
2218 # LWP::UserAgent. LWP::UserAgent will then call
2219 # $self->get_basic_credentials or some equivalent and this will be
2220 # $self->dispatched to our own get_basic_credentials method.
2222 # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2224 # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2225 # although we have gone through our get_basic_credentials, the proxy
2226 # server refuses to connect. This could be a case where the username or
2227 # password has changed in the meantime, so I'm trying once again without
2228 # $USER and $PASSWD to give the get_basic_credentials routine another
2229 # chance to set $USER and $PASSWD.
2232 my($self,$url,$aslocal) = @_;
2233 my $result = $self->SUPER::mirror($url,$aslocal);
2234 if ($result->code == 407) {
2237 $result = $self->SUPER::mirror($url,$aslocal);
2244 #-> sub CPAN::FTP::ftp_get ;
2246 my($class,$host,$dir,$file,$target) = @_;
2248 qq[Going to fetch file [$file] from dir [$dir]
2249 on host [$host] as local [$target]\n]
2251 my $ftp = Net::FTP->new($host);
2252 return 0 unless defined $ftp;
2253 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
2254 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
2255 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
2256 warn "Couldn't login on $host";
2259 unless ( $ftp->cwd($dir) ){
2260 warn "Couldn't cwd $dir";
2264 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
2265 unless ( $ftp->get($file,$target) ){
2266 warn "Couldn't fetch $file from $host\n";
2269 $ftp->quit; # it's ok if this fails
2273 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
2275 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
2276 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
2278 # > *** 1562,1567 ****
2279 # > --- 1562,1580 ----
2280 # > return 1 if substr($url,0,4) eq "file";
2281 # > return 1 unless $url =~ m|://([^/]+)|;
2283 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
2285 # > + $proxy =~ m|://([^/:]+)|;
2287 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
2288 # > + if ($noproxy) {
2289 # > + if ($host !~ /$noproxy$/) {
2290 # > + $host = $proxy;
2293 # > + $host = $proxy;
2296 # > require Net::Ping;
2297 # > return 1 unless $Net::Ping::VERSION >= 2;
2301 #-> sub CPAN::FTP::localize ;
2303 my($self,$file,$aslocal,$force) = @_;
2305 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
2306 unless defined $aslocal;
2307 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
2310 if ($^O eq 'MacOS') {
2311 # Comment by AK on 2000-09-03: Uniq short filenames would be
2312 # available in CHECKSUMS file
2313 my($name, $path) = File::Basename::fileparse($aslocal, '');
2314 if (length($name) > 31) {
2325 my $size = 31 - length($suf);
2326 while (length($name) > $size) {
2330 $aslocal = File::Spec->catfile($path, $name);
2334 return $aslocal if -f $aslocal && -r _ && !($force & 1);
2337 rename $aslocal, "$aslocal.bak";
2341 my($aslocal_dir) = File::Basename::dirname($aslocal);
2342 File::Path::mkpath($aslocal_dir);
2343 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
2344 qq{directory "$aslocal_dir".
2345 I\'ll continue, but if you encounter problems, they may be due
2346 to insufficient permissions.\n}) unless -w $aslocal_dir;
2348 # Inheritance is not easier to manage than a few if/else branches
2349 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2351 CPAN::LWP::UserAgent->config;
2352 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
2354 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
2358 $Ua->proxy('ftp', $var)
2359 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
2360 $Ua->proxy('http', $var)
2361 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
2364 # >>>>> On Wed, 13 Dec 2000 09:21:34 -0500, "Robison, Jonathon (J.M.)" <jrobiso2@visteon.com> said:
2366 # > I note that although CPAN.pm can use proxies, it doesn't seem equipped to
2367 # > use ones that require basic autorization.
2369 # > Example of when I use it manually in my own stuff:
2371 # > $ua->proxy(['http','ftp'], http://my.proxy.server:83');
2372 # > $req->proxy_authorization_basic("username","password");
2373 # > $res = $ua->request($req);
2377 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
2381 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
2382 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
2385 # Try the list of urls for each single object. We keep a record
2386 # where we did get a file from
2387 my(@reordered,$last);
2388 $CPAN::Config->{urllist} ||= [];
2389 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
2390 warn "Malformed urllist; ignoring. Configuration file corrupt?\n";
2392 $last = $#{$CPAN::Config->{urllist}};
2393 if ($force & 2) { # local cpans probably out of date, don't reorder
2394 @reordered = (0..$last);
2398 (substr($CPAN::Config->{urllist}[$b],0,4) eq "file")
2400 (substr($CPAN::Config->{urllist}[$a],0,4) eq "file")
2411 @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/);
2413 @levels = qw/easy hard hardest/;
2415 @levels = qw/easy/ if $^O eq 'MacOS';
2417 for $levelno (0..$#levels) {
2418 my $level = $levels[$levelno];
2419 my $method = "host$level";
2420 my @host_seq = $level eq "easy" ?
2421 @reordered : 0..$last; # reordered has CDROM up front
2422 @host_seq = (0) unless @host_seq;
2423 my $ret = $self->$method(\@host_seq,$file,$aslocal);
2425 $Themethod = $level;
2427 # utime $now, $now, $aslocal; # too bad, if we do that, we
2428 # might alter a local mirror
2429 $self->debug("level[$level]") if $CPAN::DEBUG;
2433 last if $CPAN::Signal; # need to cleanup
2436 unless ($CPAN::Signal) {
2439 qq{Please check, if the URLs I found in your configuration file \(}.
2440 join(", ", @{$CPAN::Config->{urllist}}).
2441 qq{\) are valid. The urllist can be edited.},
2442 qq{E.g. with 'o conf urllist push ftp://myurl/'};
2443 $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n");
2445 $CPAN::Frontend->myprint("Could not fetch $file\n");
2448 rename "$aslocal.bak", $aslocal;
2449 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
2450 $self->ls($aslocal));
2457 my($self,$host_seq,$file,$aslocal) = @_;
2459 HOSTEASY: for $i (@$host_seq) {
2460 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2461 $url .= "/" unless substr($url,-1) eq "/";
2463 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
2464 if ($url =~ /^file:/) {
2466 if ($CPAN::META->has_inst('URI::URL')) {
2467 my $u = URI::URL->new($url);
2469 } else { # works only on Unix, is poorly constructed, but
2470 # hopefully better than nothing.
2471 # RFC 1738 says fileurl BNF is
2472 # fileurl = "file://" [ host | "localhost" ] "/" fpath
2473 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
2475 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
2476 $l =~ s|^file:||; # assume they
2479 $l =~ s|^/||s unless -f $l; # e.g. /P:
2480 $self->debug("without URI::URL we try local file $l") if $CPAN::DEBUG;
2482 if ( -f $l && -r _) {
2486 # Maybe mirror has compressed it?
2488 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
2489 CPAN::Tarzip->gunzip("$l.gz", $aslocal);
2496 if ($CPAN::META->has_usable('LWP')) {
2497 $CPAN::Frontend->myprint("Fetching with LWP:
2501 CPAN::LWP::UserAgent->config;
2502 eval { $Ua = CPAN::LWP::UserAgent->new; };
2504 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
2507 my $res = $Ua->mirror($url, $aslocal);
2508 if ($res->is_success) {
2511 utime $now, $now, $aslocal; # download time is more
2512 # important than upload time
2514 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2515 my $gzurl = "$url.gz";
2516 $CPAN::Frontend->myprint("Fetching with LWP:
2519 $res = $Ua->mirror($gzurl, "$aslocal.gz");
2520 if ($res->is_success &&
2521 CPAN::Tarzip->gunzip("$aslocal.gz",$aslocal)
2527 $CPAN::Frontend->myprint(sprintf(
2528 "LWP failed with code[%s] message[%s]\n",
2532 # Alan Burlison informed me that in firewall environments
2533 # Net::FTP can still succeed where LWP fails. So we do not
2534 # skip Net::FTP anymore when LWP is available.
2537 $CPAN::Frontend->myprint("LWP not available\n");
2539 return if $CPAN::Signal;
2540 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2541 # that's the nice and easy way thanks to Graham
2542 my($host,$dir,$getfile) = ($1,$2,$3);
2543 if ($CPAN::META->has_usable('Net::FTP')) {
2545 $CPAN::Frontend->myprint("Fetching with Net::FTP:
2548 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
2549 "aslocal[$aslocal]") if $CPAN::DEBUG;
2550 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
2554 if ($aslocal !~ /\.gz(?!\n)\Z/) {
2555 my $gz = "$aslocal.gz";
2556 $CPAN::Frontend->myprint("Fetching with Net::FTP
2559 if (CPAN::FTP->ftp_get($host,
2563 CPAN::Tarzip->gunzip($gz,$aslocal)
2572 return if $CPAN::Signal;
2577 my($self,$host_seq,$file,$aslocal) = @_;
2579 # Came back if Net::FTP couldn't establish connection (or
2580 # failed otherwise) Maybe they are behind a firewall, but they
2581 # gave us a socksified (or other) ftp program...
2584 my($devnull) = $CPAN::Config->{devnull} || "";
2586 my($aslocal_dir) = File::Basename::dirname($aslocal);
2587 File::Path::mkpath($aslocal_dir);
2588 HOSTHARD: for $i (@$host_seq) {
2589 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2590 $url .= "/" unless substr($url,-1) eq "/";
2592 my($proto,$host,$dir,$getfile);
2594 # Courtesy Mark Conty mark_conty@cargill.com change from
2595 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2597 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
2598 # proto not yet used
2599 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
2601 next HOSTHARD; # who said, we could ftp anything except ftp?
2603 next HOSTHARD if $proto eq "file"; # file URLs would have had
2604 # success above. Likely a bogus URL
2606 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
2608 for $f ('lynx','ncftpget','ncftp','wget') {
2609 next unless exists $CPAN::Config->{$f};
2610 $funkyftp = $CPAN::Config->{$f};
2611 next unless defined $funkyftp;
2612 next if $funkyftp =~ /^\s*$/;
2613 my($asl_ungz, $asl_gz);
2614 ($asl_ungz = $aslocal) =~ s/\.gz//;
2615 $asl_gz = "$asl_ungz.gz";
2616 my($src_switch) = "";
2618 $src_switch = " -source";
2619 } elsif ($f eq "ncftp"){
2620 $src_switch = " -c";
2621 } elsif ($f eq "wget"){
2622 $src_switch = " -O -";
2625 my($stdout_redir) = " > $asl_ungz";
2626 if ($f eq "ncftpget"){
2627 $chdir = "cd $aslocal_dir && ";
2630 $CPAN::Frontend->myprint(
2632 Trying with "$funkyftp$src_switch" to get
2636 "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
2637 $self->debug("system[$system]") if $CPAN::DEBUG;
2639 if (($wstatus = system($system)) == 0
2642 -s $asl_ungz # lynx returns 0 when it fails somewhere
2648 } elsif ($asl_ungz ne $aslocal) {
2649 # test gzip integrity
2650 if (CPAN::Tarzip->gtest($asl_ungz)) {
2651 # e.g. foo.tar is gzipped --> foo.tar.gz
2652 rename $asl_ungz, $aslocal;
2654 CPAN::Tarzip->gzip($asl_ungz,$asl_gz);
2659 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2661 -f $asl_ungz && -s _ == 0;
2662 my $gz = "$aslocal.gz";
2663 my $gzurl = "$url.gz";
2664 $CPAN::Frontend->myprint(
2666 Trying with "$funkyftp$src_switch" to get
2669 my($system) = "$funkyftp$src_switch \"$url.gz\" $devnull > $asl_gz";
2670 $self->debug("system[$system]") if $CPAN::DEBUG;
2672 if (($wstatus = system($system)) == 0
2676 # test gzip integrity
2677 if (CPAN::Tarzip->gtest($asl_gz)) {
2678 CPAN::Tarzip->gunzip($asl_gz,$aslocal);
2680 # somebody uncompressed file for us?
2681 rename $asl_ungz, $aslocal;
2686 unlink $asl_gz if -f $asl_gz;
2689 my $estatus = $wstatus >> 8;
2690 my $size = -f $aslocal ?
2691 ", left\n$aslocal with size ".-s _ :
2692 "\nWarning: expected file [$aslocal] doesn't exist";
2693 $CPAN::Frontend->myprint(qq{
2694 System call "$system"
2695 returned status $estatus (wstat $wstatus)$size
2698 return if $CPAN::Signal;
2699 } # lynx,ncftpget,ncftp
2704 my($self,$host_seq,$file,$aslocal) = @_;
2707 my($aslocal_dir) = File::Basename::dirname($aslocal);
2708 File::Path::mkpath($aslocal_dir);
2709 my $ftpbin = $CPAN::Config->{ftp};
2710 HOSTHARDEST: for $i (@$host_seq) {
2711 unless (length $ftpbin && MM->maybe_command($ftpbin)) {
2712 $CPAN::Frontend->myprint("No external ftp command available\n\n");
2715 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2716 $url .= "/" unless substr($url,-1) eq "/";
2718 $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
2719 unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2722 my($host,$dir,$getfile) = ($1,$2,$3);
2724 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
2725 $ctime,$blksize,$blocks) = stat($aslocal);
2726 $timestamp = $mtime ||= 0;
2727 my($netrc) = CPAN::FTP::netrc->new;
2728 my($netrcfile) = $netrc->netrc;
2729 my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
2730 my $targetfile = File::Basename::basename($aslocal);
2736 map("cd $_", split /\//, $dir), # RFC 1738
2738 "get $getfile $targetfile",
2742 CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
2743 } elsif ($netrc->hasdefault || $netrc->contains($host)) {
2744 CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
2746 $netrc->contains($host))) if $CPAN::DEBUG;
2747 if ($netrc->protected) {
2748 $CPAN::Frontend->myprint(qq{
2749 Trying with external ftp to get
2751 As this requires some features that are not thoroughly tested, we\'re
2752 not sure, that we get it right....
2756 $self->talk_ftp("$ftpbin$verbose $host",
2758 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2759 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2761 if ($mtime > $timestamp) {
2762 $CPAN::Frontend->myprint("GOT $aslocal\n");
2766 $CPAN::Frontend->myprint("Hmm... Still failed!\n");
2768 return if $CPAN::Signal;
2770 $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
2771 qq{correctly protected.\n});
2774 $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
2775 nor does it have a default entry\n");
2778 # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
2779 # then and login manually to host, using e-mail as
2781 $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n});
2785 "user anonymous $Config::Config{'cf_email'}"
2787 $self->talk_ftp("$ftpbin$verbose -n", @dialog);
2788 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2789 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2791 if ($mtime > $timestamp) {
2792 $CPAN::Frontend->myprint("GOT $aslocal\n");
2796 $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
2798 return if $CPAN::Signal;
2799 $CPAN::Frontend->myprint("Can't access URL $url.\n\n");
2805 my($self,$command,@dialog) = @_;
2806 my $fh = FileHandle->new;
2807 $fh->open("|$command") or die "Couldn't open ftp: $!";
2808 foreach (@dialog) { $fh->print("$_\n") }
2809 $fh->close; # Wait for process to complete
2811 my $estatus = $wstatus >> 8;
2812 $CPAN::Frontend->myprint(qq{
2813 Subprocess "|$command"
2814 returned status $estatus (wstat $wstatus)
2818 # find2perl needs modularization, too, all the following is stolen
2822 my($self,$name) = @_;
2823 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
2824 $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
2826 my($perms,%user,%group);
2830 $blocks = int(($blocks + 1) / 2);
2833 $blocks = int(($sizemm + 1023) / 1024);
2836 if (-f _) { $perms = '-'; }
2837 elsif (-d _) { $perms = 'd'; }
2838 elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
2839 elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
2840 elsif (-p _) { $perms = 'p'; }
2841 elsif (-S _) { $perms = 's'; }
2842 else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
2844 my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
2845 my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
2846 my $tmpmode = $mode;
2847 my $tmp = $rwx[$tmpmode & 7];
2849 $tmp = $rwx[$tmpmode & 7] . $tmp;
2851 $tmp = $rwx[$tmpmode & 7] . $tmp;
2852 substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
2853 substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
2854 substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
2857 my $user = $user{$uid} || $uid; # too lazy to implement lookup
2858 my $group = $group{$gid} || $gid;
2860 my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
2862 my($moname) = $moname[$mon];
2863 if (-M _ > 365.25 / 2) {
2864 $timeyear = $year + 1900;
2867 $timeyear = sprintf("%02d:%02d", $hour, $min);
2870 sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
2884 package CPAN::FTP::netrc;
2888 my $file = File::Spec->catfile($ENV{HOME},".netrc");
2890 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2891 $atime,$mtime,$ctime,$blksize,$blocks)
2896 my($fh,@machines,$hasdefault);
2898 $fh = FileHandle->new or die "Could not create a filehandle";
2900 if($fh->open($file)){
2901 $protected = ($mode & 077) == 0;
2903 NETRC: while (<$fh>) {
2904 my(@tokens) = split " ", $_;
2905 TOKEN: while (@tokens) {
2906 my($t) = shift @tokens;
2907 if ($t eq "default"){
2911 last TOKEN if $t eq "macdef";
2912 if ($t eq "machine") {
2913 push @machines, shift @tokens;
2918 $file = $hasdefault = $protected = "";
2922 'mach' => [@machines],
2924 'hasdefault' => $hasdefault,
2925 'protected' => $protected,
2929 # CPAN::FTP::hasdefault;
2930 sub hasdefault { shift->{'hasdefault'} }
2931 sub netrc { shift->{'netrc'} }
2932 sub protected { shift->{'protected'} }
2934 my($self,$mach) = @_;
2935 for ( @{$self->{'mach'}} ) {
2936 return 1 if $_ eq $mach;
2941 package CPAN::Complete;
2944 my($text, $line, $start, $end) = @_;
2945 my(@perlret) = cpl($text, $line, $start);
2946 # find longest common match. Can anybody show me how to peruse
2947 # T::R::Gnu to have this done automatically? Seems expensive.
2948 return () unless @perlret;
2949 my($newtext) = $text;
2950 for (my $i = length($text)+1;;$i++) {
2951 last unless length($perlret[0]) && length($perlret[0]) >= $i;
2952 my $try = substr($perlret[0],0,$i);
2953 my @tries = grep {substr($_,0,$i) eq $try} @perlret;
2954 # warn "try[$try]tries[@tries]";
2955 if (@tries == @perlret) {
2961 ($newtext,@perlret);
2964 #-> sub CPAN::Complete::cpl ;
2966 my($word,$line,$pos) = @_;
2970 CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2972 if ($line =~ s/^(force\s*)//) {
2977 @return = grep /^$word/, @CPAN::Complete::COMMANDS;
2978 } elsif ( $line !~ /^[\!abcdghimorutl]/ ) {
2980 } elsif ($line =~ /^(a|ls)\s/) {
2981 @return = cplx('CPAN::Author',uc($word));
2982 } elsif ($line =~ /^b\s/) {
2983 CPAN::Shell->local_bundles;
2984 @return = cplx('CPAN::Bundle',$word);
2985 } elsif ($line =~ /^d\s/) {
2986 @return = cplx('CPAN::Distribution',$word);
2987 } elsif ($line =~ m/^(
2988 [mru]|make|clean|dump|get|test|install|readme|look|cvs_import
2990 if ($word =~ /^Bundle::/) {
2991 CPAN::Shell->local_bundles;
2993 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
2994 } elsif ($line =~ /^i\s/) {
2995 @return = cpl_any($word);
2996 } elsif ($line =~ /^reload\s/) {
2997 @return = cpl_reload($word,$line,$pos);
2998 } elsif ($line =~ /^o\s/) {
2999 @return = cpl_option($word,$line,$pos);
3000 } elsif ($line =~ m/^\S+\s/ ) {
3001 # fallback for future commands and what we have forgotten above
3002 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
3009 #-> sub CPAN::Complete::cplx ;
3011 my($class, $word) = @_;
3012 # I believed for many years that this was sorted, today I
3013 # realized, it wasn't sorted anymore. Now (rev 1.301 / v 1.55) I
3014 # make it sorted again. Maybe sort was dropped when GNU-readline
3015 # support came in? The RCS file is difficult to read on that:-(
3016 sort grep /^\Q$word\E/, map { $_->id } $CPAN::META->all_objects($class);
3019 #-> sub CPAN::Complete::cpl_any ;
3023 cplx('CPAN::Author',$word),
3024 cplx('CPAN::Bundle',$word),
3025 cplx('CPAN::Distribution',$word),
3026 cplx('CPAN::Module',$word),
3030 #-> sub CPAN::Complete::cpl_reload ;
3032 my($word,$line,$pos) = @_;
3034 my(@words) = split " ", $line;
3035 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3036 my(@ok) = qw(cpan index);
3037 return @ok if @words == 1;
3038 return grep /^\Q$word\E/, @ok if @words == 2 && $word;
3041 #-> sub CPAN::Complete::cpl_option ;
3043 my($word,$line,$pos) = @_;
3045 my(@words) = split " ", $line;
3046 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3047 my(@ok) = qw(conf debug);
3048 return @ok if @words == 1;
3049 return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
3051 } elsif ($words[1] eq 'index') {
3053 } elsif ($words[1] eq 'conf') {
3054 return CPAN::Config::cpl(@_);
3055 } elsif ($words[1] eq 'debug') {
3056 return sort grep /^\Q$word\E/, sort keys %CPAN::DEBUG, 'all';
3060 package CPAN::Index;
3062 #-> sub CPAN::Index::force_reload ;
3065 $CPAN::Index::LAST_TIME = 0;
3069 #-> sub CPAN::Index::reload ;
3071 my($cl,$force) = @_;
3074 # XXX check if a newer one is available. (We currently read it
3075 # from time to time)
3076 for ($CPAN::Config->{index_expire}) {
3077 $_ = 0.001 unless $_ && $_ > 0.001;
3079 unless (1 || $CPAN::Have_warned->{readmetadatacache}++) {
3080 # debug here when CPAN doesn't seem to read the Metadata
3082 Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]");
3084 unless ($CPAN::META->{PROTOCOL}) {
3085 $cl->read_metadata_cache;
3086 $CPAN::META->{PROTOCOL} ||= "1.0";
3088 if ( $CPAN::META->{PROTOCOL} < PROTOCOL ) {
3089 # warn "Setting last_time to 0";
3090 $LAST_TIME = 0; # No warning necessary
3092 return if $LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time
3095 # IFF we are developing, it helps to wipe out the memory
3096 # between reloads, otherwise it is not what a user expects.
3097 undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274)
3098 $CPAN::META = CPAN->new;
3102 local $LAST_TIME = $time;
3103 local $CPAN::META->{PROTOCOL} = PROTOCOL;
3105 my $needshort = $^O eq "dos";
3107 $cl->rd_authindex($cl
3109 "authors/01mailrc.txt.gz",
3111 File::Spec->catfile('authors', '01mailrc.gz') :
3112 File::Spec->catfile('authors', '01mailrc.txt.gz'),
3115 $debug = "timing reading 01[".($t2 - $time)."]";
3117 return if $CPAN::Signal; # this is sometimes lengthy
3118 $cl->rd_modpacks($cl
3120 "modules/02packages.details.txt.gz",
3122 File::Spec->catfile('modules', '02packag.gz') :
3123 File::Spec->catfile('modules', '02packages.details.txt.gz'),
3126 $debug .= "02[".($t2 - $time)."]";
3128 return if $CPAN::Signal; # this is sometimes lengthy
3131 "modules/03modlist.data.gz",
3133 File::Spec->catfile('modules', '03mlist.gz') :
3134 File::Spec->catfile('modules', '03modlist.data.gz'),
3136 $cl->write_metadata_cache;
3138 $debug .= "03[".($t2 - $time)."]";
3140 CPAN->debug($debug) if $CPAN::DEBUG;
3143 $CPAN::META->{PROTOCOL} = PROTOCOL;
3146 #-> sub CPAN::Index::reload_x ;
3148 my($cl,$wanted,$localname,$force) = @_;
3149 $force |= 2; # means we're dealing with an index here
3150 CPAN::Config->load; # we should guarantee loading wherever we rely
3152 $localname ||= $wanted;
3153 my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'},
3157 -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
3160 my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
3161 $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
3162 qq{day$s. I\'ll use that.});
3165 $force |= 1; # means we're quite serious about it.
3167 return CPAN::FTP->localize($wanted,$abs_wanted,$force);
3170 #-> sub CPAN::Index::rd_authindex ;
3172 my($cl, $index_target) = @_;
3174 return unless defined $index_target;
3175 $CPAN::Frontend->myprint("Going to read $index_target\n");
3177 tie *FH, CPAN::Tarzip, $index_target;
3179 push @lines, split /\012/ while <FH>;
3181 my($userid,$fullname,$email) =
3182 m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
3183 next unless $userid && $fullname && $email;
3185 # instantiate an author object
3186 my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
3187 $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
3188 return if $CPAN::Signal;
3193 my($self,$dist) = @_;
3194 $dist = $self->{'id'} unless defined $dist;
3195 my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
3199 #-> sub CPAN::Index::rd_modpacks ;
3201 my($self, $index_target) = @_;
3203 return unless defined $index_target;
3204 $CPAN::Frontend->myprint("Going to read $index_target\n");
3205 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3207 while ($_ = $fh->READLINE) {
3209 my @ls = map {"$_\n"} split /\n/, $_;
3210 unshift @ls, "\n" x length($1) if /^(\n+)/;
3214 my($line_count,$last_updated);
3216 my $shift = shift(@lines);
3217 last if $shift =~ /^\s*$/;
3218 $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1;
3219 $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1;
3221 if (not defined $line_count) {
3223 warn qq{Warning: Your $index_target does not contain a Line-Count header.
3224 Please check the validity of the index file by comparing it to more
3225 than one CPAN mirror. I'll continue but problems seem likely to
3230 } elsif ($line_count != scalar @lines) {
3232 warn sprintf qq{Warning: Your %s
3233 contains a Line-Count header of %d but I see %d lines there. Please
3234 check the validity of the index file by comparing it to more than one
3235 CPAN mirror. I'll continue but problems seem likely to happen.\a\n},
3236 $index_target, $line_count, scalar(@lines);
3239 if (not defined $last_updated) {
3241 warn qq{Warning: Your $index_target does not contain a Last-Updated header.
3242 Please check the validity of the index file by comparing it to more
3243 than one CPAN mirror. I'll continue but problems seem likely to
3251 ->myprint(sprintf qq{ Database was generated on %s\n},
3253 $DATE_OF_02 = $last_updated;
3255 if ($CPAN::META->has_inst(HTTP::Date)) {
3257 my($age) = (time - HTTP::Date::str2time($last_updated))/3600/24;
3262 qq{Warning: This index file is %d days old.
3263 Please check the host you chose as your CPAN mirror for staleness.
3264 I'll continue but problems seem likely to happen.\a\n},
3269 $CPAN::Frontend->myprint(" HTTP::Date not available\n");
3274 # A necessity since we have metadata_cache: delete what isn't
3276 my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN");
3277 CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
3281 # before 1.56 we split into 3 and discarded the rest. From
3282 # 1.57 we assign remaining text to $comment thus allowing to
3283 # influence isa_perl
3284 my($mod,$version,$dist,$comment) = split " ", $_, 4;
3285 my($bundle,$id,$userid);
3287 if ($mod eq 'CPAN' &&
3289 CPAN::Queue->exists('Bundle::CPAN') ||
3290 CPAN::Queue->exists('CPAN')
3294 if ($version > $CPAN::VERSION){
3295 $CPAN::Frontend->myprint(qq{
3296 There's a new CPAN.pm version (v$version) available!
3297 [Current version is v$CPAN::VERSION]
3298 You might want to try
3299 install Bundle::CPAN
3301 without quitting the current session. It should be a seamless upgrade
3302 while we are running...
3305 $CPAN::Frontend->myprint(qq{\n});
3307 last if $CPAN::Signal;
3308 } elsif ($mod =~ /^Bundle::(.*)/) {
3313 $id = $CPAN::META->instance('CPAN::Bundle',$mod);
3314 # Let's make it a module too, because bundles have so much
3315 # in common with modules.
3317 # Changed in 1.57_63: seems like memory bloat now without
3318 # any value, so commented out
3320 # $CPAN::META->instance('CPAN::Module',$mod);
3324 # instantiate a module object
3325 $id = $CPAN::META->instance('CPAN::Module',$mod);
3329 if ($id->cpan_file ne $dist){ # update only if file is
3330 # different. CPAN prohibits same
3331 # name with different version
3332 $userid = $id->userid || $self->userid($dist);
3334 'CPAN_USERID' => $userid,
3335 'CPAN_VERSION' => $version,
3336 'CPAN_FILE' => $dist,
3340 # instantiate a distribution object
3341 if ($CPAN::META->exists('CPAN::Distribution',$dist)) {
3342 # we do not need CONTAINSMODS unless we do something with
3343 # this dist, so we better produce it on demand.
3345 ## my $obj = $CPAN::META->instance(
3346 ## 'CPAN::Distribution' => $dist
3348 ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental
3350 $CPAN::META->instance(
3351 'CPAN::Distribution' => $dist
3353 'CPAN_USERID' => $userid,
3354 'CPAN_COMMENT' => $comment,
3358 for my $name ($mod,$dist) {
3359 CPAN->debug("exists name[$name]") if $CPAN::DEBUG;
3360 $exists{$name} = undef;
3363 return if $CPAN::Signal;
3367 for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) {
3368 for my $o ($CPAN::META->all_objects($class)) {
3369 next if exists $exists{$o->{ID}};
3370 $CPAN::META->delete($class,$o->{ID});
3371 CPAN->debug("deleting ID[$o->{ID}] in class[$class]")
3378 #-> sub CPAN::Index::rd_modlist ;
3380 my($cl,$index_target) = @_;
3381 return unless defined $index_target;
3382 $CPAN::Frontend->myprint("Going to read $index_target\n");
3383 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3386 while ($_ = $fh->READLINE) {
3388 my @ls = map {"$_\n"} split /\n/, $_;
3389 unshift @ls, "\n" x length($1) if /^(\n+)/;
3393 my $shift = shift(@eval);
3394 if ($shift =~ /^Date:\s+(.*)/){
3395 return if $DATE_OF_03 eq $1;
3398 last if $shift =~ /^\s*$/;
3401 push @eval, q{CPAN::Modulelist->data;};
3403 my($comp) = Safe->new("CPAN::Safe1");
3404 my($eval) = join("", @eval);
3405 my $ret = $comp->reval($eval);
3406 Carp::confess($@) if $@;
3407 return if $CPAN::Signal;
3409 my $obj = $CPAN::META->instance("CPAN::Module",$_);
3410 delete $ret->{$_}{modid}; # not needed here, maybe elsewhere
3411 $obj->set(%{$ret->{$_}});
3412 return if $CPAN::Signal;
3416 #-> sub CPAN::Index::write_metadata_cache ;
3417 sub write_metadata_cache {
3419 return unless $CPAN::Config->{'cache_metadata'};
3420 return unless $CPAN::META->has_usable("Storable");
3422 foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module
3423 CPAN::Distribution)) {
3424 $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok
3426 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3427 $cache->{last_time} = $LAST_TIME;
3428 $cache->{DATE_OF_02} = $DATE_OF_02;
3429 $cache->{PROTOCOL} = PROTOCOL;
3430 $CPAN::Frontend->myprint("Going to write $metadata_file\n");
3431 eval { Storable::nstore($cache, $metadata_file) };
3432 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3435 #-> sub CPAN::Index::read_metadata_cache ;
3436 sub read_metadata_cache {
3438 return unless $CPAN::Config->{'cache_metadata'};
3439 return unless $CPAN::META->has_usable("Storable");
3440 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3441 return unless -r $metadata_file and -f $metadata_file;
3442 $CPAN::Frontend->myprint("Going to read $metadata_file\n");
3444 eval { $cache = Storable::retrieve($metadata_file) };
3445 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3446 if (!$cache || ref $cache ne 'HASH'){
3450 if (exists $cache->{PROTOCOL}) {
3451 if (PROTOCOL > $cache->{PROTOCOL}) {
3452 $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ".
3453 "with protocol v%s, requiring v%s\n",
3460 $CPAN::Frontend->mywarn("Ignoring Metadata cache written ".
3461 "with protocol v1.0\n");
3466 while(my($class,$v) = each %$cache) {
3467 next unless $class =~ /^CPAN::/;
3468 $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok
3469 while (my($id,$ro) = each %$v) {
3470 $CPAN::META->{readwrite}{$class}{$id} ||=
3471 $class->new(ID=>$id, RO=>$ro);
3476 unless ($clcnt) { # sanity check
3477 $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n");
3480 if ($idcnt < 1000) {
3481 $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ".
3482 "in $metadata_file\n");
3485 $CPAN::META->{PROTOCOL} ||=
3486 $cache->{PROTOCOL}; # reading does not up or downgrade, but it
3487 # does initialize to some protocol
3488 $LAST_TIME = $cache->{last_time};
3489 $DATE_OF_02 = $cache->{DATE_OF_02};
3490 $CPAN::Frontend->myprint(" Database was generated on $DATE_OF_02\n")
3491 if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
3495 package CPAN::InfoObj;
3500 $self->{RO}{CPAN_USERID}
3503 sub id { shift->{ID}; }
3505 #-> sub CPAN::InfoObj::new ;
3507 my $this = bless {}, shift;
3512 # The set method may only be used by code that reads index data or
3513 # otherwise "objective" data from the outside world. All session
3514 # related material may do anything else with instance variables but
3515 # must not touch the hash under the RO attribute. The reason is that
3516 # the RO hash gets written to Metadata file and is thus persistent.
3518 #-> sub CPAN::InfoObj::set ;
3520 my($self,%att) = @_;
3521 my $class = ref $self;
3523 # This must be ||=, not ||, because only if we write an empty
3524 # reference, only then the set method will write into the readonly
3525 # area. But for Distributions that spring into existence, maybe
3526 # because of a typo, we do not like it that they are written into
3527 # the readonly area and made permanent (at least for a while) and
3528 # that is why we do not "allow" other places to call ->set.
3529 unless ($self->id) {
3530 CPAN->debug("Bug? Empty ID, rejecting");
3533 my $ro = $self->{RO} =
3534 $CPAN::META->{readonly}{$class}{$self->id} ||= {};
3536 while (my($k,$v) = each %att) {
3541 #-> sub CPAN::InfoObj::as_glimpse ;
3545 my $class = ref($self);
3546 $class =~ s/^CPAN:://;
3547 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
3551 #-> sub CPAN::InfoObj::as_string ;
3555 my $class = ref($self);
3556 $class =~ s/^CPAN:://;
3557 push @m, $class, " id = $self->{ID}\n";
3558 for (sort keys %{$self->{RO}}) {
3559 # next if m/^(ID|RO)$/;
3561 if ($_ eq "CPAN_USERID") {
3562 $extra .= " (".$self->author;
3563 my $email; # old perls!
3564 if ($email = $CPAN::META->instance("CPAN::Author",
3567 $extra .= " <$email>";
3569 $extra .= " <no email>";
3572 } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
3573 push @m, sprintf " %-12s %s\n", $_, $self->fullname;
3576 next unless defined $self->{RO}{$_};
3577 push @m, sprintf " %-12s %s%s\n", $_, $self->{RO}{$_}, $extra;
3579 for (sort keys %$self) {
3580 next if m/^(ID|RO)$/;
3581 if (ref($self->{$_}) eq "ARRAY") {
3582 push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
3583 } elsif (ref($self->{$_}) eq "HASH") {
3587 join(" ",keys %{$self->{$_}}),
3590 push @m, sprintf " %-12s %s\n", $_, $self->{$_};
3596 #-> sub CPAN::InfoObj::author ;
3599 $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
3602 #-> sub CPAN::InfoObj::dump ;
3605 require Data::Dumper;
3606 print Data::Dumper::Dumper($self);
3609 package CPAN::Author;
3611 #-> sub CPAN::Author::id
3614 my $id = $self->{ID};
3615 $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
3619 #-> sub CPAN::Author::as_glimpse ;
3623 my $class = ref($self);
3624 $class =~ s/^CPAN:://;
3625 push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
3633 #-> sub CPAN::Author::fullname ;
3635 shift->{RO}{FULLNAME};
3639 #-> sub CPAN::Author::email ;
3640 sub email { shift->{RO}{EMAIL}; }
3642 #-> sub CPAN::Author::ls ;
3647 # adapted from CPAN::Distribution::verifyMD5 ;
3648 my(@csf); # chksumfile
3649 @csf = $self->id =~ /(.)(.)(.*)/;
3650 $csf[1] = join "", @csf[0,1];
3651 $csf[2] = join "", @csf[1,2];
3653 @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0);
3654 unless (grep {$_->[2] eq $csf[1]} @dl) {
3655 $CPAN::Frontend->myprint("No files in the directory of $id\n");
3658 @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0);
3659 unless (grep {$_->[2] eq $csf[2]} @dl) {
3660 $CPAN::Frontend->myprint("No files in the directory of $id\n");
3663 @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1);
3664 $CPAN::Frontend->myprint(join "", map {
3665 sprintf("%8d %10s %s/%s\n", $_->[0], $_->[1], $id, $_->[2])
3666 } sort { $a->[2] cmp $b->[2] } @dl);
3669 # returns an array of arrays, the latter contain (size,mtime,filename)
3670 #-> sub CPAN::Author::dir_listing ;
3673 my $chksumfile = shift;
3674 my $recursive = shift;
3676 File::Spec->catfile($CPAN::Config->{keep_source_where},
3677 "authors", "id", @$chksumfile);
3679 # connect "force" argument with "index_expire".
3681 if (my @stat = stat $lc_want) {
3682 $force = $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
3684 my $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3687 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
3688 $chksumfile->[-1] .= ".gz";
3689 $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3692 $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
3693 CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
3699 # adapted from CPAN::Distribution::MD5_check_file ;
3700 my $fh = FileHandle->new;
3702 if (open $fh, $lc_file){
3705 $eval =~ s/\015?\012/\n/g;
3707 my($comp) = Safe->new();
3708 $cksum = $comp->reval($eval);
3710 rename $lc_file, "$lc_file.bad";
3711 Carp::confess($@) if $@;
3714 Carp::carp "Could not open $lc_file for reading";
3717 for $f (sort keys %$cksum) {
3718 if (exists $cksum->{$f}{isdir}) {
3720 my(@dir) = @$chksumfile;
3722 push @dir, $f, "CHECKSUMS";
3724 [$_->[0], $_->[1], "$f/$_->[2]"]
3725 } $self->dir_listing(\@dir,1);
3727 push @result, [ 0, "-", $f ];
3731 ($cksum->{$f}{"size"}||0),
3732 $cksum->{$f}{"mtime"}||"---",
3740 package CPAN::Distribution;
3743 sub cpan_comment { shift->{RO}{CPAN_COMMENT} }
3747 delete $self->{later};
3750 # CPAN::Distribution::normalize
3753 $s = $self->id unless defined $s;
3757 $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
3759 return $s if $s =~ m:^N/A|^Contact Author: ;
3760 $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4| or
3761 $CPAN::Frontend->mywarn("Strange distribution name [$s]\n");
3762 CPAN->debug("s[$s]") if $CPAN::DEBUG;
3767 #-> sub CPAN::Distribution::color_cmd_tmps ;
3768 sub color_cmd_tmps {
3770 my($depth) = shift || 0;
3771 my($color) = shift || 0;
3772 my($ancestors) = shift || [];
3773 # a distribution needs to recurse into its prereq_pms
3775 return if exists $self->{incommandcolor}
3776 && $self->{incommandcolor}==$color;
3778 $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
3780 # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
3781 my $prereq_pm = $self->prereq_pm;
3782 if (defined $prereq_pm) {
3783 for my $pre (keys %$prereq_pm) {
3784 my $premo = CPAN::Shell->expand("Module",$pre);
3785 $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
3789 delete $self->{sponsored_mods};
3790 delete $self->{badtestcnt};
3792 $self->{incommandcolor} = $color;
3795 #-> sub CPAN::Distribution::as_string ;
3798 $self->containsmods;
3799 $self->SUPER::as_string(@_);
3802 #-> sub CPAN::Distribution::containsmods ;
3805 return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
3806 my $dist_id = $self->{ID};
3807 for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
3808 my $mod_file = $mod->cpan_file or next;
3809 my $mod_id = $mod->{ID} or next;
3810 # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
3812 $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
3814 keys %{$self->{CONTAINSMODS}};
3817 #-> sub CPAN::Distribution::uptodate ;
3821 foreach $c ($self->containsmods) {
3822 my $obj = CPAN::Shell->expandany($c);
3823 return 0 unless $obj->uptodate;
3828 #-> sub CPAN::Distribution::called_for ;
3831 $self->{CALLED_FOR} = $id if defined $id;
3832 return $self->{CALLED_FOR};
3835 #-> sub CPAN::Distribution::safe_chdir ;
3837 my($self,$todir) = @_;
3838 # we die if we cannot chdir and we are debuggable
3839 Carp::confess("safe_chdir called without todir argument")
3840 unless defined $todir and length $todir;
3842 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
3845 my $cwd = CPAN::anycwd();
3846 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
3847 qq{to todir[$todir]: $!});
3851 #-> sub CPAN::Distribution::get ;
3856 exists $self->{'build_dir'} and push @e,
3857 "Is already unwrapped into directory $self->{'build_dir'}";
3858 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
3860 my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
3863 # Get the file on local disk
3868 File::Spec->catfile(
3869 $CPAN::Config->{keep_source_where},
3872 split(/\//,$self->id)
3875 $self->debug("Doing localize") if $CPAN::DEBUG;
3876 unless ($local_file =
3877 CPAN::FTP->localize("authors/id/$self->{ID}",
3880 if ($CPAN::Index::DATE_OF_02) {
3881 $note = "Note: Current database in memory was generated ".
3882 "on $CPAN::Index::DATE_OF_02\n";
3884 $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
3886 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
3887 $self->{localfile} = $local_file;
3888 return if $CPAN::Signal;
3893 if ($CPAN::META->has_inst("Digest::MD5")) {
3894 $self->debug("Digest::MD5 is installed, verifying");
3897 $self->debug("Digest::MD5 is NOT installed");
3899 return if $CPAN::Signal;
3902 # Create a clean room and go there
3904 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
3905 my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
3906 $self->safe_chdir($builddir);
3907 $self->debug("Removing tmp") if $CPAN::DEBUG;
3908 File::Path::rmtree("tmp");
3909 mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!";
3911 $self->safe_chdir($sub_wd);
3914 $self->safe_chdir("tmp");
3919 if ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)(?!\n)\Z/i){
3920 $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3921 $self->untar_me($local_file);
3922 } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
3923 $self->unzip_me($local_file);
3924 } elsif ( $local_file =~ /\.pm\.(gz|Z)(?!\n)\Z/) {
3925 $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3926 $self->pm2dir_me($local_file);
3928 $self->{archived} = "NO";
3929 $self->safe_chdir($sub_wd);
3933 # we are still in the tmp directory!
3934 # Let's check if the package has its own directory.
3935 my $dh = DirHandle->new(File::Spec->curdir)
3936 or Carp::croak("Couldn't opendir .: $!");
3937 my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
3939 my ($distdir,$packagedir);
3940 if (@readdir == 1 && -d $readdir[0]) {
3941 $distdir = $readdir[0];
3942 $packagedir = File::Spec->catdir($builddir,$distdir);
3943 $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]")
3945 -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
3947 File::Path::rmtree($packagedir);
3948 rename($distdir,$packagedir) or
3949 Carp::confess("Couldn't rename $distdir to $packagedir: $!");
3950 $self->debug(sprintf("renamed distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
3957 my $userid = $self->cpan_userid;
3959 CPAN->debug("no userid? self[$self]");
3962 my $pragmatic_dir = $userid . '000';
3963 $pragmatic_dir =~ s/\W_//g;
3964 $pragmatic_dir++ while -d "../$pragmatic_dir";
3965 $packagedir = File::Spec->catdir($builddir,$pragmatic_dir);
3966 $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG;
3967 File::Path::mkpath($packagedir);
3969 for $f (@readdir) { # is already without "." and ".."
3970 my $to = File::Spec->catdir($packagedir,$f);
3971 rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!");
3975 $self->safe_chdir($sub_wd);
3979 $self->{'build_dir'} = $packagedir;
3980 $self->safe_chdir($builddir);
3981 File::Path::rmtree("tmp");
3983 my($mpl) = File::Spec->catfile($packagedir,"Makefile.PL");
3984 my($mpl_exists) = -f $mpl;
3985 unless ($mpl_exists) {
3986 # NFS has been reported to have racing problems after the
3987 # renaming of a directory in some environments.
3990 my $mpldh = DirHandle->new($packagedir)
3991 or Carp::croak("Couldn't opendir $packagedir: $!");
3992 $mpl_exists = grep /^Makefile\.PL$/, $mpldh->read;
3995 unless ($mpl_exists) {
3996 $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
4000 my($configure) = File::Spec->catfile($packagedir,"Configure");
4001 if (-f $configure) {
4002 # do we have anything to do?
4003 $self->{'configure'} = $configure;
4004 } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
4005 $CPAN::Frontend->myprint(qq{
4006 Package comes with a Makefile and without a Makefile.PL.
4007 We\'ll try to build it with that Makefile then.
4009 $self->{writemakefile} = "YES";
4012 my $cf = $self->called_for || "unknown";
4017 $cf =~ s|[/\\:]||g; # risk of filesystem damage
4018 $cf = "unknown" unless length($cf);
4019 $CPAN::Frontend->myprint(qq{Package seems to come without Makefile.PL.
4020 (The test -f "$mpl" returned false.)
4021 Writing one on our own (setting NAME to $cf)\a\n});
4022 $self->{had_no_makefile_pl}++;
4025 # Writing our own Makefile.PL
4027 my $fh = FileHandle->new;
4029 or Carp::croak("Could not open >$mpl: $!");
4031 qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
4032 # because there was no Makefile.PL supplied.
4033 # Autogenerated on: }.scalar localtime().qq{
4035 use ExtUtils::MakeMaker;
4036 WriteMakefile(NAME => q[$cf]);
4046 # CPAN::Distribution::untar_me ;
4048 my($self,$local_file) = @_;
4049 $self->{archived} = "tar";
4050 if (CPAN::Tarzip->untar($local_file)) {
4051 $self->{unwrapped} = "YES";
4053 $self->{unwrapped} = "NO";
4057 # CPAN::Distribution::unzip_me ;
4059 my($self,$local_file) = @_;
4060 $self->{archived} = "zip";
4061 if (CPAN::Tarzip->unzip($local_file)) {
4062 $self->{unwrapped} = "YES";
4064 $self->{unwrapped} = "NO";
4070 my($self,$local_file) = @_;
4071 $self->{archived} = "pm";
4072 my $to = File::Basename::basename($local_file);
4073 $to =~ s/\.(gz|Z)(?!\n)\Z//;
4074 if (CPAN::Tarzip->gunzip($local_file,$to)) {
4075 $self->{unwrapped} = "YES";
4077 $self->{unwrapped} = "NO";
4081 #-> sub CPAN::Distribution::new ;
4083 my($class,%att) = @_;
4085 # $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();
4087 my $this = { %att };
4088 return bless $this, $class;
4091 #-> sub CPAN::Distribution::look ;
4095 if ($^O eq 'MacOS') {
4096 $self->Mac::BuildTools::look;
4100 if ( $CPAN::Config->{'shell'} ) {
4101 $CPAN::Frontend->myprint(qq{
4102 Trying to open a subshell in the build directory...
4105 $CPAN::Frontend->myprint(qq{
4106 Your configuration does not define a value for subshells.
4107 Please define it with "o conf shell <your shell>"
4111 my $dist = $self->id;
4113 unless ($dir = $self->dir) {
4116 unless ($dir ||= $self->dir) {
4117 $CPAN::Frontend->mywarn(qq{
4118 Could not determine which directory to use for looking at $dist.
4122 my $pwd = CPAN::anycwd();
4123 $self->safe_chdir($dir);
4124 $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4125 unless (system($CPAN::Config->{'shell'}) == 0) {
4127 $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
4129 $self->safe_chdir($pwd);
4132 # CPAN::Distribution::cvs_import ;
4136 my $dir = $self->dir;
4138 my $package = $self->called_for;
4139 my $module = $CPAN::META->instance('CPAN::Module', $package);
4140 my $version = $module->cpan_version;
4142 my $userid = $self->cpan_userid;
4144 my $cvs_dir = (split /\//, $dir)[-1];
4145 $cvs_dir =~ s/-\d+[^-]+(?!\n)\Z//;
4147 $CPAN::Config->{cvsroot} || $ENV{CVSROOT};
4149 $CPAN::Config->{cvs_site_perl} || $ENV{CVS_SITE_PERL};
4150 if ($cvs_site_perl) {
4151 $cvs_dir = "$cvs_site_perl/$cvs_dir";
4153 my $cvs_log = qq{"imported $package $version sources"};
4154 $version =~ s/\./_/g;
4155 my @cmd = ('cvs', '-d', $cvs_root, 'import', '-m', $cvs_log,
4156 "$cvs_dir", $userid, "v$version");
4158 my $pwd = CPAN::anycwd();
4159 chdir($dir) or $CPAN::Frontend->mydie(qq{Could not chdir to "$dir": $!});
4161 $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4163 $CPAN::Frontend->myprint(qq{@cmd\n});
4164 system(@cmd) == 0 or
4165 $CPAN::Frontend->mydie("cvs import failed");
4166 chdir($pwd) or $CPAN::Frontend->mydie(qq{Could not chdir to "$pwd": $!});
4169 #-> sub CPAN::Distribution::readme ;
4172 my($dist) = $self->id;
4173 my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/;
4174 $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG;
4177 File::Spec->catfile(
4178 $CPAN::Config->{keep_source_where},
4181 split(/\//,"$sans.readme"),
4183 $self->debug("Doing localize") if $CPAN::DEBUG;
4184 $local_file = CPAN::FTP->localize("authors/id/$sans.readme",
4186 or $CPAN::Frontend->mydie(qq{No $sans.readme found});;
4188 if ($^O eq 'MacOS') {
4189 Mac::BuildTools::launch_file($local_file);
4193 my $fh_pager = FileHandle->new;
4194 local($SIG{PIPE}) = "IGNORE";
4195 $fh_pager->open("|$CPAN::Config->{'pager'}")
4196 or die "Could not open pager $CPAN::Config->{'pager'}: $!";
4197 my $fh_readme = FileHandle->new;
4198 $fh_readme->open($local_file)
4199 or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!});
4200 $CPAN::Frontend->myprint(qq{
4203 with pager "$CPAN::Config->{'pager'}"
4206 $fh_pager->print(<$fh_readme>);
4209 #-> sub CPAN::Distribution::verifyMD5 ;
4214 $self->{MD5_STATUS} ||= "";
4215 $self->{MD5_STATUS} eq "OK" and push @e, "MD5 Checksum was ok";
4216 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4218 my($lc_want,$lc_file,@local,$basename);
4219 @local = split(/\//,$self->id);
4221 push @local, "CHECKSUMS";
4223 File::Spec->catfile($CPAN::Config->{keep_source_where},
4224 "authors", "id", @local);
4229 $self->MD5_check_file($lc_want)
4231 return $self->{MD5_STATUS} = "OK";
4233 $lc_file = CPAN::FTP->localize("authors/id/@local",
4236 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
4237 $local[-1] .= ".gz";
4238 $lc_file = CPAN::FTP->localize("authors/id/@local",
4241 $lc_file =~ s/\.gz(?!\n)\Z//;
4242 CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
4247 $self->MD5_check_file($lc_file);
4250 #-> sub CPAN::Distribution::MD5_check_file ;
4251 sub MD5_check_file {
4252 my($self,$chk_file) = @_;
4253 my($cksum,$file,$basename);
4254 $file = $self->{localfile};
4255 $basename = File::Basename::basename($file);
4256 my $fh = FileHandle->new;
4257 if (open $fh, $chk_file){
4260 $eval =~ s/\015?\012/\n/g;
4262 my($comp) = Safe->new();
4263 $cksum = $comp->reval($eval);
4265 rename $chk_file, "$chk_file.bad";
4266 Carp::confess($@) if $@;
4269 Carp::carp "Could not open $chk_file for reading";
4272 if (exists $cksum->{$basename}{md5}) {
4273 $self->debug("Found checksum for $basename:" .
4274 "$cksum->{$basename}{md5}\n") if $CPAN::DEBUG;
4278 my $eq = $self->eq_MD5($fh,$cksum->{$basename}{'md5'});
4280 $fh = CPAN::Tarzip->TIEHANDLE($file);
4283 # had to inline it, when I tied it, the tiedness got lost on
4284 # the call to eq_MD5. (Jan 1998)
4285 my $md5 = Digest::MD5->new;
4288 while ($fh->READ($ref, 4096) > 0){
4291 my $hexdigest = $md5->hexdigest;
4292 $eq += $hexdigest eq $cksum->{$basename}{'md5-ungz'};
4296 $CPAN::Frontend->myprint("Checksum for $file ok\n");
4297 return $self->{MD5_STATUS} = "OK";
4299 $CPAN::Frontend->myprint(qq{\nChecksum mismatch for }.
4300 qq{distribution file. }.
4301 qq{Please investigate.\n\n}.
4303 $CPAN::META->instance(
4308 my $wrap = qq{I\'d recommend removing $file. Its MD5
4309 checksum is incorrect. Maybe you have configured your 'urllist' with
4310 a bad URL. Please check this array with 'o conf urllist', and
4313 $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
4315 # former versions just returned here but this seems a
4316 # serious threat that deserves a die
4318 # $CPAN::Frontend->myprint("\n\n");
4322 # close $fh if fileno($fh);
4324 $self->{MD5_STATUS} ||= "";
4325 if ($self->{MD5_STATUS} eq "NIL") {
4326 $CPAN::Frontend->mywarn(qq{
4327 Warning: No md5 checksum for $basename in $chk_file.
4329 The cause for this may be that the file is very new and the checksum
4330 has not yet been calculated, but it may also be that something is
4331 going awry right now.
4333 my $answer = ExtUtils::MakeMaker::prompt("Proceed?", "yes");
4334 $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.");
4336 $self->{MD5_STATUS} = "NIL";
4341 #-> sub CPAN::Distribution::eq_MD5 ;
4343 my($self,$fh,$expectMD5) = @_;
4344 my $md5 = Digest::MD5->new;
4346 while (read($fh, $data, 4096)){
4349 # $md5->addfile($fh);
4350 my $hexdigest = $md5->hexdigest;
4351 # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]";
4352 $hexdigest eq $expectMD5;
4355 #-> sub CPAN::Distribution::force ;
4357 # Both modules and distributions know if "force" is in effect by
4358 # autoinspection, not by inspecting a global variable. One of the
4359 # reason why this was chosen to work that way was the treatment of
4360 # dependencies. They should not autpomatically inherit the force
4361 # status. But this has the downside that ^C and die() will return to
4362 # the prompt but will not be able to reset the force_update
4363 # attributes. We try to correct for it currently in the read_metadata
4364 # routine, and immediately before we check for a Signal. I hope this
4365 # works out in one of v1.57_53ff
4368 my($self, $method) = @_;
4370 MD5_STATUS archived build_dir localfile make install unwrapped
4373 delete $self->{$att};
4375 if ($method && $method eq "install") {
4376 $self->{"force_update"}++; # name should probably have been force_install
4380 #-> sub CPAN::Distribution::unforce ;
4383 delete $self->{'force_update'};
4386 #-> sub CPAN::Distribution::isa_perl ;
4389 my $file = File::Basename::basename($self->id);
4390 if ($file =~ m{ ^ perl
4403 } elsif ($self->cpan_comment
4405 $self->cpan_comment =~ /isa_perl\(.+?\)/){
4410 #-> sub CPAN::Distribution::perl ;
4413 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
4414 my $pwd = CPAN::anycwd();
4415 my $candidate = File::Spec->catfile($pwd,$^X);
4416 $perl ||= $candidate if MM->maybe_command($candidate);
4418 my ($component,$perl_name);
4419 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
4420 PATH_COMPONENT: foreach $component (File::Spec->path(),
4421 $Config::Config{'binexp'}) {
4422 next unless defined($component) && $component;
4423 my($abs) = File::Spec->catfile($component,$perl_name);
4424 if (MM->maybe_command($abs)) {
4434 #-> sub CPAN::Distribution::make ;
4437 $CPAN::Frontend->myprint(sprintf "Running make for %s\n", $self->id);
4438 # Emergency brake if they said install Pippi and get newest perl
4439 if ($self->isa_perl) {
4441 $self->called_for ne $self->id &&
4442 ! $self->{force_update}
4444 # if we die here, we break bundles
4445 $CPAN::Frontend->mywarn(sprintf qq{
4446 The most recent version "%s" of the module "%s"
4447 comes with the current version of perl (%s).
4448 I\'ll build that only if you ask for something like
4453 $CPAN::META->instance(
4467 $self->{archived} eq "NO" and push @e,
4468 "Is neither a tar nor a zip archive.";
4470 $self->{unwrapped} eq "NO" and push @e,
4471 "had problems unarchiving. Please build manually";
4473 exists $self->{writemakefile} &&
4474 $self->{writemakefile} =~ m/ ^ NO\s* ( .* ) /sx and push @e,
4475 $1 || "Had some problem writing Makefile";
4477 defined $self->{'make'} and push @e,
4478 "Has already been processed within this session";
4480 exists $self->{later} and length($self->{later}) and
4481 push @e, $self->{later};
4483 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4485 $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n");
4486 my $builddir = $self->dir;
4487 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
4488 $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;
4490 if ($^O eq 'MacOS') {
4491 Mac::BuildTools::make($self);
4496 if ($self->{'configure'}) {
4497 $system = $self->{'configure'};
4499 my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
4501 # This needs a handler that can be turned on or off:
4502 # $switch = "-MExtUtils::MakeMaker ".
4503 # "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
4505 $system = "$perl $switch Makefile.PL $CPAN::Config->{makepl_arg}";
4507 unless (exists $self->{writemakefile}) {
4508 local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
4511 if ($CPAN::Config->{inactivity_timeout}) {
4513 alarm $CPAN::Config->{inactivity_timeout};
4514 local $SIG{CHLD}; # = sub { wait };
4515 if (defined($pid = fork)) {
4520 # note, this exec isn't necessary if
4521 # inactivity_timeout is 0. On the Mac I'd
4522 # suggest, we set it always to 0.
4526 $CPAN::Frontend->myprint("Cannot fork: $!");