1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
4 # $Id: CPAN.pm,v 1.412 2003/07/31 14:53:04 k Exp $
6 # only used during development:
8 # $Revision = "[".substr(q$Revision: 1.412 $, 10)."]";
15 use ExtUtils::MakeMaker (); # $SelfLoader::DEBUG=1;
16 use File::Basename ();
22 use Text::ParseWords ();
26 no lib "."; # we need to run chdir all over and we would get at wrong
29 require Mac::BuildTools if $^O eq 'MacOS';
31 END { $End++; &cleanup; }
54 $CPAN::Frontend ||= "CPAN::Shell";
55 $CPAN::Defaultsite ||= "ftp://ftp.perl.org/pub/CPAN";
60 use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $HAS_USABLE $term
61 $Revision $Signal $End $Suppress_readline $Frontend
62 $Defaultsite $Have_warned);
64 @CPAN::ISA = qw(CPAN::Debug Exporter);
67 autobundle bundle expand force get cvs_import
68 install make readme recompile shell test clean
71 #-> sub CPAN::AUTOLOAD ;
76 @EXPORT{@EXPORT} = '';
77 CPAN::Config->load unless $CPAN::Config_loaded++;
78 if (exists $EXPORT{$l}){
81 $CPAN::Frontend->mywarn(qq{Unknown command "$AUTOLOAD". }.
90 $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
91 CPAN::Config->load unless $CPAN::Config_loaded++;
93 my $oprompt = shift || "cpan> ";
94 my $prompt = $oprompt;
95 my $commandline = shift || "";
98 unless ($Suppress_readline) {
99 require Term::ReadLine;
102 $term->ReadLine eq "Term::ReadLine::Stub"
104 $term = Term::ReadLine->new('CPAN Monitor');
106 if ($term->ReadLine eq "Term::ReadLine::Gnu") {
107 my $attribs = $term->Attribs;
108 $attribs->{attempted_completion_function} = sub {
109 &CPAN::Complete::gnu_cpl;
112 $readline::rl_completion_function =
113 $readline::rl_completion_function = 'CPAN::Complete::cpl';
115 if (my $histfile = $CPAN::Config->{'histfile'}) {{
116 unless ($term->can("AddHistory")) {
117 $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
120 my($fh) = FileHandle->new;
121 open $fh, "<$histfile" or last;
125 $term->AddHistory($_);
129 # $term->OUT is autoflushed anyway
130 my $odef = select STDERR;
137 # no strict; # I do not recall why no strict was here (2000-09-03)
139 my $cwd = CPAN::anycwd();
140 my $try_detect_readline;
141 $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
142 my $rl_avail = $Suppress_readline ? "suppressed" :
143 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
144 "available (try 'install Bundle::CPAN')";
146 $CPAN::Frontend->myprint(
148 cpan shell -- CPAN exploration and modules installation (v%s%s)
156 unless $CPAN::Config->{'inhibit_startup_message'} ;
157 my($continuation) = "";
158 SHELLCOMMAND: while () {
159 if ($Suppress_readline) {
161 last SHELLCOMMAND unless defined ($_ = <> );
164 last SHELLCOMMAND unless
165 defined ($_ = $term->readline($prompt, $commandline));
167 $_ = "$continuation$_" if $continuation;
169 next SHELLCOMMAND if /^$/;
170 $_ = 'h' if /^\s*\?/;
171 if (/^(?:q(?:uit)?|bye|exit)$/i) {
181 use vars qw($import_done);
182 CPAN->import(':DEFAULT') unless $import_done++;
183 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
190 if ($] < 5.00322) { # parsewords had a bug until recently
193 eval { @line = Text::ParseWords::shellwords($_) };
194 warn($@), next SHELLCOMMAND if $@;
195 warn("Text::Parsewords could not parse the line [$_]"),
196 next SHELLCOMMAND unless @line;
198 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
199 my $command = shift @line;
200 eval { CPAN::Shell->$command(@line) };
202 chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
203 $CPAN::Frontend->myprint("\n");
208 $commandline = ""; # I do want to be able to pass a default to
209 # shell, but on the second command I see no
212 CPAN::Queue->nullify_queue;
213 if ($try_detect_readline) {
214 if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
216 $CPAN::META->has_inst("Term::ReadLine::Perl")
218 delete $INC{"Term/ReadLine.pm"};
220 local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
221 require Term::ReadLine;
222 $CPAN::Frontend->myprint("\n$redef subroutines in ".
223 "Term::ReadLine redefined\n");
229 chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
232 package CPAN::CacheMgr;
233 @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
236 package CPAN::Config;
237 use vars qw(%can $dot_cpan);
240 'commit' => "Commit changes to disk",
241 'defaults' => "Reload defaults from disk",
242 'init' => "Interactive setting of all options",
246 use vars qw($Ua $Thesite $Themethod);
247 @CPAN::FTP::ISA = qw(CPAN::Debug);
249 package CPAN::LWP::UserAgent;
250 use vars qw(@ISA $USER $PASSWD $SETUPDONE);
251 # we delay requiring LWP::UserAgent and setting up inheritence until we need it
253 package CPAN::Complete;
254 @CPAN::Complete::ISA = qw(CPAN::Debug);
255 @CPAN::Complete::COMMANDS = sort qw(
256 ! a b d h i m o q r u autobundle clean dump
257 make test install force readme reload look
259 ) unless @CPAN::Complete::COMMANDS;
262 use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
263 @CPAN::Index::ISA = qw(CPAN::Debug);
266 # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
269 package CPAN::InfoObj;
270 @CPAN::InfoObj::ISA = qw(CPAN::Debug);
272 package CPAN::Author;
273 @CPAN::Author::ISA = qw(CPAN::InfoObj);
275 package CPAN::Distribution;
276 @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
278 package CPAN::Bundle;
279 @CPAN::Bundle::ISA = qw(CPAN::Module);
281 package CPAN::Module;
282 @CPAN::Module::ISA = qw(CPAN::InfoObj);
284 package CPAN::Exception::RecursiveDependency;
285 use overload '""' => "as_string";
292 for my $dep (@$deps) {
294 last if $seen{$dep}++;
296 bless { deps => \@deps }, $class;
301 "\nRecursive dependency detected:\n " .
302 join("\n => ", @{$self->{deps}}) .
303 ".\nCannot continue.\n";
307 use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
308 @CPAN::Shell::ISA = qw(CPAN::Debug);
309 $COLOR_REGISTERED ||= 0;
310 $PRINT_ORNAMENTING ||= 0;
312 #-> sub CPAN::Shell::AUTOLOAD ;
314 my($autoload) = $AUTOLOAD;
315 my $class = shift(@_);
316 # warn "autoload[$autoload] class[$class]";
317 $autoload =~ s/.*:://;
318 if ($autoload =~ /^w/) {
319 if ($CPAN::META->has_inst('CPAN::WAIT')) {
320 CPAN::WAIT->$autoload(@_);
322 $CPAN::Frontend->mywarn(qq{
323 Commands starting with "w" require CPAN::WAIT to be installed.
324 Please consider installing CPAN::WAIT to use the fulltext index.
325 For this you just need to type
330 $CPAN::Frontend->mywarn(qq{Unknown command '$autoload'. }.
336 package CPAN::Tarzip;
337 use vars qw($AUTOLOAD @ISA $BUGHUNTING);
338 @CPAN::Tarzip::ISA = qw(CPAN::Debug);
339 $BUGHUNTING = 0; # released code must have turned off
343 # One use of the queue is to determine if we should or shouldn't
344 # announce the availability of a new CPAN module
346 # Now we try to use it for dependency tracking. For that to happen
347 # we need to draw a dependency tree and do the leaves first. This can
348 # easily be reached by running CPAN.pm recursively, but we don't want
349 # to waste memory and run into deep recursion. So what we can do is
352 # CPAN::Queue is the package where the queue is maintained. Dependencies
353 # often have high priority and must be brought to the head of the queue,
354 # possibly by jumping the queue if they are already there. My first code
355 # attempt tried to be extremely correct. Whenever a module needed
356 # immediate treatment, I either unshifted it to the front of the queue,
357 # or, if it was already in the queue, I spliced and let it bypass the
358 # others. This became a too correct model that made it impossible to put
359 # an item more than once into the queue. Why would you need that? Well,
360 # you need temporary duplicates as the manager of the queue is a loop
363 # (1) looks at the first item in the queue without shifting it off
365 # (2) cares for the item
367 # (3) removes the item from the queue, *even if its agenda failed and
368 # even if the item isn't the first in the queue anymore* (that way
369 # protecting against never ending queues)
371 # So if an item has prerequisites, the installation fails now, but we
372 # want to retry later. That's easy if we have it twice in the queue.
374 # I also expect insane dependency situations where an item gets more
375 # than two lives in the queue. Simplest example is triggered by 'install
376 # Foo Foo Foo'. People make this kind of mistakes and I don't want to
377 # get in the way. I wanted the queue manager to be a dumb servant, not
378 # one that knows everything.
380 # Who would I tell in this model that the user wants to be asked before
381 # processing? I can't attach that information to the module object,
382 # because not modules are installed but distributions. So I'd have to
383 # tell the distribution object that it should ask the user before
384 # processing. Where would the question be triggered then? Most probably
385 # in CPAN::Distribution::rematein.
386 # Hope that makes sense, my head is a bit off:-) -- AK
393 my $self = bless { qmod => $s }, $class;
398 # CPAN::Queue::first ;
404 # CPAN::Queue::delete_first ;
406 my($class,$what) = @_;
408 for my $i (0..$#All) {
409 if ( $All[$i]->{qmod} eq $what ) {
416 # CPAN::Queue::jumpqueue ;
420 CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
421 join(",",map {$_->{qmod}} @All),
424 WHAT: for my $what (reverse @what) {
426 for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
427 CPAN->debug("i[$All[$i]]what[$what]") if $CPAN::DEBUG;
428 if ($All[$i]->{qmod} eq $what){
430 if ($jumped > 100) { # one's OK if e.g. just
431 # processing now; more are OK if
432 # user typed it several times
433 $CPAN::Frontend->mywarn(
434 qq{Object [$what] queued more than 100 times, ignoring}
440 my $obj = bless { qmod => $what }, $class;
443 CPAN->debug(sprintf("after jumpqueue All[%s] what[%s]",
444 join(",",map {$_->{qmod}} @All),
449 # CPAN::Queue::exists ;
451 my($self,$what) = @_;
452 my @all = map { $_->{qmod} } @All;
453 my $exists = grep { $_->{qmod} eq $what } @All;
454 # warn "in exists what[$what] all[@all] exists[$exists]";
458 # CPAN::Queue::delete ;
461 @All = grep { $_->{qmod} ne $mod } @All;
464 # CPAN::Queue::nullify_queue ;
473 $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
475 # from here on only subs.
476 ################################################################################
478 #-> sub CPAN::all_objects ;
480 my($mgr,$class) = @_;
481 CPAN::Config->load unless $CPAN::Config_loaded++;
482 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
484 values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
486 *all = \&all_objects;
488 # Called by shell, not in batch mode. In batch mode I see no risk in
489 # having many processes updating something as installations are
490 # continually checked at runtime. In shell mode I suspect it is
491 # unintentional to open more than one shell at a time
493 #-> sub CPAN::checklock ;
496 my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
497 if (-f $lockfile && -M _ > 0) {
498 my $fh = FileHandle->new($lockfile) or
499 $CPAN::Frontend->mydie("Could not open $lockfile: $!");
500 my $otherpid = <$fh>;
501 my $otherhost = <$fh>;
503 if (defined $otherpid && $otherpid) {
506 if (defined $otherhost && $otherhost) {
509 my $thishost = hostname();
510 if (defined $otherhost && defined $thishost &&
511 $otherhost ne '' && $thishost ne '' &&
512 $otherhost ne $thishost) {
513 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
514 "reports other host $otherhost and other process $otherpid.\n".
515 "Cannot proceed.\n"));
517 elsif (defined $otherpid && $otherpid) {
518 return if $$ == $otherpid; # should never happen
519 $CPAN::Frontend->mywarn(
521 There seems to be running another CPAN process (pid $otherpid). Contacting...
523 if (kill 0, $otherpid) {
524 $CPAN::Frontend->mydie(qq{Other job is running.
525 You may want to kill it and delete the lockfile, maybe. On UNIX try:
529 } elsif (-w $lockfile) {
531 ExtUtils::MakeMaker::prompt
532 (qq{Other job not responding. Shall I overwrite }.
533 qq{the lockfile? (Y/N)},"y");
534 $CPAN::Frontend->myexit("Ok, bye\n")
535 unless $ans =~ /^y/i;
538 qq{Lockfile $lockfile not writeable by you. }.
539 qq{Cannot proceed.\n}.
542 qq{ and then rerun us.\n}
546 $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
547 "reports other process with ID ".
548 "$otherpid. Cannot proceed.\n"));
551 my $dotcpan = $CPAN::Config->{cpan_home};
552 eval { File::Path::mkpath($dotcpan);};
554 # A special case at least for Jarkko.
559 $symlinkcpan = readlink $dotcpan;
560 die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
561 eval { File::Path::mkpath($symlinkcpan); };
565 $CPAN::Frontend->mywarn(qq{
566 Working directory $symlinkcpan created.
570 unless (-d $dotcpan) {
572 Your configuration suggests "$dotcpan" as your
573 CPAN.pm working directory. I could not create this directory due
574 to this error: $firsterror\n};
576 As "$dotcpan" is a symlink to "$symlinkcpan",
577 I tried to create that, but I failed with this error: $seconderror
580 Please make sure the directory exists and is writable.
582 $CPAN::Frontend->mydie($diemess);
586 unless ($fh = FileHandle->new(">$lockfile")) {
587 if ($! =~ /Permission/) {
588 my $incc = $INC{'CPAN/Config.pm'};
589 my $myincc = File::Spec->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
590 $CPAN::Frontend->myprint(qq{
592 Your configuration suggests that CPAN.pm should use a working
594 $CPAN::Config->{cpan_home}
595 Unfortunately we could not create the lock file
597 due to permission problems.
599 Please make sure that the configuration variable
600 \$CPAN::Config->{cpan_home}
601 points to a directory where you can write a .lock file. You can set
602 this variable in either
609 $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
611 $fh->print($$, "\n");
612 $fh->print(hostname(), "\n");
613 $self->{LOCK} = $lockfile;
617 $CPAN::Frontend->mydie("Got SIGTERM, leaving");
622 $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
623 print "Caught SIGINT\n";
627 # From: Larry Wall <larry@wall.org>
628 # Subject: Re: deprecating SIGDIE
629 # To: perl5-porters@perl.org
630 # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
632 # The original intent of __DIE__ was only to allow you to substitute one
633 # kind of death for another on an application-wide basis without respect
634 # to whether you were in an eval or not. As a global backstop, it should
635 # not be used any more lightly (or any more heavily :-) than class
636 # UNIVERSAL. Any attempt to build a general exception model on it should
637 # be politely squashed. Any bug that causes every eval {} to have to be
638 # modified should be not so politely squashed.
640 # Those are my current opinions. It is also my optinion that polite
641 # arguments degenerate to personal arguments far too frequently, and that
642 # when they do, it's because both people wanted it to, or at least didn't
643 # sufficiently want it not to.
647 # global backstop to cleanup if we should really die
648 $SIG{__DIE__} = \&cleanup;
649 $self->debug("Signal handler set.") if $CPAN::DEBUG;
652 #-> sub CPAN::DESTROY ;
654 &cleanup; # need an eval?
657 #-> sub CPAN::anycwd ;
660 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
665 sub cwd {Cwd::cwd();}
667 #-> sub CPAN::getcwd ;
668 sub getcwd {Cwd::getcwd();}
670 #-> sub CPAN::exists ;
672 my($mgr,$class,$id) = @_;
673 CPAN::Config->load unless $CPAN::Config_loaded++;
675 ### Carp::croak "exists called without class argument" unless $class;
677 exists $META->{readonly}{$class}{$id} or
678 exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
681 #-> sub CPAN::delete ;
683 my($mgr,$class,$id) = @_;
684 delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
685 delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
688 #-> sub CPAN::has_usable
689 # has_inst is sometimes too optimistic, we should replace it with this
690 # has_usable whenever a case is given
692 my($self,$mod,$message) = @_;
693 return 1 if $HAS_USABLE->{$mod};
694 my $has_inst = $self->has_inst($mod,$message);
695 return unless $has_inst;
698 LWP => [ # we frequently had "Can't locate object
699 # method "new" via package "LWP::UserAgent" at
700 # (eval 69) line 2006
702 sub {require LWP::UserAgent},
703 sub {require HTTP::Request},
704 sub {require URI::URL},
707 sub {require Net::FTP},
708 sub {require Net::Config},
711 if ($usable->{$mod}) {
712 for my $c (0..$#{$usable->{$mod}}) {
713 my $code = $usable->{$mod}[$c];
714 my $ret = eval { &$code() };
716 warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
721 return $HAS_USABLE->{$mod} = 1;
724 #-> sub CPAN::has_inst
726 my($self,$mod,$message) = @_;
727 Carp::croak("CPAN->has_inst() called without an argument")
729 if (defined $message && $message eq "no"
731 exists $CPAN::META->{dontload_hash}{$mod} # unsafe meta access, ok
733 exists $CPAN::Config->{dontload_hash}{$mod}
735 $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
741 $file =~ s|/|\\|g if $^O eq 'MSWin32';
744 # checking %INC is wrong, because $INC{LWP} may be true
745 # although $INC{"URI/URL.pm"} may have failed. But as
746 # I really want to say "bla loaded OK", I have to somehow
748 ### warn "$file in %INC"; #debug
750 } elsif (eval { require $file }) {
751 # eval is good: if we haven't yet read the database it's
752 # perfect and if we have installed the module in the meantime,
753 # it tries again. The second require is only a NOOP returning
754 # 1 if we had success, otherwise it's retrying
756 $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
757 if ($mod eq "CPAN::WAIT") {
758 push @CPAN::Shell::ISA, CPAN::WAIT;
761 } elsif ($mod eq "Net::FTP") {
762 $CPAN::Frontend->mywarn(qq{
763 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
765 install Bundle::libnet
767 }) unless $Have_warned->{"Net::FTP"}++;
769 } elsif ($mod eq "Digest::MD5"){
770 $CPAN::Frontend->myprint(qq{
771 CPAN: MD5 security checks disabled because Digest::MD5 not installed.
772 Please consider installing the Digest::MD5 module.
777 delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
782 #-> sub CPAN::instance ;
784 my($mgr,$class,$id) = @_;
787 # unsafe meta access, ok?
788 return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
789 $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
797 #-> sub CPAN::cleanup ;
799 # warn "cleanup called with arg[@_] End[$End] Signal[$Signal]";
800 local $SIG{__DIE__} = '';
805 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
807 $subroutine eq '(eval)';
809 return if $ineval && !$End;
810 return unless defined $META->{LOCK};
811 return unless -f $META->{LOCK};
813 unlink $META->{LOCK};
815 # Carp::cluck("DEBUGGING");
816 $CPAN::Frontend->mywarn("Lockfile removed.\n");
819 #-> sub CPAN::savehist
822 my($histfile,$histsize);
823 unless ($histfile = $CPAN::Config->{'histfile'}){
824 $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
827 $histsize = $CPAN::Config->{'histsize'} || 100;
829 unless ($CPAN::term->can("GetHistory")) {
830 $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
836 my @h = $CPAN::term->GetHistory;
837 splice @h, 0, @h-$histsize if @h>$histsize;
838 my($fh) = FileHandle->new;
839 open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
840 local $\ = local $, = "\n";
846 my($self,$what) = @_;
847 $self->{is_tested}{$what} = 1;
851 my($self,$what) = @_;
852 delete $self->{is_tested}{$what};
857 $self->{is_tested} ||= {};
858 return unless %{$self->{is_tested}};
859 my $env = $ENV{PERL5LIB};
860 $env = $ENV{PERLLIB} unless defined $env;
862 push @env, $env if defined $env and length $env;
863 my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
864 $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
865 $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
868 package CPAN::CacheMgr;
870 #-> sub CPAN::CacheMgr::as_string ;
872 eval { require Data::Dumper };
874 return shift->SUPER::as_string;
876 return Data::Dumper::Dumper(shift);
880 #-> sub CPAN::CacheMgr::cachesize ;
885 #-> sub CPAN::CacheMgr::tidyup ;
888 return unless -d $self->{ID};
889 while ($self->{DU} > $self->{'MAX'} ) {
890 my($toremove) = shift @{$self->{FIFO}};
891 $CPAN::Frontend->myprint(sprintf(
892 "Deleting from cache".
893 ": $toremove (%.1f>%.1f MB)\n",
894 $self->{DU}, $self->{'MAX'})
896 return if $CPAN::Signal;
897 $self->force_clean_cache($toremove);
898 return if $CPAN::Signal;
902 #-> sub CPAN::CacheMgr::dir ;
907 #-> sub CPAN::CacheMgr::entries ;
910 return unless defined $dir;
911 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
912 $dir ||= $self->{ID};
913 my($cwd) = CPAN::anycwd();
914 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
915 my $dh = DirHandle->new(File::Spec->curdir)
916 or Carp::croak("Couldn't opendir $dir: $!");
919 next if $_ eq "." || $_ eq "..";
921 push @entries, File::Spec->catfile($dir,$_);
923 push @entries, File::Spec->catdir($dir,$_);
925 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
928 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
929 sort { -M $b <=> -M $a} @entries;
932 #-> sub CPAN::CacheMgr::disk_usage ;
935 return if exists $self->{SIZE}{$dir};
936 return if $CPAN::Signal;
940 $File::Find::prune++ if $CPAN::Signal;
942 if ($^O eq 'MacOS') {
944 my $cat = Mac::Files::FSpGetCatInfo($_);
945 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
952 return if $CPAN::Signal;
953 $self->{SIZE}{$dir} = $Du/1024/1024;
954 push @{$self->{FIFO}}, $dir;
955 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
956 $self->{DU} += $Du/1024/1024;
960 #-> sub CPAN::CacheMgr::force_clean_cache ;
961 sub force_clean_cache {
963 return unless -e $dir;
964 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
966 File::Path::rmtree($dir);
967 $self->{DU} -= $self->{SIZE}{$dir};
968 delete $self->{SIZE}{$dir};
971 #-> sub CPAN::CacheMgr::new ;
978 ID => $CPAN::Config->{'build_dir'},
979 MAX => $CPAN::Config->{'build_cache'},
980 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
983 File::Path::mkpath($self->{ID});
984 my $dh = DirHandle->new($self->{ID});
988 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
990 CPAN->debug($debug) if $CPAN::DEBUG;
994 #-> sub CPAN::CacheMgr::scan_cache ;
997 return if $self->{SCAN} eq 'never';
998 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
999 unless $self->{SCAN} eq 'atstart';
1000 $CPAN::Frontend->myprint(
1001 sprintf("Scanning cache %s for sizes\n",
1004 for $e ($self->entries($self->{ID})) {
1005 next if $e eq ".." || $e eq ".";
1006 $self->disk_usage($e);
1007 return if $CPAN::Signal;
1012 package CPAN::Debug;
1014 #-> sub CPAN::Debug::debug ;
1016 my($self,$arg) = @_;
1017 my($caller,$func,$line,@rest) = caller(1); # caller(0) eg
1018 # Complete, caller(1)
1020 ($caller) = caller(0);
1021 $caller =~ s/.*:://;
1022 $arg = "" unless defined $arg;
1023 my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest;
1024 if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){
1025 if ($arg and ref $arg) {
1026 eval { require Data::Dumper };
1028 $CPAN::Frontend->myprint($arg->as_string);
1030 $CPAN::Frontend->myprint(Data::Dumper::Dumper($arg));
1033 $CPAN::Frontend->myprint("Debug($caller:$func,$line,[$rest]): $arg\n");
1038 package CPAN::Config;
1040 #-> sub CPAN::Config::edit ;
1041 # returns true on successful action
1043 my($self,@args) = @_;
1044 return unless @args;
1045 CPAN->debug("self[$self]args[".join(" | ",@args)."]");
1046 my($o,$str,$func,$args,$key_exists);
1052 CPAN->debug("o[$o]") if $CPAN::DEBUG;
1053 if ($o =~ /list$/) {
1054 $func = shift @args;
1056 CPAN->debug("func[$func]") if $CPAN::DEBUG;
1058 # Let's avoid eval, it's easier to comprehend without.
1059 if ($func eq "push") {
1060 push @{$CPAN::Config->{$o}}, @args;
1062 } elsif ($func eq "pop") {
1063 pop @{$CPAN::Config->{$o}};
1065 } elsif ($func eq "shift") {
1066 shift @{$CPAN::Config->{$o}};
1068 } elsif ($func eq "unshift") {
1069 unshift @{$CPAN::Config->{$o}}, @args;
1071 } elsif ($func eq "splice") {
1072 splice @{$CPAN::Config->{$o}}, @args;
1075 $CPAN::Config->{$o} = [@args];
1078 $self->prettyprint($o);
1080 if ($o eq "urllist" && $changed) {
1081 # reset the cached values
1082 undef $CPAN::FTP::Thesite;
1083 undef $CPAN::FTP::Themethod;
1087 $CPAN::Config->{$o} = $args[0] if defined $args[0];
1088 $self->prettyprint($o);
1095 my $v = $CPAN::Config->{$k};
1097 my(@report) = ref $v eq "ARRAY" ?
1099 map { sprintf(" %-18s => %s\n",
1101 defined $v->{$_} ? $v->{$_} : "UNDEFINED"
1103 $CPAN::Frontend->myprint(
1110 map {"\t$_\n"} @report
1113 } elsif (defined $v) {
1114 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1116 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, "UNDEFINED");
1120 #-> sub CPAN::Config::commit ;
1122 my($self,$configpm) = @_;
1123 unless (defined $configpm){
1124 $configpm ||= $INC{"CPAN/MyConfig.pm"};
1125 $configpm ||= $INC{"CPAN/Config.pm"};
1126 $configpm || Carp::confess(q{
1127 CPAN::Config::commit called without an argument.
1128 Please specify a filename where to save the configuration or try
1129 "o conf init" to have an interactive course through configing.
1134 $mode = (stat $configpm)[2];
1135 if ($mode && ! -w _) {
1136 Carp::confess("$configpm is not writable");
1141 $msg = <<EOF unless $configpm =~ /MyConfig/;
1143 # This is CPAN.pm's systemwide configuration file. This file provides
1144 # defaults for users, and the values can be changed in a per-user
1145 # configuration file. The user-config file is being looked for as
1146 # ~/.cpan/CPAN/MyConfig.pm.
1150 my($fh) = FileHandle->new;
1151 rename $configpm, "$configpm~" if -f $configpm;
1152 open $fh, ">$configpm" or
1153 $CPAN::Frontend->mydie("Couldn't open >$configpm: $!");
1154 $fh->print(qq[$msg\$CPAN::Config = \{\n]);
1155 foreach (sort keys %$CPAN::Config) {
1158 ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$_}),
1163 $fh->print("};\n1;\n__END__\n");
1166 #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
1167 #chmod $mode, $configpm;
1168 ###why was that so? $self->defaults;
1169 $CPAN::Frontend->myprint("commit: wrote $configpm\n");
1173 *default = \&defaults;
1174 #-> sub CPAN::Config::defaults ;
1184 undef $CPAN::Config->{'inhibit_startup_message'}; # lazy trick to
1193 # This is a piece of repeated code that is abstracted here for
1194 # maintainability. RMB
1197 my($configpmdir, $configpmtest) = @_;
1198 if (-w $configpmtest) {
1199 return $configpmtest;
1200 } elsif (-w $configpmdir) {
1201 #_#_# following code dumped core on me with 5.003_11, a.k.
1202 my $configpm_bak = "$configpmtest.bak";
1203 unlink $configpm_bak if -f $configpm_bak;
1204 if( -f $configpmtest ) {
1205 if( rename $configpmtest, $configpm_bak ) {
1206 $CPAN::Frontend->mywarn(<<END)
1207 Old configuration file $configpmtest
1208 moved to $configpm_bak
1212 my $fh = FileHandle->new;
1213 if ($fh->open(">$configpmtest")) {
1215 return $configpmtest;
1217 # Should never happen
1218 Carp::confess("Cannot open >$configpmtest");
1223 #-> sub CPAN::Config::load ;
1228 eval {require CPAN::Config;}; # We eval because of some
1229 # MakeMaker problems
1230 unless ($dot_cpan++){
1231 unshift @INC, File::Spec->catdir($ENV{HOME},".cpan");
1232 eval {require CPAN::MyConfig;}; # where you can override
1233 # system wide settings
1236 return unless @miss = $self->missing_config_data;
1238 require CPAN::FirstTime;
1239 my($configpm,$fh,$redo,$theycalled);
1241 $theycalled++ if @miss==1 && $miss[0] eq 'inhibit_startup_message';
1242 if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
1243 $configpm = $INC{"CPAN/Config.pm"};
1245 } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
1246 $configpm = $INC{"CPAN/MyConfig.pm"};
1249 my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
1250 my($configpmdir) = File::Spec->catdir($path_to_cpan,"CPAN");
1251 my($configpmtest) = File::Spec->catfile($configpmdir,"Config.pm");
1252 if (-d $configpmdir or File::Path::mkpath($configpmdir)) {
1253 $configpm = _configpmtest($configpmdir,$configpmtest);
1255 unless ($configpm) {
1256 $configpmdir = File::Spec->catdir($ENV{HOME},".cpan","CPAN");
1257 File::Path::mkpath($configpmdir);
1258 $configpmtest = File::Spec->catfile($configpmdir,"MyConfig.pm");
1259 $configpm = _configpmtest($configpmdir,$configpmtest);
1260 unless ($configpm) {
1261 Carp::confess(qq{WARNING: CPAN.pm is unable to }.
1262 qq{create a configuration file.});
1267 $CPAN::Frontend->myprint(<<END) if $redo && ! $theycalled;
1268 We have to reconfigure CPAN.pm due to following uninitialized parameters:
1272 $CPAN::Frontend->myprint(qq{
1273 $configpm initialized.
1276 CPAN::FirstTime::init($configpm);
1279 #-> sub CPAN::Config::missing_config_data ;
1280 sub missing_config_data {
1283 "cpan_home", "keep_source_where", "build_dir", "build_cache",
1284 "scan_cache", "index_expire", "gzip", "tar", "unzip", "make",
1286 "makepl_arg", "make_arg", "make_install_arg", "urllist",
1287 "inhibit_startup_message", "ftp_proxy", "http_proxy", "no_proxy",
1288 "prerequisites_policy",
1291 push @miss, $_ unless defined $CPAN::Config->{$_};
1296 #-> sub CPAN::Config::unload ;
1298 delete $INC{'CPAN/MyConfig.pm'};
1299 delete $INC{'CPAN/Config.pm'};
1302 #-> sub CPAN::Config::help ;
1304 $CPAN::Frontend->myprint(q[
1306 defaults reload default config values from disk
1307 commit commit session changes to disk
1308 init go through a dialog to set all parameters
1310 You may edit key values in the follow fashion (the "o" is a literal
1313 o conf build_cache 15
1315 o conf build_dir "/foo/bar"
1317 o conf urllist shift
1319 o conf urllist unshift ftp://ftp.foo.bar/
1322 undef; #don't reprint CPAN::Config
1325 #-> sub CPAN::Config::cpl ;
1327 my($word,$line,$pos) = @_;
1329 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1330 my(@words) = split " ", substr($line,0,$pos+1);
1335 $words[2] =~ /list$/ && @words == 3
1337 $words[2] =~ /list$/ && @words == 4 && length($word)
1340 return grep /^\Q$word\E/, qw(splice shift unshift pop push);
1341 } elsif (@words >= 4) {
1344 my(@o_conf) = (keys %CPAN::Config::can, keys %$CPAN::Config);
1345 return grep /^\Q$word\E/, @o_conf;
1348 package CPAN::Shell;
1350 #-> sub CPAN::Shell::h ;
1352 my($class,$about) = @_;
1353 if (defined $about) {
1354 $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
1356 $CPAN::Frontend->myprint(q{
1358 command argument description
1359 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1360 i WORD or /REGEXP/ about anything of above
1361 r NONE reinstall recommendations
1362 ls AUTHOR about files in the author's directory
1364 Download, Test, Make, Install...
1366 make make (implies get)
1367 test MODULES, make test (implies make)
1368 install DISTS, BUNDLES make install (implies test)
1370 look open subshell in these dists' directories
1371 readme display these dists' README files
1374 h,? display this menu ! perl-code eval a perl command
1375 o conf [opt] set and query options q quit the cpan shell
1376 reload cpan load CPAN.pm again reload index load newer indices
1377 autobundle Snapshot force cmd unconditionally do cmd});
1383 #-> sub CPAN::Shell::a ;
1385 my($self,@arg) = @_;
1386 # authors are always UPPERCASE
1388 $_ = uc $_ unless /=/;
1390 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1393 #-> sub CPAN::Shell::ls ;
1395 my($self,@arg) = @_;
1398 unless (/^[A-Z\-]+$/i) {
1399 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1402 push @accept, uc $_;
1404 for my $a (@accept){
1405 my $author = $self->expand('Author',$a) or die "No author found for $a";
1410 #-> sub CPAN::Shell::local_bundles ;
1412 my($self,@which) = @_;
1413 my($incdir,$bdir,$dh);
1414 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1415 my @bbase = "Bundle";
1416 while (my $bbase = shift @bbase) {
1417 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1418 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1419 if ($dh = DirHandle->new($bdir)) { # may fail
1421 for $entry ($dh->read) {
1422 next if $entry =~ /^\./;
1423 if (-d File::Spec->catdir($bdir,$entry)){
1424 push @bbase, "$bbase\::$entry";
1426 next unless $entry =~ s/\.pm(?!\n)\Z//;
1427 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1435 #-> sub CPAN::Shell::b ;
1437 my($self,@which) = @_;
1438 CPAN->debug("which[@which]") if $CPAN::DEBUG;
1439 $self->local_bundles;
1440 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1443 #-> sub CPAN::Shell::d ;
1444 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1446 #-> sub CPAN::Shell::m ;
1447 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1449 $CPAN::Frontend->myprint($self->format_result('Module',@_));
1452 #-> sub CPAN::Shell::i ;
1457 @type = qw/Author Bundle Distribution Module/;
1458 @args = '/./' unless @args;
1461 push @result, $self->expand($type,@args);
1463 my $result = @result == 1 ?
1464 $result[0]->as_string :
1466 "No objects found of any type for argument @args\n" :
1468 (map {$_->as_glimpse} @result),
1469 scalar @result, " items found\n",
1471 $CPAN::Frontend->myprint($result);
1474 #-> sub CPAN::Shell::o ;
1476 # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf'
1477 # should have been called set and 'o debug' maybe 'set debug'
1479 my($self,$o_type,@o_what) = @_;
1481 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1482 if ($o_type eq 'conf') {
1483 shift @o_what if @o_what && $o_what[0] eq 'help';
1484 if (!@o_what) { # print all things, "o conf"
1486 $CPAN::Frontend->myprint("CPAN::Config options");
1487 if (exists $INC{'CPAN/Config.pm'}) {
1488 $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1490 if (exists $INC{'CPAN/MyConfig.pm'}) {
1491 $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1493 $CPAN::Frontend->myprint(":\n");
1494 for $k (sort keys %CPAN::Config::can) {
1495 $v = $CPAN::Config::can{$k};
1496 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1498 $CPAN::Frontend->myprint("\n");
1499 for $k (sort keys %$CPAN::Config) {
1500 CPAN::Config->prettyprint($k);
1502 $CPAN::Frontend->myprint("\n");
1503 } elsif (!CPAN::Config->edit(@o_what)) {
1504 $CPAN::Frontend->myprint(qq{Type 'o conf' to view configuration }.
1505 qq{edit options\n\n});
1507 } elsif ($o_type eq 'debug') {
1509 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1512 my($what) = shift @o_what;
1513 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
1514 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
1517 if ( exists $CPAN::DEBUG{$what} ) {
1518 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1519 } elsif ($what =~ /^\d/) {
1520 $CPAN::DEBUG = $what;
1521 } elsif (lc $what eq 'all') {
1523 for (values %CPAN::DEBUG) {
1526 $CPAN::DEBUG = $max;
1529 for (keys %CPAN::DEBUG) {
1530 next unless lc($_) eq lc($what);
1531 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
1534 $CPAN::Frontend->myprint("unknown argument [$what]\n")
1539 my $raw = "Valid options for debug are ".
1540 join(", ",sort(keys %CPAN::DEBUG), 'all').
1541 qq{ or a number. Completion works on the options. }.
1542 qq{Case is ignored.};
1544 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
1545 $CPAN::Frontend->myprint("\n\n");
1548 $CPAN::Frontend->myprint("Options set for debugging:\n");
1550 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1551 $v = $CPAN::DEBUG{$k};
1552 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
1553 if $v & $CPAN::DEBUG;
1556 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
1559 $CPAN::Frontend->myprint(qq{
1561 conf set or get configuration variables
1562 debug set or get debugging options
1567 sub paintdots_onreload {
1570 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
1574 # $CPAN::Frontend->myprint(".($subr)");
1575 $CPAN::Frontend->myprint(".");
1582 #-> sub CPAN::Shell::reload ;
1584 my($self,$command,@arg) = @_;
1586 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1587 if ($command =~ /cpan/i) {
1588 for my $f (qw(CPAN.pm CPAN/FirstTime.pm)) {
1589 next unless $INC{$f};
1590 CPAN->debug("reloading the whole $f") if $CPAN::DEBUG;
1591 my $fh = FileHandle->new($INC{$f});
1594 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
1597 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
1599 } elsif ($command =~ /index/) {
1600 CPAN::Index->force_reload;
1602 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
1603 index re-reads the index files\n});
1607 #-> sub CPAN::Shell::_binary_extensions ;
1608 sub _binary_extensions {
1609 my($self) = shift @_;
1610 my(@result,$module,%seen,%need,$headerdone);
1611 for $module ($self->expand('Module','/./')) {
1612 my $file = $module->cpan_file;
1613 next if $file eq "N/A";
1614 next if $file =~ /^Contact Author/;
1615 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
1616 next if $dist->isa_perl;
1617 next unless $module->xs_file;
1619 $CPAN::Frontend->myprint(".");
1620 push @result, $module;
1622 # print join " | ", @result;
1623 $CPAN::Frontend->myprint("\n");
1627 #-> sub CPAN::Shell::recompile ;
1629 my($self) = shift @_;
1630 my($module,@module,$cpan_file,%dist);
1631 @module = $self->_binary_extensions();
1632 for $module (@module){ # we force now and compile later, so we
1634 $cpan_file = $module->cpan_file;
1635 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1637 $dist{$cpan_file}++;
1639 for $cpan_file (sort keys %dist) {
1640 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
1641 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1643 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1644 # stop a package from recompiling,
1645 # e.g. IO-1.12 when we have perl5.003_10
1649 #-> sub CPAN::Shell::_u_r_common ;
1651 my($self) = shift @_;
1652 my($what) = shift @_;
1653 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1654 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
1655 $what && $what =~ /^[aru]$/;
1657 @args = '/./' unless @args;
1658 my(@result,$module,%seen,%need,$headerdone,
1659 $version_undefs,$version_zeroes);
1660 $version_undefs = $version_zeroes = 0;
1661 my $sprintf = "%s%-25s%s %9s %9s %s\n";
1662 my @expand = $self->expand('Module',@args);
1663 my $expand = scalar @expand;
1664 if (0) { # Looks like noise to me, was very useful for debugging
1665 # for metadata cache
1666 $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
1668 for $module (@expand) {
1669 my $file = $module->cpan_file;
1670 next unless defined $file; # ??
1671 my($latest) = $module->cpan_version;
1672 my($inst_file) = $module->inst_file;
1674 return if $CPAN::Signal;
1677 $have = $module->inst_version;
1678 } elsif ($what eq "r") {
1679 $have = $module->inst_version;
1681 if ($have eq "undef"){
1683 } elsif ($have == 0){
1686 next unless CPAN::Version->vgt($latest, $have);
1687 # to be pedantic we should probably say:
1688 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1689 # to catch the case where CPAN has a version 0 and we have a version undef
1690 } elsif ($what eq "u") {
1696 } elsif ($what eq "r") {
1698 } elsif ($what eq "u") {
1702 return if $CPAN::Signal; # this is sometimes lengthy
1705 push @result, sprintf "%s %s\n", $module->id, $have;
1706 } elsif ($what eq "r") {
1707 push @result, $module->id;
1708 next if $seen{$file}++;
1709 } elsif ($what eq "u") {
1710 push @result, $module->id;
1711 next if $seen{$file}++;
1712 next if $file =~ /^Contact/;
1714 unless ($headerdone++){
1715 $CPAN::Frontend->myprint("\n");
1716 $CPAN::Frontend->myprint(sprintf(
1719 "Package namespace",
1731 $CPAN::META->has_inst("Term::ANSIColor")
1733 $module->{RO}{description}
1735 $color_on = Term::ANSIColor::color("green");
1736 $color_off = Term::ANSIColor::color("reset");
1738 $CPAN::Frontend->myprint(sprintf $sprintf,
1745 $need{$module->id}++;
1749 $CPAN::Frontend->myprint("No modules found for @args\n");
1750 } elsif ($what eq "r") {
1751 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
1755 if ($version_zeroes) {
1756 my $s_has = $version_zeroes > 1 ? "s have" : " has";
1757 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1758 qq{a version number of 0\n});
1760 if ($version_undefs) {
1761 my $s_has = $version_undefs > 1 ? "s have" : " has";
1762 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1763 qq{parseable version number\n});
1769 #-> sub CPAN::Shell::r ;
1771 shift->_u_r_common("r",@_);
1774 #-> sub CPAN::Shell::u ;
1776 shift->_u_r_common("u",@_);
1779 #-> sub CPAN::Shell::autobundle ;
1782 CPAN::Config->load unless $CPAN::Config_loaded++;
1783 my(@bundle) = $self->_u_r_common("a",@_);
1784 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1785 File::Path::mkpath($todir);
1786 unless (-d $todir) {
1787 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1790 my($y,$m,$d) = (localtime)[5,4,3];
1794 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1795 my($to) = File::Spec->catfile($todir,"$me.pm");
1797 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1798 $to = File::Spec->catfile($todir,"$me.pm");
1800 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1802 "package Bundle::$me;\n\n",
1803 "\$VERSION = '0.01';\n\n",
1807 "Bundle::$me - Snapshot of installation on ",
1808 $Config::Config{'myhostname'},
1811 "\n\n=head1 SYNOPSIS\n\n",
1812 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1813 "=head1 CONTENTS\n\n",
1814 join("\n", @bundle),
1815 "\n\n=head1 CONFIGURATION\n\n",
1817 "\n\n=head1 AUTHOR\n\n",
1818 "This Bundle has been generated automatically ",
1819 "by the autobundle routine in CPAN.pm.\n",
1822 $CPAN::Frontend->myprint("\nWrote bundle file
1826 #-> sub CPAN::Shell::expandany ;
1829 CPAN->debug("s[$s]") if $CPAN::DEBUG;
1830 if ($s =~ m|/|) { # looks like a file
1831 $s = CPAN::Distribution->normalize($s);
1832 return $CPAN::META->instance('CPAN::Distribution',$s);
1833 # Distributions spring into existence, not expand
1834 } elsif ($s =~ m|^Bundle::|) {
1835 $self->local_bundles; # scanning so late for bundles seems
1836 # both attractive and crumpy: always
1837 # current state but easy to forget
1839 return $self->expand('Bundle',$s);
1841 return $self->expand('Module',$s)
1842 if $CPAN::META->exists('CPAN::Module',$s);
1847 #-> sub CPAN::Shell::expand ;
1850 my($type,@args) = @_;
1852 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1854 my($regex,$command);
1855 if ($arg =~ m|^/(.*)/$|) {
1857 } elsif ($arg =~ m/=/) {
1860 my $class = "CPAN::$type";
1862 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1864 defined $regex ? $regex : "UNDEFINED",
1865 $command || "UNDEFINED",
1867 if (defined $regex) {
1871 $CPAN::META->all_objects($class)
1874 # BUG, we got an empty object somewhere
1875 require Data::Dumper;
1876 CPAN->debug(sprintf(
1877 "Bug in CPAN: Empty id on obj[%s][%s]",
1879 Data::Dumper::Dumper($obj)
1884 if $obj->id =~ /$regex/i
1888 $] < 5.00303 ### provide sort of
1889 ### compatibility with 5.003
1894 $obj->name =~ /$regex/i
1897 } elsif ($command) {
1898 die "equal sign in command disabled (immature interface), ".
1900 ! \$CPAN::Shell::ADVANCED_QUERY=1
1901 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1902 that may go away anytime.\n"
1903 unless $ADVANCED_QUERY;
1904 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1905 my($matchcrit) = $criterion =~ m/^~(.+)/;
1909 $CPAN::META->all_objects($class)
1911 my $lhs = $self->$method() or next; # () for 5.00503
1913 push @m, $self if $lhs =~ m/$matchcrit/;
1915 push @m, $self if $lhs eq $criterion;
1920 if ( $type eq 'Bundle' ) {
1921 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1922 } elsif ($type eq "Distribution") {
1923 $xarg = CPAN::Distribution->normalize($arg);
1925 if ($CPAN::META->exists($class,$xarg)) {
1926 $obj = $CPAN::META->instance($class,$xarg);
1927 } elsif ($CPAN::META->exists($class,$arg)) {
1928 $obj = $CPAN::META->instance($class,$arg);
1935 return wantarray ? @m : $m[0];
1938 #-> sub CPAN::Shell::format_result ;
1941 my($type,@args) = @_;
1942 @args = '/./' unless @args;
1943 my(@result) = $self->expand($type,@args);
1944 my $result = @result == 1 ?
1945 $result[0]->as_string :
1947 "No objects of type $type found for argument @args\n" :
1949 (map {$_->as_glimpse} @result),
1950 scalar @result, " items found\n",
1955 # The only reason for this method is currently to have a reliable
1956 # debugging utility that reveals which output is going through which
1957 # channel. No, I don't like the colors ;-)
1959 #-> sub CPAN::Shell::print_ornameted ;
1960 sub print_ornamented {
1961 my($self,$what,$ornament) = @_;
1963 return unless defined $what;
1965 if ($CPAN::Config->{term_is_latin}){
1968 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
1970 if ($PRINT_ORNAMENTING) {
1971 unless (defined &color) {
1972 if ($CPAN::META->has_inst("Term::ANSIColor")) {
1973 import Term::ANSIColor "color";
1975 *color = sub { return "" };
1979 for $line (split /\n/, $what) {
1980 $longest = length($line) if length($line) > $longest;
1982 my $sprintf = "%-" . $longest . "s";
1984 $what =~ s/(.*\n?)//m;
1987 my($nl) = chomp $line ? "\n" : "";
1988 # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
1989 print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
1993 # $what .= "\n"; # newlines unless $PRINT_ORNAMENTING
1999 my($self,$what) = @_;
2001 $self->print_ornamented($what, 'bold blue on_yellow');
2005 my($self,$what) = @_;
2006 $self->myprint($what);
2011 my($self,$what) = @_;
2012 $self->print_ornamented($what, 'bold red on_yellow');
2016 my($self,$what) = @_;
2017 $self->print_ornamented($what, 'bold red on_white');
2018 Carp::confess "died";
2022 my($self,$what) = @_;
2023 $self->print_ornamented($what, 'bold red on_white');
2028 return if -t STDOUT;
2029 my $odef = select STDERR;
2036 #-> sub CPAN::Shell::rematein ;
2037 # RE-adme||MA-ke||TE-st||IN-stall
2040 my($meth,@some) = @_;
2042 if ($meth eq 'force') {
2044 $meth = shift @some;
2047 CPAN->debug("pragma[$pragma]meth[$meth] some[@some]") if $CPAN::DEBUG;
2049 # Here is the place to set "test_count" on all involved parties to
2050 # 0. We then can pass this counter on to the involved
2051 # distributions and those can refuse to test if test_count > X. In
2052 # the first stab at it we could use a 1 for "X".
2054 # But when do I reset the distributions to start with 0 again?
2055 # Jost suggested to have a random or cycling interaction ID that
2056 # we pass through. But the ID is something that is just left lying
2057 # around in addition to the counter, so I'd prefer to set the
2058 # counter to 0 now, and repeat at the end of the loop. But what
2059 # about dependencies? They appear later and are not reset, they
2060 # enter the queue but not its copy. How do they get a sensible
2063 # construct the queue
2065 foreach $s (@some) {
2068 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
2070 } elsif ($s =~ m|^/|) { # looks like a regexp
2071 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
2076 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
2077 $obj = CPAN::Shell->expandany($s);
2080 $obj->color_cmd_tmps(0,1);
2081 CPAN::Queue->new($obj->id);
2083 } elsif ($CPAN::META->exists('CPAN::Author',$s)) {
2084 $obj = $CPAN::META->instance('CPAN::Author',$s);
2085 if ($meth =~ /^(dump|ls)$/) {
2088 $CPAN::Frontend->myprint(
2090 "Don't be silly, you can't $meth ",
2098 ->myprint(qq{Warning: Cannot $meth $s, }.
2099 qq{don\'t know what it is.
2104 to find objects with matching identifiers.
2110 # queuerunner (please be warned: when I started to change the
2111 # queue to hold objects instead of names, I made one or two
2112 # mistakes and never found which. I reverted back instead)
2113 while ($s = CPAN::Queue->first) {
2116 $obj = $s; # I do not believe, we would survive if this happened
2118 $obj = CPAN::Shell->expandany($s);
2122 ($] < 5.00303 || $obj->can($pragma))){
2123 ### compatibility with 5.003
2124 $obj->$pragma($meth); # the pragma "force" in
2125 # "CPAN::Distribution" must know
2126 # what we are intending
2128 if ($]>=5.00303 && $obj->can('called_for')) {
2129 $obj->called_for($s);
2132 qq{pragma[$pragma]meth[$meth]obj[$obj]as_string\[}.
2138 CPAN::Queue->delete($s);
2140 CPAN->debug("failed");
2144 CPAN::Queue->delete_first($s);
2146 for my $obj (@qcopy) {
2147 $obj->color_cmd_tmps(0,0);
2151 #-> sub CPAN::Shell::dump ;
2152 sub dump { shift->rematein('dump',@_); }
2153 #-> sub CPAN::Shell::force ;
2154 sub force { shift->rematein('force',@_); }
2155 #-> sub CPAN::Shell::get ;
2156 sub get { shift->rematein('get',@_); }
2157 #-> sub CPAN::Shell::readme ;
2158 sub readme { shift->rematein('readme',@_); }
2159 #-> sub CPAN::Shell::make ;
2160 sub make { shift->rematein('make',@_); }
2161 #-> sub CPAN::Shell::test ;
2162 sub test { shift->rematein('test',@_); }
2163 #-> sub CPAN::Shell::install ;
2164 sub install { shift->rematein('install',@_); }
2165 #-> sub CPAN::Shell::clean ;
2166 sub clean { shift->rematein('clean',@_); }
2167 #-> sub CPAN::Shell::look ;
2168 sub look { shift->rematein('look',@_); }
2169 #-> sub CPAN::Shell::cvs_import ;
2170 sub cvs_import { shift->rematein('cvs_import',@_); }
2172 package CPAN::LWP::UserAgent;
2175 return if $SETUPDONE;
2176 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2177 require LWP::UserAgent;
2178 @ISA = qw(Exporter LWP::UserAgent);
2181 $CPAN::Frontend->mywarn("LWP::UserAgent not available\n");
2185 sub get_basic_credentials {
2186 my($self, $realm, $uri, $proxy) = @_;
2187 return unless $proxy;
2188 if ($USER && $PASSWD) {
2189 } elsif (defined $CPAN::Config->{proxy_user} &&
2190 defined $CPAN::Config->{proxy_pass}) {
2191 $USER = $CPAN::Config->{proxy_user};
2192 $PASSWD = $CPAN::Config->{proxy_pass};
2194 require ExtUtils::MakeMaker;
2195 ExtUtils::MakeMaker->import(qw(prompt));
2196 $USER = prompt("Proxy authentication needed!
2197 (Note: to permanently configure username and password run
2198 o conf proxy_user your_username
2199 o conf proxy_pass your_password
2201 if ($CPAN::META->has_inst("Term::ReadKey")) {
2202 Term::ReadKey::ReadMode("noecho");
2204 $CPAN::Frontend->mywarn("Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n");
2206 $PASSWD = prompt("Password:");
2207 if ($CPAN::META->has_inst("Term::ReadKey")) {
2208 Term::ReadKey::ReadMode("restore");
2210 $CPAN::Frontend->myprint("\n\n");
2212 return($USER,$PASSWD);
2216 my($self,$url,$aslocal) = @_;
2217 my $result = $self->SUPER::mirror($url,$aslocal);
2218 if ($result->code == 407) {
2221 $result = $self->SUPER::mirror($url,$aslocal);
2228 #-> sub CPAN::FTP::ftp_get ;
2230 my($class,$host,$dir,$file,$target) = @_;
2232 qq[Going to fetch file [$file] from dir [$dir]
2233 on host [$host] as local [$target]\n]
2235 my $ftp = Net::FTP->new($host);
2236 return 0 unless defined $ftp;
2237 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
2238 $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
2239 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
2240 warn "Couldn't login on $host";
2243 unless ( $ftp->cwd($dir) ){
2244 warn "Couldn't cwd $dir";
2248 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
2249 unless ( $ftp->get($file,$target) ){
2250 warn "Couldn't fetch $file from $host\n";
2253 $ftp->quit; # it's ok if this fails
2257 # If more accuracy is wanted/needed, Chris Leach sent me this patch...
2259 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
2260 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
2262 # > *** 1562,1567 ****
2263 # > --- 1562,1580 ----
2264 # > return 1 if substr($url,0,4) eq "file";
2265 # > return 1 unless $url =~ m|://([^/]+)|;
2267 # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
2269 # > + $proxy =~ m|://([^/:]+)|;
2271 # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
2272 # > + if ($noproxy) {
2273 # > + if ($host !~ /$noproxy$/) {
2274 # > + $host = $proxy;
2277 # > + $host = $proxy;
2280 # > require Net::Ping;
2281 # > return 1 unless $Net::Ping::VERSION >= 2;
2285 #-> sub CPAN::FTP::localize ;
2287 my($self,$file,$aslocal,$force) = @_;
2289 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
2290 unless defined $aslocal;
2291 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
2294 if ($^O eq 'MacOS') {
2295 # Comment by AK on 2000-09-03: Uniq short filenames would be
2296 # available in CHECKSUMS file
2297 my($name, $path) = File::Basename::fileparse($aslocal, '');
2298 if (length($name) > 31) {
2309 my $size = 31 - length($suf);
2310 while (length($name) > $size) {
2314 $aslocal = File::Spec->catfile($path, $name);
2318 return $aslocal if -f $aslocal && -r _ && !($force & 1);
2321 rename $aslocal, "$aslocal.bak";
2325 my($aslocal_dir) = File::Basename::dirname($aslocal);
2326 File::Path::mkpath($aslocal_dir);
2327 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
2328 qq{directory "$aslocal_dir".
2329 I\'ll continue, but if you encounter problems, they may be due
2330 to insufficient permissions.\n}) unless -w $aslocal_dir;
2332 # Inheritance is not easier to manage than a few if/else branches
2333 if ($CPAN::META->has_usable('LWP::UserAgent')) {
2335 CPAN::LWP::UserAgent->config;
2336 eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
2338 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
2342 $Ua->proxy('ftp', $var)
2343 if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
2344 $Ua->proxy('http', $var)
2345 if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
2348 # >>>>> On Wed, 13 Dec 2000 09:21:34 -0500, "Robison, Jonathon (J.M.)" <jrobiso2@visteon.com> said:
2350 # > I note that although CPAN.pm can use proxies, it doesn't seem equipped to
2351 # > use ones that require basic autorization.
2353 # > Example of when I use it manually in my own stuff:
2355 # > $ua->proxy(['http','ftp'], http://my.proxy.server:83');
2356 # > $req->proxy_authorization_basic("username","password");
2357 # > $res = $ua->request($req);
2361 if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
2365 for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
2366 $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
2369 # Try the list of urls for each single object. We keep a record
2370 # where we did get a file from
2371 my(@reordered,$last);
2372 $CPAN::Config->{urllist} ||= [];
2373 unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
2374 warn "Malformed urllist; ignoring. Configuration file corrupt?\n";
2376 $last = $#{$CPAN::Config->{urllist}};
2377 if ($force & 2) { # local cpans probably out of date, don't reorder
2378 @reordered = (0..$last);
2382 (substr($CPAN::Config->{urllist}[$b],0,4) eq "file")
2384 (substr($CPAN::Config->{urllist}[$a],0,4) eq "file")
2395 @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/);
2397 @levels = qw/easy hard hardest/;
2399 @levels = qw/easy/ if $^O eq 'MacOS';
2401 for $levelno (0..$#levels) {
2402 my $level = $levels[$levelno];
2403 my $method = "host$level";
2404 my @host_seq = $level eq "easy" ?
2405 @reordered : 0..$last; # reordered has CDROM up front
2406 @host_seq = (0) unless @host_seq;
2407 my $ret = $self->$method(\@host_seq,$file,$aslocal);
2409 $Themethod = $level;
2411 # utime $now, $now, $aslocal; # too bad, if we do that, we
2412 # might alter a local mirror
2413 $self->debug("level[$level]") if $CPAN::DEBUG;
2417 last if $CPAN::Signal; # need to cleanup
2420 unless ($CPAN::Signal) {
2423 qq{Please check, if the URLs I found in your configuration file \(}.
2424 join(", ", @{$CPAN::Config->{urllist}}).
2425 qq{\) are valid. The urllist can be edited.},
2426 qq{E.g. with 'o conf urllist push ftp://myurl/'};
2427 $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n");
2429 $CPAN::Frontend->myprint("Could not fetch $file\n");
2432 rename "$aslocal.bak", $aslocal;
2433 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
2434 $self->ls($aslocal));
2441 my($self,$host_seq,$file,$aslocal) = @_;
2443 HOSTEASY: for $i (@$host_seq) {
2444 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2445 $url .= "/" unless substr($url,-1) eq "/";
2447 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
2448 if ($url =~ /^file:/) {
2450 if ($CPAN::META->has_inst('URI::URL')) {
2451 my $u = URI::URL->new($url);
2453 } else { # works only on Unix, is poorly constructed, but
2454 # hopefully better than nothing.
2455 # RFC 1738 says fileurl BNF is
2456 # fileurl = "file://" [ host | "localhost" ] "/" fpath
2457 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
2459 ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
2460 $l =~ s|^file:||; # assume they
2463 $l =~ s|^/||s unless -f $l; # e.g. /P:
2464 $self->debug("without URI::URL we try local file $l") if $CPAN::DEBUG;
2466 if ( -f $l && -r _) {
2470 # Maybe mirror has compressed it?
2472 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
2473 CPAN::Tarzip->gunzip("$l.gz", $aslocal);
2480 if ($CPAN::META->has_usable('LWP')) {
2481 $CPAN::Frontend->myprint("Fetching with LWP:
2485 CPAN::LWP::UserAgent->config;
2486 eval { $Ua = CPAN::LWP::UserAgent->new; };
2488 $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
2491 my $res = $Ua->mirror($url, $aslocal);
2492 if ($res->is_success) {
2495 utime $now, $now, $aslocal; # download time is more
2496 # important than upload time
2498 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2499 my $gzurl = "$url.gz";
2500 $CPAN::Frontend->myprint("Fetching with LWP:
2503 $res = $Ua->mirror($gzurl, "$aslocal.gz");
2504 if ($res->is_success &&
2505 CPAN::Tarzip->gunzip("$aslocal.gz",$aslocal)
2511 $CPAN::Frontend->myprint(sprintf(
2512 "LWP failed with code[%s] message[%s]\n",
2516 # Alan Burlison informed me that in firewall environments
2517 # Net::FTP can still succeed where LWP fails. So we do not
2518 # skip Net::FTP anymore when LWP is available.
2521 $CPAN::Frontend->myprint("LWP not available\n");
2523 return if $CPAN::Signal;
2524 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2525 # that's the nice and easy way thanks to Graham
2526 my($host,$dir,$getfile) = ($1,$2,$3);
2527 if ($CPAN::META->has_usable('Net::FTP')) {
2529 $CPAN::Frontend->myprint("Fetching with Net::FTP:
2532 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
2533 "aslocal[$aslocal]") if $CPAN::DEBUG;
2534 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
2538 if ($aslocal !~ /\.gz(?!\n)\Z/) {
2539 my $gz = "$aslocal.gz";
2540 $CPAN::Frontend->myprint("Fetching with Net::FTP
2543 if (CPAN::FTP->ftp_get($host,
2547 CPAN::Tarzip->gunzip($gz,$aslocal)
2556 return if $CPAN::Signal;
2561 my($self,$host_seq,$file,$aslocal) = @_;
2563 # Came back if Net::FTP couldn't establish connection (or
2564 # failed otherwise) Maybe they are behind a firewall, but they
2565 # gave us a socksified (or other) ftp program...
2568 my($devnull) = $CPAN::Config->{devnull} || "";
2570 my($aslocal_dir) = File::Basename::dirname($aslocal);
2571 File::Path::mkpath($aslocal_dir);
2572 HOSTHARD: for $i (@$host_seq) {
2573 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2574 $url .= "/" unless substr($url,-1) eq "/";
2576 my($proto,$host,$dir,$getfile);
2578 # Courtesy Mark Conty mark_conty@cargill.com change from
2579 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2581 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
2582 # proto not yet used
2583 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
2585 next HOSTHARD; # who said, we could ftp anything except ftp?
2587 next HOSTHARD if $proto eq "file"; # file URLs would have had
2588 # success above. Likely a bogus URL
2590 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
2592 for $f ('lynx','ncftpget','ncftp','wget') {
2593 next unless exists $CPAN::Config->{$f};
2594 $funkyftp = $CPAN::Config->{$f};
2595 next unless defined $funkyftp;
2596 next if $funkyftp =~ /^\s*$/;
2597 my($asl_ungz, $asl_gz);
2598 ($asl_ungz = $aslocal) =~ s/\.gz//;
2599 $asl_gz = "$asl_ungz.gz";
2600 my($src_switch) = "";
2602 $src_switch = " -source";
2603 } elsif ($f eq "ncftp"){
2604 $src_switch = " -c";
2605 } elsif ($f eq "wget"){
2606 $src_switch = " -O -";
2609 my($stdout_redir) = " > $asl_ungz";
2610 if ($f eq "ncftpget"){
2611 $chdir = "cd $aslocal_dir && ";
2614 $CPAN::Frontend->myprint(
2616 Trying with "$funkyftp$src_switch" to get
2620 "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
2621 $self->debug("system[$system]") if $CPAN::DEBUG;
2623 if (($wstatus = system($system)) == 0
2626 -s $asl_ungz # lynx returns 0 when it fails somewhere
2632 } elsif ($asl_ungz ne $aslocal) {
2633 # test gzip integrity
2634 if (CPAN::Tarzip->gtest($asl_ungz)) {
2635 # e.g. foo.tar is gzipped --> foo.tar.gz
2636 rename $asl_ungz, $aslocal;
2638 CPAN::Tarzip->gzip($asl_ungz,$asl_gz);
2643 } elsif ($url !~ /\.gz(?!\n)\Z/) {
2645 -f $asl_ungz && -s _ == 0;
2646 my $gz = "$aslocal.gz";
2647 my $gzurl = "$url.gz";
2648 $CPAN::Frontend->myprint(
2650 Trying with "$funkyftp$src_switch" to get
2653 my($system) = "$funkyftp$src_switch \"$url.gz\" $devnull > $asl_gz";
2654 $self->debug("system[$system]") if $CPAN::DEBUG;
2656 if (($wstatus = system($system)) == 0
2660 # test gzip integrity
2661 if (CPAN::Tarzip->gtest($asl_gz)) {
2662 CPAN::Tarzip->gunzip($asl_gz,$aslocal);
2664 # somebody uncompressed file for us?
2665 rename $asl_ungz, $aslocal;
2670 unlink $asl_gz if -f $asl_gz;
2673 my $estatus = $wstatus >> 8;
2674 my $size = -f $aslocal ?
2675 ", left\n$aslocal with size ".-s _ :
2676 "\nWarning: expected file [$aslocal] doesn't exist";
2677 $CPAN::Frontend->myprint(qq{
2678 System call "$system"
2679 returned status $estatus (wstat $wstatus)$size
2682 return if $CPAN::Signal;
2683 } # lynx,ncftpget,ncftp
2688 my($self,$host_seq,$file,$aslocal) = @_;
2691 my($aslocal_dir) = File::Basename::dirname($aslocal);
2692 File::Path::mkpath($aslocal_dir);
2693 my $ftpbin = $CPAN::Config->{ftp};
2694 HOSTHARDEST: for $i (@$host_seq) {
2695 unless (length $ftpbin && MM->maybe_command($ftpbin)) {
2696 $CPAN::Frontend->myprint("No external ftp command available\n\n");
2699 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2700 $url .= "/" unless substr($url,-1) eq "/";
2702 $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
2703 unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2706 my($host,$dir,$getfile) = ($1,$2,$3);
2708 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
2709 $ctime,$blksize,$blocks) = stat($aslocal);
2710 $timestamp = $mtime ||= 0;
2711 my($netrc) = CPAN::FTP::netrc->new;
2712 my($netrcfile) = $netrc->netrc;
2713 my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
2714 my $targetfile = File::Basename::basename($aslocal);
2720 map("cd $_", split /\//, $dir), # RFC 1738
2722 "get $getfile $targetfile",
2726 CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
2727 } elsif ($netrc->hasdefault || $netrc->contains($host)) {
2728 CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
2730 $netrc->contains($host))) if $CPAN::DEBUG;
2731 if ($netrc->protected) {
2732 $CPAN::Frontend->myprint(qq{
2733 Trying with external ftp to get
2735 As this requires some features that are not thoroughly tested, we\'re
2736 not sure, that we get it right....
2740 $self->talk_ftp("$ftpbin$verbose $host",
2742 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2743 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2745 if ($mtime > $timestamp) {
2746 $CPAN::Frontend->myprint("GOT $aslocal\n");
2750 $CPAN::Frontend->myprint("Hmm... Still failed!\n");
2752 return if $CPAN::Signal;
2754 $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
2755 qq{correctly protected.\n});
2758 $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
2759 nor does it have a default entry\n");
2762 # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
2763 # then and login manually to host, using e-mail as
2765 $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n});
2769 "user anonymous $Config::Config{'cf_email'}"
2771 $self->talk_ftp("$ftpbin$verbose -n", @dialog);
2772 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2773 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2775 if ($mtime > $timestamp) {
2776 $CPAN::Frontend->myprint("GOT $aslocal\n");
2780 $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
2782 return if $CPAN::Signal;
2783 $CPAN::Frontend->myprint("Can't access URL $url.\n\n");
2789 my($self,$command,@dialog) = @_;
2790 my $fh = FileHandle->new;
2791 $fh->open("|$command") or die "Couldn't open ftp: $!";
2792 foreach (@dialog) { $fh->print("$_\n") }
2793 $fh->close; # Wait for process to complete
2795 my $estatus = $wstatus >> 8;
2796 $CPAN::Frontend->myprint(qq{
2797 Subprocess "|$command"
2798 returned status $estatus (wstat $wstatus)
2802 # find2perl needs modularization, too, all the following is stolen
2806 my($self,$name) = @_;
2807 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
2808 $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
2810 my($perms,%user,%group);
2814 $blocks = int(($blocks + 1) / 2);
2817 $blocks = int(($sizemm + 1023) / 1024);
2820 if (-f _) { $perms = '-'; }
2821 elsif (-d _) { $perms = 'd'; }
2822 elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
2823 elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
2824 elsif (-p _) { $perms = 'p'; }
2825 elsif (-S _) { $perms = 's'; }
2826 else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
2828 my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
2829 my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
2830 my $tmpmode = $mode;
2831 my $tmp = $rwx[$tmpmode & 7];
2833 $tmp = $rwx[$tmpmode & 7] . $tmp;
2835 $tmp = $rwx[$tmpmode & 7] . $tmp;
2836 substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
2837 substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
2838 substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
2841 my $user = $user{$uid} || $uid; # too lazy to implement lookup
2842 my $group = $group{$gid} || $gid;
2844 my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
2846 my($moname) = $moname[$mon];
2847 if (-M _ > 365.25 / 2) {
2848 $timeyear = $year + 1900;
2851 $timeyear = sprintf("%02d:%02d", $hour, $min);
2854 sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
2868 package CPAN::FTP::netrc;
2872 my $file = File::Spec->catfile($ENV{HOME},".netrc");
2874 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2875 $atime,$mtime,$ctime,$blksize,$blocks)
2880 my($fh,@machines,$hasdefault);
2882 $fh = FileHandle->new or die "Could not create a filehandle";
2884 if($fh->open($file)){
2885 $protected = ($mode & 077) == 0;
2887 NETRC: while (<$fh>) {
2888 my(@tokens) = split " ", $_;
2889 TOKEN: while (@tokens) {
2890 my($t) = shift @tokens;
2891 if ($t eq "default"){
2895 last TOKEN if $t eq "macdef";
2896 if ($t eq "machine") {
2897 push @machines, shift @tokens;
2902 $file = $hasdefault = $protected = "";
2906 'mach' => [@machines],
2908 'hasdefault' => $hasdefault,
2909 'protected' => $protected,
2913 # CPAN::FTP::hasdefault;
2914 sub hasdefault { shift->{'hasdefault'} }
2915 sub netrc { shift->{'netrc'} }
2916 sub protected { shift->{'protected'} }
2918 my($self,$mach) = @_;
2919 for ( @{$self->{'mach'}} ) {
2920 return 1 if $_ eq $mach;
2925 package CPAN::Complete;
2928 my($text, $line, $start, $end) = @_;
2929 my(@perlret) = cpl($text, $line, $start);
2930 # find longest common match. Can anybody show me how to peruse
2931 # T::R::Gnu to have this done automatically? Seems expensive.
2932 return () unless @perlret;
2933 my($newtext) = $text;
2934 for (my $i = length($text)+1;;$i++) {
2935 last unless length($perlret[0]) && length($perlret[0]) >= $i;
2936 my $try = substr($perlret[0],0,$i);
2937 my @tries = grep {substr($_,0,$i) eq $try} @perlret;
2938 # warn "try[$try]tries[@tries]";
2939 if (@tries == @perlret) {
2945 ($newtext,@perlret);
2948 #-> sub CPAN::Complete::cpl ;
2950 my($word,$line,$pos) = @_;
2954 CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2956 if ($line =~ s/^(force\s*)//) {
2961 @return = grep /^$word/, @CPAN::Complete::COMMANDS;
2962 } elsif ( $line !~ /^[\!abcdghimorutl]/ ) {
2964 } elsif ($line =~ /^(a|ls)\s/) {
2965 @return = cplx('CPAN::Author',uc($word));
2966 } elsif ($line =~ /^b\s/) {
2967 CPAN::Shell->local_bundles;
2968 @return = cplx('CPAN::Bundle',$word);
2969 } elsif ($line =~ /^d\s/) {
2970 @return = cplx('CPAN::Distribution',$word);
2971 } elsif ($line =~ m/^(
2972 [mru]|make|clean|dump|get|test|install|readme|look|cvs_import
2974 if ($word =~ /^Bundle::/) {
2975 CPAN::Shell->local_bundles;
2977 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
2978 } elsif ($line =~ /^i\s/) {
2979 @return = cpl_any($word);
2980 } elsif ($line =~ /^reload\s/) {
2981 @return = cpl_reload($word,$line,$pos);
2982 } elsif ($line =~ /^o\s/) {
2983 @return = cpl_option($word,$line,$pos);
2984 } elsif ($line =~ m/^\S+\s/ ) {
2985 # fallback for future commands and what we have forgotten above
2986 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
2993 #-> sub CPAN::Complete::cplx ;
2995 my($class, $word) = @_;
2996 # I believed for many years that this was sorted, today I
2997 # realized, it wasn't sorted anymore. Now (rev 1.301 / v 1.55) I
2998 # make it sorted again. Maybe sort was dropped when GNU-readline
2999 # support came in? The RCS file is difficult to read on that:-(
3000 sort grep /^\Q$word\E/, map { $_->id } $CPAN::META->all_objects($class);
3003 #-> sub CPAN::Complete::cpl_any ;
3007 cplx('CPAN::Author',$word),
3008 cplx('CPAN::Bundle',$word),
3009 cplx('CPAN::Distribution',$word),
3010 cplx('CPAN::Module',$word),
3014 #-> sub CPAN::Complete::cpl_reload ;
3016 my($word,$line,$pos) = @_;
3018 my(@words) = split " ", $line;
3019 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3020 my(@ok) = qw(cpan index);
3021 return @ok if @words == 1;
3022 return grep /^\Q$word\E/, @ok if @words == 2 && $word;
3025 #-> sub CPAN::Complete::cpl_option ;
3027 my($word,$line,$pos) = @_;
3029 my(@words) = split " ", $line;
3030 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3031 my(@ok) = qw(conf debug);
3032 return @ok if @words == 1;
3033 return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
3035 } elsif ($words[1] eq 'index') {
3037 } elsif ($words[1] eq 'conf') {
3038 return CPAN::Config::cpl(@_);
3039 } elsif ($words[1] eq 'debug') {
3040 return sort grep /^\Q$word\E/, sort keys %CPAN::DEBUG, 'all';
3044 package CPAN::Index;
3046 #-> sub CPAN::Index::force_reload ;
3049 $CPAN::Index::LAST_TIME = 0;
3053 #-> sub CPAN::Index::reload ;
3055 my($cl,$force) = @_;
3058 # XXX check if a newer one is available. (We currently read it
3059 # from time to time)
3060 for ($CPAN::Config->{index_expire}) {
3061 $_ = 0.001 unless $_ && $_ > 0.001;
3063 unless (1 || $CPAN::Have_warned->{readmetadatacache}++) {
3064 # debug here when CPAN doesn't seem to read the Metadata
3066 Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]");
3068 unless ($CPAN::META->{PROTOCOL}) {
3069 $cl->read_metadata_cache;
3070 $CPAN::META->{PROTOCOL} ||= "1.0";
3072 if ( $CPAN::META->{PROTOCOL} < PROTOCOL ) {
3073 # warn "Setting last_time to 0";
3074 $LAST_TIME = 0; # No warning necessary
3076 return if $LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time
3079 # IFF we are developing, it helps to wipe out the memory
3080 # between reloads, otherwise it is not what a user expects.
3081 undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274)
3082 $CPAN::META = CPAN->new;
3086 local $LAST_TIME = $time;
3087 local $CPAN::META->{PROTOCOL} = PROTOCOL;
3089 my $needshort = $^O eq "dos";
3091 $cl->rd_authindex($cl
3093 "authors/01mailrc.txt.gz",
3095 File::Spec->catfile('authors', '01mailrc.gz') :
3096 File::Spec->catfile('authors', '01mailrc.txt.gz'),
3099 $debug = "timing reading 01[".($t2 - $time)."]";
3101 return if $CPAN::Signal; # this is sometimes lengthy
3102 $cl->rd_modpacks($cl
3104 "modules/02packages.details.txt.gz",
3106 File::Spec->catfile('modules', '02packag.gz') :
3107 File::Spec->catfile('modules', '02packages.details.txt.gz'),
3110 $debug .= "02[".($t2 - $time)."]";
3112 return if $CPAN::Signal; # this is sometimes lengthy
3115 "modules/03modlist.data.gz",
3117 File::Spec->catfile('modules', '03mlist.gz') :
3118 File::Spec->catfile('modules', '03modlist.data.gz'),
3120 $cl->write_metadata_cache;
3122 $debug .= "03[".($t2 - $time)."]";
3124 CPAN->debug($debug) if $CPAN::DEBUG;
3127 $CPAN::META->{PROTOCOL} = PROTOCOL;
3130 #-> sub CPAN::Index::reload_x ;
3132 my($cl,$wanted,$localname,$force) = @_;
3133 $force |= 2; # means we're dealing with an index here
3134 CPAN::Config->load; # we should guarantee loading wherever we rely
3136 $localname ||= $wanted;
3137 my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'},
3141 -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
3144 my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
3145 $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
3146 qq{day$s. I\'ll use that.});
3149 $force |= 1; # means we're quite serious about it.
3151 return CPAN::FTP->localize($wanted,$abs_wanted,$force);
3154 #-> sub CPAN::Index::rd_authindex ;
3156 my($cl, $index_target) = @_;
3158 return unless defined $index_target;
3159 $CPAN::Frontend->myprint("Going to read $index_target\n");
3161 tie *FH, CPAN::Tarzip, $index_target;
3163 push @lines, split /\012/ while <FH>;
3165 my($userid,$fullname,$email) =
3166 m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
3167 next unless $userid && $fullname && $email;
3169 # instantiate an author object
3170 my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
3171 $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
3172 return if $CPAN::Signal;
3177 my($self,$dist) = @_;
3178 $dist = $self->{'id'} unless defined $dist;
3179 my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
3183 #-> sub CPAN::Index::rd_modpacks ;
3185 my($self, $index_target) = @_;
3187 return unless defined $index_target;
3188 $CPAN::Frontend->myprint("Going to read $index_target\n");
3189 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3191 while ($_ = $fh->READLINE) {
3193 my @ls = map {"$_\n"} split /\n/, $_;
3194 unshift @ls, "\n" x length($1) if /^(\n+)/;
3198 my($line_count,$last_updated);
3200 my $shift = shift(@lines);
3201 last if $shift =~ /^\s*$/;
3202 $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1;
3203 $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1;
3205 if (not defined $line_count) {
3207 warn qq{Warning: Your $index_target does not contain a Line-Count header.
3208 Please check the validity of the index file by comparing it to more
3209 than one CPAN mirror. I'll continue but problems seem likely to
3214 } elsif ($line_count != scalar @lines) {
3216 warn sprintf qq{Warning: Your %s
3217 contains a Line-Count header of %d but I see %d lines there. Please
3218 check the validity of the index file by comparing it to more than one
3219 CPAN mirror. I'll continue but problems seem likely to happen.\a\n},
3220 $index_target, $line_count, scalar(@lines);
3223 if (not defined $last_updated) {
3225 warn qq{Warning: Your $index_target does not contain a Last-Updated header.
3226 Please check the validity of the index file by comparing it to more
3227 than one CPAN mirror. I'll continue but problems seem likely to
3235 ->myprint(sprintf qq{ Database was generated on %s\n},
3237 $DATE_OF_02 = $last_updated;
3239 if ($CPAN::META->has_inst(HTTP::Date)) {
3241 my($age) = (time - HTTP::Date::str2time($last_updated))/3600/24;
3246 qq{Warning: This index file is %d days old.
3247 Please check the host you chose as your CPAN mirror for staleness.
3248 I'll continue but problems seem likely to happen.\a\n},
3253 $CPAN::Frontend->myprint(" HTTP::Date not available\n");
3258 # A necessity since we have metadata_cache: delete what isn't
3260 my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN");
3261 CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
3265 # before 1.56 we split into 3 and discarded the rest. From
3266 # 1.57 we assign remaining text to $comment thus allowing to
3267 # influence isa_perl
3268 my($mod,$version,$dist,$comment) = split " ", $_, 4;
3269 my($bundle,$id,$userid);
3271 if ($mod eq 'CPAN' &&
3273 CPAN::Queue->exists('Bundle::CPAN') ||
3274 CPAN::Queue->exists('CPAN')
3278 if ($version > $CPAN::VERSION){
3279 $CPAN::Frontend->myprint(qq{
3280 There's a new CPAN.pm version (v$version) available!
3281 [Current version is v$CPAN::VERSION]
3282 You might want to try
3283 install Bundle::CPAN
3285 without quitting the current session. It should be a seamless upgrade
3286 while we are running...
3289 $CPAN::Frontend->myprint(qq{\n});
3291 last if $CPAN::Signal;
3292 } elsif ($mod =~ /^Bundle::(.*)/) {
3297 $id = $CPAN::META->instance('CPAN::Bundle',$mod);
3298 # Let's make it a module too, because bundles have so much
3299 # in common with modules.
3301 # Changed in 1.57_63: seems like memory bloat now without
3302 # any value, so commented out
3304 # $CPAN::META->instance('CPAN::Module',$mod);
3308 # instantiate a module object
3309 $id = $CPAN::META->instance('CPAN::Module',$mod);
3313 if ($id->cpan_file ne $dist){ # update only if file is
3314 # different. CPAN prohibits same
3315 # name with different version
3316 $userid = $id->userid || $self->userid($dist);
3318 'CPAN_USERID' => $userid,
3319 'CPAN_VERSION' => $version,
3320 'CPAN_FILE' => $dist,
3324 # instantiate a distribution object
3325 if ($CPAN::META->exists('CPAN::Distribution',$dist)) {
3326 # we do not need CONTAINSMODS unless we do something with
3327 # this dist, so we better produce it on demand.
3329 ## my $obj = $CPAN::META->instance(
3330 ## 'CPAN::Distribution' => $dist
3332 ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental
3334 $CPAN::META->instance(
3335 'CPAN::Distribution' => $dist
3337 'CPAN_USERID' => $userid,
3338 'CPAN_COMMENT' => $comment,
3342 for my $name ($mod,$dist) {
3343 CPAN->debug("exists name[$name]") if $CPAN::DEBUG;
3344 $exists{$name} = undef;
3347 return if $CPAN::Signal;
3351 for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) {
3352 for my $o ($CPAN::META->all_objects($class)) {
3353 next if exists $exists{$o->{ID}};
3354 $CPAN::META->delete($class,$o->{ID});
3355 CPAN->debug("deleting ID[$o->{ID}] in class[$class]")
3362 #-> sub CPAN::Index::rd_modlist ;
3364 my($cl,$index_target) = @_;
3365 return unless defined $index_target;
3366 $CPAN::Frontend->myprint("Going to read $index_target\n");
3367 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3370 while ($_ = $fh->READLINE) {
3372 my @ls = map {"$_\n"} split /\n/, $_;
3373 unshift @ls, "\n" x length($1) if /^(\n+)/;
3377 my $shift = shift(@eval);
3378 if ($shift =~ /^Date:\s+(.*)/){
3379 return if $DATE_OF_03 eq $1;
3382 last if $shift =~ /^\s*$/;
3385 push @eval, q{CPAN::Modulelist->data;};
3387 my($comp) = Safe->new("CPAN::Safe1");
3388 my($eval) = join("", @eval);
3389 my $ret = $comp->reval($eval);
3390 Carp::confess($@) if $@;
3391 return if $CPAN::Signal;
3393 my $obj = $CPAN::META->instance("CPAN::Module",$_);
3394 delete $ret->{$_}{modid}; # not needed here, maybe elsewhere
3395 $obj->set(%{$ret->{$_}});
3396 return if $CPAN::Signal;
3400 #-> sub CPAN::Index::write_metadata_cache ;
3401 sub write_metadata_cache {
3403 return unless $CPAN::Config->{'cache_metadata'};
3404 return unless $CPAN::META->has_usable("Storable");
3406 foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module
3407 CPAN::Distribution)) {
3408 $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok
3410 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3411 $cache->{last_time} = $LAST_TIME;
3412 $cache->{DATE_OF_02} = $DATE_OF_02;
3413 $cache->{PROTOCOL} = PROTOCOL;
3414 $CPAN::Frontend->myprint("Going to write $metadata_file\n");
3415 eval { Storable::nstore($cache, $metadata_file) };
3416 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3419 #-> sub CPAN::Index::read_metadata_cache ;
3420 sub read_metadata_cache {
3422 return unless $CPAN::Config->{'cache_metadata'};
3423 return unless $CPAN::META->has_usable("Storable");
3424 my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3425 return unless -r $metadata_file and -f $metadata_file;
3426 $CPAN::Frontend->myprint("Going to read $metadata_file\n");
3428 eval { $cache = Storable::retrieve($metadata_file) };
3429 $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3430 if (!$cache || ref $cache ne 'HASH'){
3434 if (exists $cache->{PROTOCOL}) {
3435 if (PROTOCOL > $cache->{PROTOCOL}) {
3436 $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ".
3437 "with protocol v%s, requiring v%s\n",
3444 $CPAN::Frontend->mywarn("Ignoring Metadata cache written ".
3445 "with protocol v1.0\n");
3450 while(my($class,$v) = each %$cache) {
3451 next unless $class =~ /^CPAN::/;
3452 $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok
3453 while (my($id,$ro) = each %$v) {
3454 $CPAN::META->{readwrite}{$class}{$id} ||=
3455 $class->new(ID=>$id, RO=>$ro);
3460 unless ($clcnt) { # sanity check
3461 $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n");
3464 if ($idcnt < 1000) {
3465 $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ".
3466 "in $metadata_file\n");
3469 $CPAN::META->{PROTOCOL} ||=
3470 $cache->{PROTOCOL}; # reading does not up or downgrade, but it
3471 # does initialize to some protocol
3472 $LAST_TIME = $cache->{last_time};
3473 $DATE_OF_02 = $cache->{DATE_OF_02};
3474 $CPAN::Frontend->myprint(" Database was generated on $DATE_OF_02\n")
3475 if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
3479 package CPAN::InfoObj;
3484 $self->{RO}{CPAN_USERID}
3487 sub id { shift->{ID}; }
3489 #-> sub CPAN::InfoObj::new ;
3491 my $this = bless {}, shift;
3496 # The set method may only be used by code that reads index data or
3497 # otherwise "objective" data from the outside world. All session
3498 # related material may do anything else with instance variables but
3499 # must not touch the hash under the RO attribute. The reason is that
3500 # the RO hash gets written to Metadata file and is thus persistent.
3502 #-> sub CPAN::InfoObj::set ;
3504 my($self,%att) = @_;
3505 my $class = ref $self;
3507 # This must be ||=, not ||, because only if we write an empty
3508 # reference, only then the set method will write into the readonly
3509 # area. But for Distributions that spring into existence, maybe
3510 # because of a typo, we do not like it that they are written into
3511 # the readonly area and made permanent (at least for a while) and
3512 # that is why we do not "allow" other places to call ->set.
3513 unless ($self->id) {
3514 CPAN->debug("Bug? Empty ID, rejecting");
3517 my $ro = $self->{RO} =
3518 $CPAN::META->{readonly}{$class}{$self->id} ||= {};
3520 while (my($k,$v) = each %att) {
3525 #-> sub CPAN::InfoObj::as_glimpse ;
3529 my $class = ref($self);
3530 $class =~ s/^CPAN:://;
3531 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
3535 #-> sub CPAN::InfoObj::as_string ;
3539 my $class = ref($self);
3540 $class =~ s/^CPAN:://;
3541 push @m, $class, " id = $self->{ID}\n";
3542 for (sort keys %{$self->{RO}}) {
3543 # next if m/^(ID|RO)$/;
3545 if ($_ eq "CPAN_USERID") {
3546 $extra .= " (".$self->author;
3547 my $email; # old perls!
3548 if ($email = $CPAN::META->instance("CPAN::Author",
3551 $extra .= " <$email>";
3553 $extra .= " <no email>";
3556 } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
3557 push @m, sprintf " %-12s %s\n", $_, $self->fullname;
3560 next unless defined $self->{RO}{$_};
3561 push @m, sprintf " %-12s %s%s\n", $_, $self->{RO}{$_}, $extra;
3563 for (sort keys %$self) {
3564 next if m/^(ID|RO)$/;
3565 if (ref($self->{$_}) eq "ARRAY") {
3566 push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
3567 } elsif (ref($self->{$_}) eq "HASH") {
3571 join(" ",keys %{$self->{$_}}),
3574 push @m, sprintf " %-12s %s\n", $_, $self->{$_};
3580 #-> sub CPAN::InfoObj::author ;
3583 $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
3586 #-> sub CPAN::InfoObj::dump ;
3589 require Data::Dumper;
3590 print Data::Dumper::Dumper($self);
3593 package CPAN::Author;
3595 #-> sub CPAN::Author::id
3598 my $id = $self->{ID};
3599 $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
3603 #-> sub CPAN::Author::as_glimpse ;
3607 my $class = ref($self);
3608 $class =~ s/^CPAN:://;
3609 push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
3617 #-> sub CPAN::Author::fullname ;
3619 shift->{RO}{FULLNAME};
3623 #-> sub CPAN::Author::email ;
3624 sub email { shift->{RO}{EMAIL}; }
3626 #-> sub CPAN::Author::ls ;
3631 # adapted from CPAN::Distribution::verifyMD5 ;
3632 my(@csf); # chksumfile
3633 @csf = $self->id =~ /(.)(.)(.*)/;
3634 $csf[1] = join "", @csf[0,1];
3635 $csf[2] = join "", @csf[1,2];
3637 @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0);
3638 unless (grep {$_->[2] eq $csf[1]} @dl) {
3639 $CPAN::Frontend->myprint("No files in the directory of $id\n");
3642 @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0);
3643 unless (grep {$_->[2] eq $csf[2]} @dl) {
3644 $CPAN::Frontend->myprint("No files in the directory of $id\n");
3647 @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1);
3648 $CPAN::Frontend->myprint(join "", map {
3649 sprintf("%8d %10s %s/%s\n", $_->[0], $_->[1], $id, $_->[2])
3650 } sort { $a->[2] cmp $b->[2] } @dl);
3653 # returns an array of arrays, the latter contain (size,mtime,filename)
3654 #-> sub CPAN::Author::dir_listing ;
3657 my $chksumfile = shift;
3658 my $recursive = shift;
3660 File::Spec->catfile($CPAN::Config->{keep_source_where},
3661 "authors", "id", @$chksumfile);
3663 # connect "force" argument with "index_expire".
3665 if (my @stat = stat $lc_want) {
3666 $force = $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
3668 my $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3671 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
3672 $chksumfile->[-1] .= ".gz";
3673 $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3676 $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
3677 CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
3683 # adapted from CPAN::Distribution::MD5_check_file ;
3684 my $fh = FileHandle->new;
3686 if (open $fh, $lc_file){
3689 $eval =~ s/\015?\012/\n/g;
3691 my($comp) = Safe->new();
3692 $cksum = $comp->reval($eval);
3694 rename $lc_file, "$lc_file.bad";
3695 Carp::confess($@) if $@;
3698 Carp::carp "Could not open $lc_file for reading";
3701 for $f (sort keys %$cksum) {
3702 if (exists $cksum->{$f}{isdir}) {
3704 my(@dir) = @$chksumfile;
3706 push @dir, $f, "CHECKSUMS";
3708 [$_->[0], $_->[1], "$f/$_->[2]"]
3709 } $self->dir_listing(\@dir,1);
3711 push @result, [ 0, "-", $f ];
3715 ($cksum->{$f}{"size"}||0),
3716 $cksum->{$f}{"mtime"}||"---",
3724 package CPAN::Distribution;
3727 sub cpan_comment { shift->{RO}{CPAN_COMMENT} }
3731 delete $self->{later};
3734 # CPAN::Distribution::normalize
3737 $s = $self->id unless defined $s;
3741 $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
3743 return $s if $s =~ m:^N/A|^Contact Author: ;
3744 $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4| or
3745 $CPAN::Frontend->mywarn("Strange distribution name [$s]\n");
3746 CPAN->debug("s[$s]") if $CPAN::DEBUG;
3751 #-> sub CPAN::Distribution::color_cmd_tmps ;
3752 sub color_cmd_tmps {
3754 my($depth) = shift || 0;
3755 my($color) = shift || 0;
3756 my($ancestors) = shift || [];
3757 # a distribution needs to recurse into its prereq_pms
3759 return if exists $self->{incommandcolor}
3760 && $self->{incommandcolor}==$color;
3762 $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
3764 # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
3765 my $prereq_pm = $self->prereq_pm;
3766 if (defined $prereq_pm) {
3767 for my $pre (keys %$prereq_pm) {
3768 my $premo = CPAN::Shell->expand("Module",$pre);
3769 $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
3773 delete $self->{sponsored_mods};
3774 delete $self->{badtestcnt};
3776 $self->{incommandcolor} = $color;
3779 #-> sub CPAN::Distribution::as_string ;
3782 $self->containsmods;
3783 $self->SUPER::as_string(@_);
3786 #-> sub CPAN::Distribution::containsmods ;
3789 return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
3790 my $dist_id = $self->{ID};
3791 for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
3792 my $mod_file = $mod->cpan_file or next;
3793 my $mod_id = $mod->{ID} or next;
3794 # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
3796 $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
3798 keys %{$self->{CONTAINSMODS}};
3801 #-> sub CPAN::Distribution::uptodate ;
3805 foreach $c ($self->containsmods) {
3806 my $obj = CPAN::Shell->expandany($c);
3807 return 0 unless $obj->uptodate;
3812 #-> sub CPAN::Distribution::called_for ;
3815 $self->{CALLED_FOR} = $id if defined $id;
3816 return $self->{CALLED_FOR};
3819 #-> sub CPAN::Distribution::safe_chdir ;
3821 my($self,$todir) = @_;
3822 # we die if we cannot chdir and we are debuggable
3823 Carp::confess("safe_chdir called without todir argument")
3824 unless defined $todir and length $todir;
3826 $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
3829 my $cwd = CPAN::anycwd();
3830 $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
3831 qq{to todir[$todir]: $!});
3835 #-> sub CPAN::Distribution::get ;
3840 exists $self->{'build_dir'} and push @e,
3841 "Is already unwrapped into directory $self->{'build_dir'}";
3842 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
3844 my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
3847 # Get the file on local disk
3852 File::Spec->catfile(
3853 $CPAN::Config->{keep_source_where},
3856 split(/\//,$self->id)
3859 $self->debug("Doing localize") if $CPAN::DEBUG;
3860 unless ($local_file =
3861 CPAN::FTP->localize("authors/id/$self->{ID}",
3864 if ($CPAN::Index::DATE_OF_02) {
3865 $note = "Note: Current database in memory was generated ".
3866 "on $CPAN::Index::DATE_OF_02\n";
3868 $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
3870 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
3871 $self->{localfile} = $local_file;
3872 return if $CPAN::Signal;
3877 if ($CPAN::META->has_inst("Digest::MD5")) {
3878 $self->debug("Digest::MD5 is installed, verifying");
3881 $self->debug("Digest::MD5 is NOT installed");
3883 return if $CPAN::Signal;
3886 # Create a clean room and go there
3888 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
3889 my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
3890 $self->safe_chdir($builddir);
3891 $self->debug("Removing tmp") if $CPAN::DEBUG;
3892 File::Path::rmtree("tmp");
3893 mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!";
3895 $self->safe_chdir($sub_wd);
3898 $self->safe_chdir("tmp");
3903 if ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)(?!\n)\Z/i){
3904 $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3905 $self->untar_me($local_file);
3906 } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
3907 $self->unzip_me($local_file);
3908 } elsif ( $local_file =~ /\.pm\.(gz|Z)(?!\n)\Z/) {
3909 $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3910 $self->pm2dir_me($local_file);
3912 $self->{archived} = "NO";
3913 $self->safe_chdir($sub_wd);
3917 # we are still in the tmp directory!
3918 # Let's check if the package has its own directory.
3919 my $dh = DirHandle->new(File::Spec->curdir)
3920 or Carp::croak("Couldn't opendir .: $!");
3921 my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
3923 my ($distdir,$packagedir);
3924 if (@readdir == 1 && -d $readdir[0]) {
3925 $distdir = $readdir[0];
3926 $packagedir = File::Spec->catdir($builddir,$distdir);
3927 $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]")
3929 -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
3931 File::Path::rmtree($packagedir);
3932 rename($distdir,$packagedir) or
3933 Carp::confess("Couldn't rename $distdir to $packagedir: $!");
3934 $self->debug(sprintf("renamed distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
3941 my $userid = $self->cpan_userid;
3943 CPAN->debug("no userid? self[$self]");
3946 my $pragmatic_dir = $userid . '000';
3947 $pragmatic_dir =~ s/\W_//g;
3948 $pragmatic_dir++ while -d "../$pragmatic_dir";
3949 $packagedir = File::Spec->catdir($builddir,$pragmatic_dir);
3950 $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG;
3951 File::Path::mkpath($packagedir);
3953 for $f (@readdir) { # is already without "." and ".."
3954 my $to = File::Spec->catdir($packagedir,$f);
3955 rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!");
3959 $self->safe_chdir($sub_wd);
3963 $self->{'build_dir'} = $packagedir;
3964 $self->safe_chdir($builddir);
3965 File::Path::rmtree("tmp");
3967 my($mpl) = File::Spec->catfile($packagedir,"Makefile.PL");
3968 my($mpl_exists) = -f $mpl;
3969 unless ($mpl_exists) {
3970 # NFS has been reported to have racing problems after the
3971 # renaming of a directory in some environments.
3974 my $mpldh = DirHandle->new($packagedir)
3975 or Carp::croak("Couldn't opendir $packagedir: $!");
3976 $mpl_exists = grep /^Makefile\.PL$/, $mpldh->read;
3979 unless ($mpl_exists) {
3980 $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
3984 my($configure) = File::Spec->catfile($packagedir,"Configure");
3985 if (-f $configure) {
3986 # do we have anything to do?
3987 $self->{'configure'} = $configure;
3988 } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
3989 $CPAN::Frontend->myprint(qq{
3990 Package comes with a Makefile and without a Makefile.PL.
3991 We\'ll try to build it with that Makefile then.
3993 $self->{writemakefile} = "YES";
3996 my $cf = $self->called_for || "unknown";
4001 $cf =~ s|[/\\:]||g; # risk of filesystem damage
4002 $cf = "unknown" unless length($cf);
4003 $CPAN::Frontend->myprint(qq{Package seems to come without Makefile.PL.
4004 (The test -f "$mpl" returned false.)
4005 Writing one on our own (setting NAME to $cf)\a\n});
4006 $self->{had_no_makefile_pl}++;
4009 # Writing our own Makefile.PL
4011 my $fh = FileHandle->new;
4013 or Carp::croak("Could not open >$mpl: $!");
4015 qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
4016 # because there was no Makefile.PL supplied.
4017 # Autogenerated on: }.scalar localtime().qq{
4019 use ExtUtils::MakeMaker;
4020 WriteMakefile(NAME => q[$cf]);
4030 # CPAN::Distribution::untar_me ;
4032 my($self,$local_file) = @_;
4033 $self->{archived} = "tar";
4034 if (CPAN::Tarzip->untar($local_file)) {
4035 $self->{unwrapped} = "YES";
4037 $self->{unwrapped} = "NO";
4041 # CPAN::Distribution::unzip_me ;
4043 my($self,$local_file) = @_;
4044 $self->{archived} = "zip";
4045 if (CPAN::Tarzip->unzip($local_file)) {
4046 $self->{unwrapped} = "YES";
4048 $self->{unwrapped} = "NO";
4054 my($self,$local_file) = @_;
4055 $self->{archived} = "pm";
4056 my $to = File::Basename::basename($local_file);
4057 $to =~ s/\.(gz|Z)(?!\n)\Z//;
4058 if (CPAN::Tarzip->gunzip($local_file,$to)) {
4059 $self->{unwrapped} = "YES";
4061 $self->{unwrapped} = "NO";
4065 #-> sub CPAN::Distribution::new ;
4067 my($class,%att) = @_;
4069 # $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();
4071 my $this = { %att };
4072 return bless $this, $class;
4075 #-> sub CPAN::Distribution::look ;
4079 if ($^O eq 'MacOS') {
4080 $self->Mac::BuildTools::look;
4084 if ( $CPAN::Config->{'shell'} ) {
4085 $CPAN::Frontend->myprint(qq{
4086 Trying to open a subshell in the build directory...
4089 $CPAN::Frontend->myprint(qq{
4090 Your configuration does not define a value for subshells.
4091 Please define it with "o conf shell <your shell>"
4095 my $dist = $self->id;
4097 unless ($dir = $self->dir) {
4100 unless ($dir ||= $self->dir) {
4101 $CPAN::Frontend->mywarn(qq{
4102 Could not determine which directory to use for looking at $dist.
4106 my $pwd = CPAN::anycwd();
4107 $self->safe_chdir($dir);
4108 $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4109 unless (system($CPAN::Config->{'shell'}) == 0) {
4111 $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
4113 $self->safe_chdir($pwd);
4116 # CPAN::Distribution::cvs_import ;
4120 my $dir = $self->dir;
4122 my $package = $self->called_for;
4123 my $module = $CPAN::META->instance('CPAN::Module', $package);
4124 my $version = $module->cpan_version;
4126 my $userid = $self->cpan_userid;
4128 my $cvs_dir = (split /\//, $dir)[-1];
4129 $cvs_dir =~ s/-\d+[^-]+(?!\n)\Z//;
4131 $CPAN::Config->{cvsroot} || $ENV{CVSROOT};
4133 $CPAN::Config->{cvs_site_perl} || $ENV{CVS_SITE_PERL};
4134 if ($cvs_site_perl) {
4135 $cvs_dir = "$cvs_site_perl/$cvs_dir";
4137 my $cvs_log = qq{"imported $package $version sources"};
4138 $version =~ s/\./_/g;
4139 my @cmd = ('cvs', '-d', $cvs_root, 'import', '-m', $cvs_log,
4140 "$cvs_dir", $userid, "v$version");
4142 my $pwd = CPAN::anycwd();
4143 chdir($dir) or $CPAN::Frontend->mydie(qq{Could not chdir to "$dir": $!});
4145 $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4147 $CPAN::Frontend->myprint(qq{@cmd\n});
4148 system(@cmd) == 0 or
4149 $CPAN::Frontend->mydie("cvs import failed");
4150 chdir($pwd) or $CPAN::Frontend->mydie(qq{Could not chdir to "$pwd": $!});
4153 #-> sub CPAN::Distribution::readme ;
4156 my($dist) = $self->id;
4157 my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/;
4158 $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG;
4161 File::Spec->catfile(
4162 $CPAN::Config->{keep_source_where},
4165 split(/\//,"$sans.readme"),
4167 $self->debug("Doing localize") if $CPAN::DEBUG;
4168 $local_file = CPAN::FTP->localize("authors/id/$sans.readme",
4170 or $CPAN::Frontend->mydie(qq{No $sans.readme found});;
4172 if ($^O eq 'MacOS') {
4173 Mac::BuildTools::launch_file($local_file);
4177 my $fh_pager = FileHandle->new;
4178 local($SIG{PIPE}) = "IGNORE";
4179 $fh_pager->open("|$CPAN::Config->{'pager'}")
4180 or die "Could not open pager $CPAN::Config->{'pager'}: $!";
4181 my $fh_readme = FileHandle->new;
4182 $fh_readme->open($local_file)
4183 or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!});
4184 $CPAN::Frontend->myprint(qq{
4187 with pager "$CPAN::Config->{'pager'}"
4190 $fh_pager->print(<$fh_readme>);
4193 #-> sub CPAN::Distribution::verifyMD5 ;
4198 $self->{MD5_STATUS} ||= "";
4199 $self->{MD5_STATUS} eq "OK" and push @e, "MD5 Checksum was ok";
4200 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4202 my($lc_want,$lc_file,@local,$basename);
4203 @local = split(/\//,$self->id);
4205 push @local, "CHECKSUMS";
4207 File::Spec->catfile($CPAN::Config->{keep_source_where},
4208 "authors", "id", @local);
4213 $self->MD5_check_file($lc_want)
4215 return $self->{MD5_STATUS} = "OK";
4217 $lc_file = CPAN::FTP->localize("authors/id/@local",
4220 $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
4221 $local[-1] .= ".gz";
4222 $lc_file = CPAN::FTP->localize("authors/id/@local",
4225 $lc_file =~ s/\.gz(?!\n)\Z//;
4226 CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
4231 $self->MD5_check_file($lc_file);
4234 #-> sub CPAN::Distribution::MD5_check_file ;
4235 sub MD5_check_file {
4236 my($self,$chk_file) = @_;
4237 my($cksum,$file,$basename);
4238 $file = $self->{localfile};
4239 $basename = File::Basename::basename($file);
4240 my $fh = FileHandle->new;
4241 if (open $fh, $chk_file){
4244 $eval =~ s/\015?\012/\n/g;
4246 my($comp) = Safe->new();
4247 $cksum = $comp->reval($eval);
4249 rename $chk_file, "$chk_file.bad";
4250 Carp::confess($@) if $@;
4253 Carp::carp "Could not open $chk_file for reading";
4256 if (exists $cksum->{$basename}{md5}) {
4257 $self->debug("Found checksum for $basename:" .
4258 "$cksum->{$basename}{md5}\n") if $CPAN::DEBUG;
4262 my $eq = $self->eq_MD5($fh,$cksum->{$basename}{'md5'});
4264 $fh = CPAN::Tarzip->TIEHANDLE($file);
4267 # had to inline it, when I tied it, the tiedness got lost on
4268 # the call to eq_MD5. (Jan 1998)
4269 my $md5 = Digest::MD5->new;
4272 while ($fh->READ($ref, 4096) > 0){
4275 my $hexdigest = $md5->hexdigest;
4276 $eq += $hexdigest eq $cksum->{$basename}{'md5-ungz'};
4280 $CPAN::Frontend->myprint("Checksum for $file ok\n");
4281 return $self->{MD5_STATUS} = "OK";
4283 $CPAN::Frontend->myprint(qq{\nChecksum mismatch for }.
4284 qq{distribution file. }.
4285 qq{Please investigate.\n\n}.
4287 $CPAN::META->instance(
4292 my $wrap = qq{I\'d recommend removing $file. Its MD5
4293 checksum is incorrect. Maybe you have configured your 'urllist' with
4294 a bad URL. Please check this array with 'o conf urllist', and
4297 $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
4299 # former versions just returned here but this seems a
4300 # serious threat that deserves a die
4302 # $CPAN::Frontend->myprint("\n\n");
4306 # close $fh if fileno($fh);
4308 $self->{MD5_STATUS} ||= "";
4309 if ($self->{MD5_STATUS} eq "NIL") {
4310 $CPAN::Frontend->mywarn(qq{
4311 Warning: No md5 checksum for $basename in $chk_file.
4313 The cause for this may be that the file is very new and the checksum
4314 has not yet been calculated, but it may also be that something is
4315 going awry right now.
4317 my $answer = ExtUtils::MakeMaker::prompt("Proceed?", "yes");
4318 $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.");
4320 $self->{MD5_STATUS} = "NIL";
4325 #-> sub CPAN::Distribution::eq_MD5 ;
4327 my($self,$fh,$expectMD5) = @_;
4328 my $md5 = Digest::MD5->new;
4330 while (read($fh, $data, 4096)){
4333 # $md5->addfile($fh);
4334 my $hexdigest = $md5->hexdigest;
4335 # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]";
4336 $hexdigest eq $expectMD5;
4339 #-> sub CPAN::Distribution::force ;
4341 # Both modules and distributions know if "force" is in effect by
4342 # autoinspection, not by inspecting a global variable. One of the
4343 # reason why this was chosen to work that way was the treatment of
4344 # dependencies. They should not autpomatically inherit the force
4345 # status. But this has the downside that ^C and die() will return to
4346 # the prompt but will not be able to reset the force_update
4347 # attributes. We try to correct for it currently in the read_metadata
4348 # routine, and immediately before we check for a Signal. I hope this
4349 # works out in one of v1.57_53ff
4352 my($self, $method) = @_;
4354 MD5_STATUS archived build_dir localfile make install unwrapped
4357 delete $self->{$att};
4359 if ($method && $method eq "install") {
4360 $self->{"force_update"}++; # name should probably have been force_install
4364 #-> sub CPAN::Distribution::unforce ;
4367 delete $self->{'force_update'};
4370 #-> sub CPAN::Distribution::isa_perl ;
4373 my $file = File::Basename::basename($self->id);
4374 if ($file =~ m{ ^ perl
4387 } elsif ($self->cpan_comment
4389 $self->cpan_comment =~ /isa_perl\(.+?\)/){
4394 #-> sub CPAN::Distribution::perl ;
4397 my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
4398 my $pwd = CPAN::anycwd();
4399 my $candidate = File::Spec->catfile($pwd,$^X);
4400 $perl ||= $candidate if MM->maybe_command($candidate);
4402 my ($component,$perl_name);
4403 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
4404 PATH_COMPONENT: foreach $component (File::Spec->path(),
4405 $Config::Config{'binexp'}) {
4406 next unless defined($component) && $component;
4407 my($abs) = File::Spec->catfile($component,$perl_name);
4408 if (MM->maybe_command($abs)) {
4418 #-> sub CPAN::Distribution::make ;
4421 $CPAN::Frontend->myprint(sprintf "Running make for %s\n", $self->id);
4422 # Emergency brake if they said install Pippi and get newest perl
4423 if ($self->isa_perl) {
4425 $self->called_for ne $self->id &&
4426 ! $self->{force_update}
4428 # if we die here, we break bundles
4429 $CPAN::Frontend->mywarn(sprintf qq{
4430 The most recent version "%s" of the module "%s"
4431 comes with the current version of perl (%s).
4432 I\'ll build that only if you ask for something like
4437 $CPAN::META->instance(
4451 $self->{archived} eq "NO" and push @e,
4452 "Is neither a tar nor a zip archive.";
4454 $self->{unwrapped} eq "NO" and push @e,
4455 "had problems unarchiving. Please build manually";
4457 exists $self->{writemakefile} &&
4458 $self->{writemakefile} =~ m/ ^ NO\s* ( .* ) /sx and push @e,
4459 $1 || "Had some problem writing Makefile";
4461 defined $self->{'make'} and push @e,
4462 "Has already been processed within this session";
4464 exists $self->{later} and length($self->{later}) and
4465 push @e, $self->{later};
4467 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4469 $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n");
4470 my $builddir = $self->dir;
4471 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
4472 $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;
4474 if ($^O eq 'MacOS') {
4475 Mac::BuildTools::make($self);
4480 if ($self->{'configure'}) {
4481 $system = $self->{'configure'};
4483 my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
4485 # This needs a handler that can be turned on or off:
4486 # $switch = "-MExtUtils::MakeMaker ".
4487 # "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
4489 $system = "$perl $switch Makefile.PL $CPAN::Config->{makepl_arg}";
4491 unless (exists $self->{writemakefile}) {
4492 local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
4495 if ($CPAN::Config->{inactivity_timeout}) {
4497 alarm $CPAN::Config->{inactivity_timeout};
4498 local $SIG{CHLD}; # = sub { wait };
4499 if (defined($pid = fork)) {
4504 # note, this exec isn't necessary if
4505 # inactivity_timeout is 0. On the Mac I'd
4506 # suggest, we set it always to 0.
4510 $CPAN::Frontend->myprint("Cannot fork: $!");
4518 $CPAN::Frontend->myprint($@);
4519 $self->{writemakefile} = "NO $@";
4524 $ret = system($system);
4526 $self->{writemakefile} = "NO Makefile.PL returned status $ret";