ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/lib/CPAN.pm
Revision: 1.1
Committed: Thu Jun 30 14:27:08 2005 UTC (21 years, 3 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
2     package CPAN;
3     $VERSION = '1.76_01';
4     $VERSION = eval $VERSION;
5     # $Id: CPAN.pm,v 1.412 2003/07/31 14:53:04 k Exp $
6    
7     # only used during development:
8     $Revision = "";
9     # $Revision = "[".substr(q$Revision: 1.412 $, 10)."]";
10    
11     use Carp ();
12     use Config ();
13     use Cwd ();
14     use DirHandle;
15     use Exporter ();
16     use ExtUtils::MakeMaker (); # $SelfLoader::DEBUG=1;
17     use File::Basename ();
18     use File::Copy ();
19     use File::Find;
20     use File::Path ();
21     use FileHandle ();
22     use Safe ();
23     use Text::ParseWords ();
24     use Text::Wrap;
25     use File::Spec;
26     use Sys::Hostname;
27     no lib "."; # we need to run chdir all over and we would get at wrong
28     # libraries there
29    
30     require Mac::BuildTools if $^O eq 'MacOS';
31    
32     END { $End++; &cleanup; }
33    
34     %CPAN::DEBUG = qw[
35     CPAN 1
36     Index 2
37     InfoObj 4
38     Author 8
39     Distribution 16
40     Bundle 32
41     Module 64
42     CacheMgr 128
43     Complete 256
44     FTP 512
45     Shell 1024
46     Eval 2048
47     Config 4096
48     Tarzip 8192
49     Version 16384
50     Queue 32768
51     ];
52    
53     $CPAN::DEBUG ||= 0;
54     $CPAN::Signal ||= 0;
55     $CPAN::Frontend ||= "CPAN::Shell";
56     $CPAN::Defaultsite ||= "ftp://ftp.perl.org/pub/CPAN";
57    
58     package CPAN;
59     use strict qw(vars);
60    
61     use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $HAS_USABLE $term
62     $Revision $Signal $End $Suppress_readline $Frontend
63     $Defaultsite $Have_warned);
64    
65     @CPAN::ISA = qw(CPAN::Debug Exporter);
66    
67     @EXPORT = qw(
68     autobundle bundle expand force get cvs_import
69     install make readme recompile shell test clean
70     );
71    
72     #-> sub CPAN::AUTOLOAD ;
73     sub AUTOLOAD {
74     my($l) = $AUTOLOAD;
75     $l =~ s/.*:://;
76     my(%EXPORT);
77     @EXPORT{@EXPORT} = '';
78     CPAN::Config->load unless $CPAN::Config_loaded++;
79     if (exists $EXPORT{$l}){
80     CPAN::Shell->$l(@_);
81     } else {
82     $CPAN::Frontend->mywarn(qq{Unknown command "$AUTOLOAD". }.
83     qq{Type ? for help.
84     });
85     }
86     }
87    
88     #-> sub CPAN::shell ;
89     sub shell {
90     my($self) = @_;
91     $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
92     CPAN::Config->load unless $CPAN::Config_loaded++;
93    
94     my $oprompt = shift || "cpan> ";
95     my $prompt = $oprompt;
96     my $commandline = shift || "";
97    
98     local($^W) = 1;
99     unless ($Suppress_readline) {
100     require Term::ReadLine;
101     if (! $term
102     or
103     $term->ReadLine eq "Term::ReadLine::Stub"
104     ) {
105     $term = Term::ReadLine->new('CPAN Monitor');
106     }
107     if ($term->ReadLine eq "Term::ReadLine::Gnu") {
108     my $attribs = $term->Attribs;
109     $attribs->{attempted_completion_function} = sub {
110     &CPAN::Complete::gnu_cpl;
111     }
112     } else {
113     $readline::rl_completion_function =
114     $readline::rl_completion_function = 'CPAN::Complete::cpl';
115     }
116     if (my $histfile = $CPAN::Config->{'histfile'}) {{
117     unless ($term->can("AddHistory")) {
118     $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
119     last;
120     }
121     my($fh) = FileHandle->new;
122     open $fh, "<$histfile" or last;
123     local $/ = "\n";
124     while (<$fh>) {
125     chomp;
126     $term->AddHistory($_);
127     }
128     close $fh;
129     }}
130     # $term->OUT is autoflushed anyway
131     my $odef = select STDERR;
132     $| = 1;
133     select STDOUT;
134     $| = 1;
135     select $odef;
136     }
137    
138     # no strict; # I do not recall why no strict was here (2000-09-03)
139     $META->checklock();
140     my $cwd = CPAN::anycwd();
141     my $try_detect_readline;
142     $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
143     my $rl_avail = $Suppress_readline ? "suppressed" :
144     ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
145     "available (try 'install Bundle::CPAN')";
146    
147     $CPAN::Frontend->myprint(
148     sprintf qq{
149     cpan shell -- CPAN exploration and modules installation (v%s%s)
150     ReadLine support %s
151    
152     },
153     $CPAN::VERSION,
154     $CPAN::Revision,
155     $rl_avail
156     )
157     unless $CPAN::Config->{'inhibit_startup_message'} ;
158     my($continuation) = "";
159     SHELLCOMMAND: while () {
160     if ($Suppress_readline) {
161     print $prompt;
162     last SHELLCOMMAND unless defined ($_ = <> );
163     chomp;
164     } else {
165     last SHELLCOMMAND unless
166     defined ($_ = $term->readline($prompt, $commandline));
167     }
168     $_ = "$continuation$_" if $continuation;
169     s/^\s+//;
170     next SHELLCOMMAND if /^$/;
171     $_ = 'h' if /^\s*\?/;
172     if (/^(?:q(?:uit)?|bye|exit)$/i) {
173     last SHELLCOMMAND;
174     } elsif (s/\\$//s) {
175     chomp;
176     $continuation = $_;
177     $prompt = " > ";
178     } elsif (/^\!/) {
179     s/^\!//;
180     my($eval) = $_;
181     package CPAN::Eval;
182     use vars qw($import_done);
183     CPAN->import(':DEFAULT') unless $import_done++;
184     CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
185     eval($eval);
186     warn $@ if $@;
187     $continuation = "";
188     $prompt = $oprompt;
189     } elsif (/./) {
190     my(@line);
191     if ($] < 5.00322) { # parsewords had a bug until recently
192     @line = split;
193     } else {
194     eval { @line = Text::ParseWords::shellwords($_) };
195     warn($@), next SHELLCOMMAND if $@;
196     warn("Text::Parsewords could not parse the line [$_]"),
197     next SHELLCOMMAND unless @line;
198     }
199     $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
200     my $command = shift @line;
201     eval { CPAN::Shell->$command(@line) };
202     warn $@ if $@;
203     chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
204     $CPAN::Frontend->myprint("\n");
205     $continuation = "";
206     $prompt = $oprompt;
207     }
208     } continue {
209     $commandline = ""; # I do want to be able to pass a default to
210     # shell, but on the second command I see no
211     # use in that
212     $Signal=0;
213     CPAN::Queue->nullify_queue;
214     if ($try_detect_readline) {
215     if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
216     ||
217     $CPAN::META->has_inst("Term::ReadLine::Perl")
218     ) {
219     delete $INC{"Term/ReadLine.pm"};
220     my $redef = 0;
221     local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
222     require Term::ReadLine;
223     $CPAN::Frontend->myprint("\n$redef subroutines in ".
224     "Term::ReadLine redefined\n");
225     @_ = ($oprompt,"");
226     goto &shell;
227     }
228     }
229     }
230     chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
231     }
232    
233     package CPAN::CacheMgr;
234     @CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
235     use File::Find;
236    
237     package CPAN::Config;
238     use vars qw(%can $dot_cpan);
239    
240     %can = (
241     'commit' => "Commit changes to disk",
242     'defaults' => "Reload defaults from disk",
243     'init' => "Interactive setting of all options",
244     );
245    
246     package CPAN::FTP;
247     use vars qw($Ua $Thesite $Themethod);
248     @CPAN::FTP::ISA = qw(CPAN::Debug);
249    
250     package CPAN::LWP::UserAgent;
251     use vars qw(@ISA $USER $PASSWD $SETUPDONE);
252     # we delay requiring LWP::UserAgent and setting up inheritence until we need it
253    
254     package CPAN::Complete;
255     @CPAN::Complete::ISA = qw(CPAN::Debug);
256     @CPAN::Complete::COMMANDS = sort qw(
257     ! a b d h i m o q r u autobundle clean dump
258     make test install force readme reload look
259     cvs_import ls
260     ) unless @CPAN::Complete::COMMANDS;
261    
262     package CPAN::Index;
263     use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
264     @CPAN::Index::ISA = qw(CPAN::Debug);
265     $LAST_TIME ||= 0;
266     $DATE_OF_03 ||= 0;
267     # use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57
268     sub PROTOCOL { 2.0 }
269    
270     package CPAN::InfoObj;
271     @CPAN::InfoObj::ISA = qw(CPAN::Debug);
272    
273     package CPAN::Author;
274     @CPAN::Author::ISA = qw(CPAN::InfoObj);
275    
276     package CPAN::Distribution;
277     @CPAN::Distribution::ISA = qw(CPAN::InfoObj);
278    
279     package CPAN::Bundle;
280     @CPAN::Bundle::ISA = qw(CPAN::Module);
281    
282     package CPAN::Module;
283     @CPAN::Module::ISA = qw(CPAN::InfoObj);
284    
285     package CPAN::Exception::RecursiveDependency;
286     use overload '""' => "as_string";
287    
288     sub new {
289     my($class) = shift;
290     my($deps) = shift;
291     my @deps;
292     my %seen;
293     for my $dep (@$deps) {
294     push @deps, $dep;
295     last if $seen{$dep}++;
296     }
297     bless { deps => \@deps }, $class;
298     }
299    
300     sub as_string {
301     my($self) = shift;
302     "\nRecursive dependency detected:\n " .
303     join("\n => ", @{$self->{deps}}) .
304     ".\nCannot continue.\n";
305     }
306    
307     package CPAN::Shell;
308     use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
309     @CPAN::Shell::ISA = qw(CPAN::Debug);
310     $COLOR_REGISTERED ||= 0;
311     $PRINT_ORNAMENTING ||= 0;
312    
313     #-> sub CPAN::Shell::AUTOLOAD ;
314     sub AUTOLOAD {
315     my($autoload) = $AUTOLOAD;
316     my $class = shift(@_);
317     # warn "autoload[$autoload] class[$class]";
318     $autoload =~ s/.*:://;
319     if ($autoload =~ /^w/) {
320     if ($CPAN::META->has_inst('CPAN::WAIT')) {
321     CPAN::WAIT->$autoload(@_);
322     } else {
323     $CPAN::Frontend->mywarn(qq{
324     Commands starting with "w" require CPAN::WAIT to be installed.
325     Please consider installing CPAN::WAIT to use the fulltext index.
326     For this you just need to type
327     install CPAN::WAIT
328     });
329     }
330     } else {
331     $CPAN::Frontend->mywarn(qq{Unknown command '$autoload'. }.
332     qq{Type ? for help.
333     });
334     }
335     }
336    
337     package CPAN::Tarzip;
338     use vars qw($AUTOLOAD @ISA $BUGHUNTING);
339     @CPAN::Tarzip::ISA = qw(CPAN::Debug);
340     $BUGHUNTING = 0; # released code must have turned off
341    
342     package CPAN::Queue;
343    
344     # One use of the queue is to determine if we should or shouldn't
345     # announce the availability of a new CPAN module
346    
347     # Now we try to use it for dependency tracking. For that to happen
348     # we need to draw a dependency tree and do the leaves first. This can
349     # easily be reached by running CPAN.pm recursively, but we don't want
350     # to waste memory and run into deep recursion. So what we can do is
351     # this:
352    
353     # CPAN::Queue is the package where the queue is maintained. Dependencies
354     # often have high priority and must be brought to the head of the queue,
355     # possibly by jumping the queue if they are already there. My first code
356     # attempt tried to be extremely correct. Whenever a module needed
357     # immediate treatment, I either unshifted it to the front of the queue,
358     # or, if it was already in the queue, I spliced and let it bypass the
359     # others. This became a too correct model that made it impossible to put
360     # an item more than once into the queue. Why would you need that? Well,
361     # you need temporary duplicates as the manager of the queue is a loop
362     # that
363     #
364     # (1) looks at the first item in the queue without shifting it off
365     #
366     # (2) cares for the item
367     #
368     # (3) removes the item from the queue, *even if its agenda failed and
369     # even if the item isn't the first in the queue anymore* (that way
370     # protecting against never ending queues)
371     #
372     # So if an item has prerequisites, the installation fails now, but we
373     # want to retry later. That's easy if we have it twice in the queue.
374     #
375     # I also expect insane dependency situations where an item gets more
376     # than two lives in the queue. Simplest example is triggered by 'install
377     # Foo Foo Foo'. People make this kind of mistakes and I don't want to
378     # get in the way. I wanted the queue manager to be a dumb servant, not
379     # one that knows everything.
380     #
381     # Who would I tell in this model that the user wants to be asked before
382     # processing? I can't attach that information to the module object,
383     # because not modules are installed but distributions. So I'd have to
384     # tell the distribution object that it should ask the user before
385     # processing. Where would the question be triggered then? Most probably
386     # in CPAN::Distribution::rematein.
387     # Hope that makes sense, my head is a bit off:-) -- AK
388    
389     use vars qw{ @All };
390    
391     # CPAN::Queue::new ;
392     sub new {
393     my($class,$s) = @_;
394     my $self = bless { qmod => $s }, $class;
395     push @All, $self;
396     return $self;
397     }
398    
399     # CPAN::Queue::first ;
400     sub first {
401     my $obj = $All[0];
402     $obj->{qmod};
403     }
404    
405     # CPAN::Queue::delete_first ;
406     sub delete_first {
407     my($class,$what) = @_;
408     my $i;
409     for my $i (0..$#All) {
410     if ( $All[$i]->{qmod} eq $what ) {
411     splice @All, $i, 1;
412     return;
413     }
414     }
415     }
416    
417     # CPAN::Queue::jumpqueue ;
418     sub jumpqueue {
419     my $class = shift;
420     my @what = @_;
421     CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
422     join(",",map {$_->{qmod}} @All),
423     join(",",@what)
424     )) if $CPAN::DEBUG;
425     WHAT: for my $what (reverse @what) {
426     my $jumped = 0;
427     for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
428     CPAN->debug("i[$All[$i]]what[$what]") if $CPAN::DEBUG;
429     if ($All[$i]->{qmod} eq $what){
430     $jumped++;
431     if ($jumped > 100) { # one's OK if e.g. just
432     # processing now; more are OK if
433     # user typed it several times
434     $CPAN::Frontend->mywarn(
435     qq{Object [$what] queued more than 100 times, ignoring}
436     );
437     next WHAT;
438     }
439     }
440     }
441     my $obj = bless { qmod => $what }, $class;
442     unshift @All, $obj;
443     }
444     CPAN->debug(sprintf("after jumpqueue All[%s] what[%s]",
445     join(",",map {$_->{qmod}} @All),
446     join(",",@what)
447     )) if $CPAN::DEBUG;
448     }
449    
450     # CPAN::Queue::exists ;
451     sub exists {
452     my($self,$what) = @_;
453     my @all = map { $_->{qmod} } @All;
454     my $exists = grep { $_->{qmod} eq $what } @All;
455     # warn "in exists what[$what] all[@all] exists[$exists]";
456     $exists;
457     }
458    
459     # CPAN::Queue::delete ;
460     sub delete {
461     my($self,$mod) = @_;
462     @All = grep { $_->{qmod} ne $mod } @All;
463     }
464    
465     # CPAN::Queue::nullify_queue ;
466     sub nullify_queue {
467     @All = ();
468     }
469    
470    
471    
472     package CPAN;
473    
474     $META ||= CPAN->new; # In case we re-eval ourselves we need the ||
475    
476     # from here on only subs.
477     ################################################################################
478    
479     #-> sub CPAN::all_objects ;
480     sub all_objects {
481     my($mgr,$class) = @_;
482     CPAN::Config->load unless $CPAN::Config_loaded++;
483     CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
484     CPAN::Index->reload;
485     values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
486     }
487     *all = \&all_objects;
488    
489     # Called by shell, not in batch mode. In batch mode I see no risk in
490     # having many processes updating something as installations are
491     # continually checked at runtime. In shell mode I suspect it is
492     # unintentional to open more than one shell at a time
493    
494     #-> sub CPAN::checklock ;
495     sub checklock {
496     my($self) = @_;
497     my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
498     if (-f $lockfile && -M _ > 0) {
499     my $fh = FileHandle->new($lockfile) or
500     $CPAN::Frontend->mydie("Could not open $lockfile: $!");
501     my $otherpid = <$fh>;
502     my $otherhost = <$fh>;
503     $fh->close;
504     if (defined $otherpid && $otherpid) {
505     chomp $otherpid;
506     }
507     if (defined $otherhost && $otherhost) {
508     chomp $otherhost;
509     }
510     my $thishost = hostname();
511     if (defined $otherhost && defined $thishost &&
512     $otherhost ne '' && $thishost ne '' &&
513     $otherhost ne $thishost) {
514     $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
515     "reports other host $otherhost and other process $otherpid.\n".
516     "Cannot proceed.\n"));
517     }
518     elsif (defined $otherpid && $otherpid) {
519     return if $$ == $otherpid; # should never happen
520     $CPAN::Frontend->mywarn(
521     qq{
522     There seems to be running another CPAN process (pid $otherpid). Contacting...
523     });
524     if (kill 0, $otherpid) {
525     $CPAN::Frontend->mydie(qq{Other job is running.
526     You may want to kill it and delete the lockfile, maybe. On UNIX try:
527     kill $otherpid
528     rm $lockfile
529     });
530     } elsif (-w $lockfile) {
531     my($ans) =
532     ExtUtils::MakeMaker::prompt
533     (qq{Other job not responding. Shall I overwrite }.
534     qq{the lockfile? (Y/N)},"y");
535     $CPAN::Frontend->myexit("Ok, bye\n")
536     unless $ans =~ /^y/i;
537     } else {
538     Carp::croak(
539     qq{Lockfile $lockfile not writeable by you. }.
540     qq{Cannot proceed.\n}.
541     qq{ On UNIX try:\n}.
542     qq{ rm $lockfile\n}.
543     qq{ and then rerun us.\n}
544     );
545     }
546     } else {
547     $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
548     "reports other process with ID ".
549     "$otherpid. Cannot proceed.\n"));
550     }
551     }
552     my $dotcpan = $CPAN::Config->{cpan_home};
553     eval { File::Path::mkpath($dotcpan);};
554     if ($@) {
555     # A special case at least for Jarkko.
556     my $firsterror = $@;
557     my $seconderror;
558     my $symlinkcpan;
559     if (-l $dotcpan) {
560     $symlinkcpan = readlink $dotcpan;
561     die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
562     eval { File::Path::mkpath($symlinkcpan); };
563     if ($@) {
564     $seconderror = $@;
565     } else {
566     $CPAN::Frontend->mywarn(qq{
567     Working directory $symlinkcpan created.
568     });
569     }
570     }
571     unless (-d $dotcpan) {
572     my $diemess = qq{
573     Your configuration suggests "$dotcpan" as your
574     CPAN.pm working directory. I could not create this directory due
575     to this error: $firsterror\n};
576     $diemess .= qq{
577     As "$dotcpan" is a symlink to "$symlinkcpan",
578     I tried to create that, but I failed with this error: $seconderror
579     } if $seconderror;
580     $diemess .= qq{
581     Please make sure the directory exists and is writable.
582     };
583     $CPAN::Frontend->mydie($diemess);
584     }
585     }
586     my $fh;
587     unless ($fh = FileHandle->new(">$lockfile")) {
588     if ($! =~ /Permission/) {
589     my $incc = $INC{'CPAN/Config.pm'};
590     my $myincc = File::Spec->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
591     $CPAN::Frontend->myprint(qq{
592    
593     Your configuration suggests that CPAN.pm should use a working
594     directory of
595     $CPAN::Config->{cpan_home}
596     Unfortunately we could not create the lock file
597     $lockfile
598     due to permission problems.
599    
600     Please make sure that the configuration variable
601     \$CPAN::Config->{cpan_home}
602     points to a directory where you can write a .lock file. You can set
603     this variable in either
604     $incc
605     or
606     $myincc
607    
608     });
609     }
610     $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
611     }
612     $fh->print($$, "\n");
613     $fh->print(hostname(), "\n");
614     $self->{LOCK} = $lockfile;
615     $fh->close;
616     $SIG{TERM} = sub {
617     &cleanup;
618     $CPAN::Frontend->mydie("Got SIGTERM, leaving");
619     };
620     $SIG{INT} = sub {
621     # no blocks!!!
622     &cleanup if $Signal;
623     $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
624     print "Caught SIGINT\n";
625     $Signal++;
626     };
627    
628     # From: Larry Wall <larry@wall.org>
629     # Subject: Re: deprecating SIGDIE
630     # To: perl5-porters@perl.org
631     # Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
632     #
633     # The original intent of __DIE__ was only to allow you to substitute one
634     # kind of death for another on an application-wide basis without respect
635     # to whether you were in an eval or not. As a global backstop, it should
636     # not be used any more lightly (or any more heavily :-) than class
637     # UNIVERSAL. Any attempt to build a general exception model on it should
638     # be politely squashed. Any bug that causes every eval {} to have to be
639     # modified should be not so politely squashed.
640     #
641     # Those are my current opinions. It is also my optinion that polite
642     # arguments degenerate to personal arguments far too frequently, and that
643     # when they do, it's because both people wanted it to, or at least didn't
644     # sufficiently want it not to.
645     #
646     # Larry
647    
648     # global backstop to cleanup if we should really die
649     $SIG{__DIE__} = \&cleanup;
650     $self->debug("Signal handler set.") if $CPAN::DEBUG;
651     }
652    
653     #-> sub CPAN::DESTROY ;
654     sub DESTROY {
655     &cleanup; # need an eval?
656     }
657    
658     #-> sub CPAN::anycwd ;
659     sub anycwd () {
660     my $getcwd;
661     $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
662     CPAN->$getcwd();
663     }
664    
665     #-> sub CPAN::cwd ;
666     sub cwd {Cwd::cwd();}
667    
668     #-> sub CPAN::getcwd ;
669     sub getcwd {Cwd::getcwd();}
670    
671     #-> sub CPAN::exists ;
672     sub exists {
673     my($mgr,$class,$id) = @_;
674     CPAN::Config->load unless $CPAN::Config_loaded++;
675     CPAN::Index->reload;
676     ### Carp::croak "exists called without class argument" unless $class;
677     $id ||= "";
678     exists $META->{readonly}{$class}{$id} or
679     exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
680     }
681    
682     #-> sub CPAN::delete ;
683     sub delete {
684     my($mgr,$class,$id) = @_;
685     delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
686     delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
687     }
688    
689     #-> sub CPAN::has_usable
690     # has_inst is sometimes too optimistic, we should replace it with this
691     # has_usable whenever a case is given
692     sub has_usable {
693     my($self,$mod,$message) = @_;
694     return 1 if $HAS_USABLE->{$mod};
695     my $has_inst = $self->has_inst($mod,$message);
696     return unless $has_inst;
697     my $usable;
698     $usable = {
699     LWP => [ # we frequently had "Can't locate object
700     # method "new" via package "LWP::UserAgent" at
701     # (eval 69) line 2006
702     sub {require LWP},
703     sub {require LWP::UserAgent},
704     sub {require HTTP::Request},
705     sub {require URI::URL},
706     ],
707     Net::FTP => [
708     sub {require Net::FTP},
709     sub {require Net::Config},
710     ]
711     };
712     if ($usable->{$mod}) {
713     for my $c (0..$#{$usable->{$mod}}) {
714     my $code = $usable->{$mod}[$c];
715     my $ret = eval { &$code() };
716     if ($@) {
717     warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
718     return;
719     }
720     }
721     }
722     return $HAS_USABLE->{$mod} = 1;
723     }
724    
725     #-> sub CPAN::has_inst
726     sub has_inst {
727     my($self,$mod,$message) = @_;
728     Carp::croak("CPAN->has_inst() called without an argument")
729     unless defined $mod;
730     if (defined $message && $message eq "no"
731     ||
732     exists $CPAN::META->{dontload_hash}{$mod} # unsafe meta access, ok
733     ||
734     exists $CPAN::Config->{dontload_hash}{$mod}
735     ) {
736     $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
737     return 0;
738     }
739     my $file = $mod;
740     my $obj;
741     $file =~ s|::|/|g;
742     $file =~ s|/|\\|g if $^O eq 'MSWin32';
743     $file .= ".pm";
744     if ($INC{$file}) {
745     # checking %INC is wrong, because $INC{LWP} may be true
746     # although $INC{"URI/URL.pm"} may have failed. But as
747     # I really want to say "bla loaded OK", I have to somehow
748     # cache results.
749     ### warn "$file in %INC"; #debug
750     return 1;
751     } elsif (eval { require $file }) {
752     # eval is good: if we haven't yet read the database it's
753     # perfect and if we have installed the module in the meantime,
754     # it tries again. The second require is only a NOOP returning
755     # 1 if we had success, otherwise it's retrying
756    
757     $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
758     if ($mod eq "CPAN::WAIT") {
759     push @CPAN::Shell::ISA, CPAN::WAIT;
760     }
761     return 1;
762     } elsif ($mod eq "Net::FTP") {
763     $CPAN::Frontend->mywarn(qq{
764     Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
765     if you just type
766     install Bundle::libnet
767    
768     }) unless $Have_warned->{"Net::FTP"}++;
769     sleep 3;
770     } elsif ($mod eq "Digest::MD5"){
771     $CPAN::Frontend->myprint(qq{
772     CPAN: MD5 security checks disabled because Digest::MD5 not installed.
773     Please consider installing the Digest::MD5 module.
774    
775     });
776     sleep 2;
777     } else {
778     delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
779     }
780     return 0;
781     }
782    
783     #-> sub CPAN::instance ;
784     sub instance {
785     my($mgr,$class,$id) = @_;
786     CPAN::Index->reload;
787     $id ||= "";
788     # unsafe meta access, ok?
789     return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
790     $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
791     }
792    
793     #-> sub CPAN::new ;
794     sub new {
795     bless {}, shift;
796     }
797    
798     #-> sub CPAN::cleanup ;
799     sub cleanup {
800     # warn "cleanup called with arg[@_] End[$End] Signal[$Signal]";
801     local $SIG{__DIE__} = '';
802     my($message) = @_;
803     my $i = 0;
804     my $ineval = 0;
805     my($subroutine);
806     while ((undef,undef,undef,$subroutine) = caller(++$i)) {
807     $ineval = 1, last if
808     $subroutine eq '(eval)';
809     }
810     return if $ineval && !$End;
811     return unless defined $META->{LOCK};
812     return unless -f $META->{LOCK};
813     $META->savehist;
814     unlink $META->{LOCK};
815     # require Carp;
816     # Carp::cluck("DEBUGGING");
817     $CPAN::Frontend->mywarn("Lockfile removed.\n");
818     }
819    
820     #-> sub CPAN::savehist
821     sub savehist {
822     my($self) = @_;
823     my($histfile,$histsize);
824     unless ($histfile = $CPAN::Config->{'histfile'}){
825     $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
826     return;
827     }
828     $histsize = $CPAN::Config->{'histsize'} || 100;
829     if ($CPAN::term){
830     unless ($CPAN::term->can("GetHistory")) {
831     $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
832     return;
833     }
834     } else {
835     return;
836     }
837     my @h = $CPAN::term->GetHistory;
838     splice @h, 0, @h-$histsize if @h>$histsize;
839     my($fh) = FileHandle->new;
840     open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
841     local $\ = local $, = "\n";
842     print $fh @h;
843     close $fh;
844     }
845    
846     sub is_tested {
847     my($self,$what) = @_;
848     $self->{is_tested}{$what} = 1;
849     }
850    
851     sub is_installed {
852     my($self,$what) = @_;
853     delete $self->{is_tested}{$what};
854     }
855    
856     sub set_perl5lib {
857     my($self) = @_;
858     $self->{is_tested} ||= {};
859     return unless %{$self->{is_tested}};
860     my $env = $ENV{PERL5LIB};
861     $env = $ENV{PERLLIB} unless defined $env;
862     my @env;
863     push @env, $env if defined $env and length $env;
864     my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
865     $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
866     $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
867     }
868    
869     package CPAN::CacheMgr;
870    
871     #-> sub CPAN::CacheMgr::as_string ;
872     sub as_string {
873     eval { require Data::Dumper };
874     if ($@) {
875     return shift->SUPER::as_string;
876     } else {
877     return Data::Dumper::Dumper(shift);
878     }
879     }
880    
881     #-> sub CPAN::CacheMgr::cachesize ;
882     sub cachesize {
883     shift->{DU};
884     }
885    
886     #-> sub CPAN::CacheMgr::tidyup ;
887     sub tidyup {
888     my($self) = @_;
889     return unless -d $self->{ID};
890     while ($self->{DU} > $self->{'MAX'} ) {
891     my($toremove) = shift @{$self->{FIFO}};
892     $CPAN::Frontend->myprint(sprintf(
893     "Deleting from cache".
894     ": $toremove (%.1f>%.1f MB)\n",
895     $self->{DU}, $self->{'MAX'})
896     );
897     return if $CPAN::Signal;
898     $self->force_clean_cache($toremove);
899     return if $CPAN::Signal;
900     }
901     }
902    
903     #-> sub CPAN::CacheMgr::dir ;
904     sub dir {
905     shift->{ID};
906     }
907    
908     #-> sub CPAN::CacheMgr::entries ;
909     sub entries {
910     my($self,$dir) = @_;
911     return unless defined $dir;
912     $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
913     $dir ||= $self->{ID};
914     my($cwd) = CPAN::anycwd();
915     chdir $dir or Carp::croak("Can't chdir to $dir: $!");
916     my $dh = DirHandle->new(File::Spec->curdir)
917     or Carp::croak("Couldn't opendir $dir: $!");
918     my(@entries);
919     for ($dh->read) {
920     next if $_ eq "." || $_ eq "..";
921     if (-f $_) {
922     push @entries, File::Spec->catfile($dir,$_);
923     } elsif (-d _) {
924     push @entries, File::Spec->catdir($dir,$_);
925     } else {
926     $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
927     }
928     }
929     chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
930     sort { -M $b <=> -M $a} @entries;
931     }
932    
933     #-> sub CPAN::CacheMgr::disk_usage ;
934     sub disk_usage {
935     my($self,$dir) = @_;
936     return if exists $self->{SIZE}{$dir};
937     return if $CPAN::Signal;
938     my($Du) = 0;
939     find(
940     sub {
941     $File::Find::prune++ if $CPAN::Signal;
942     return if -l $_;
943     if ($^O eq 'MacOS') {
944     require Mac::Files;
945     my $cat = Mac::Files::FSpGetCatInfo($_);
946     $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
947     } else {
948     $Du += (-s _);
949     }
950     },
951     $dir
952     );
953     return if $CPAN::Signal;
954     $self->{SIZE}{$dir} = $Du/1024/1024;
955     push @{$self->{FIFO}}, $dir;
956     $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
957     $self->{DU} += $Du/1024/1024;
958     $self->{DU};
959     }
960    
961     #-> sub CPAN::CacheMgr::force_clean_cache ;
962     sub force_clean_cache {
963     my($self,$dir) = @_;
964     return unless -e $dir;
965     $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
966     if $CPAN::DEBUG;
967     File::Path::rmtree($dir);
968     $self->{DU} -= $self->{SIZE}{$dir};
969     delete $self->{SIZE}{$dir};
970     }
971    
972     #-> sub CPAN::CacheMgr::new ;
973     sub new {
974     my $class = shift;
975     my $time = time;
976     my($debug,$t2);
977     $debug = "";
978     my $self = {
979     ID => $CPAN::Config->{'build_dir'},
980     MAX => $CPAN::Config->{'build_cache'},
981     SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
982     DU => 0
983     };
984     File::Path::mkpath($self->{ID});
985     my $dh = DirHandle->new($self->{ID});
986     bless $self, $class;
987     $self->scan_cache;
988     $t2 = time;
989     $debug .= "timing of CacheMgr->new: ".($t2 - $time);
990     $time = $t2;
991     CPAN->debug($debug) if $CPAN::DEBUG;
992     $self;
993     }
994    
995     #-> sub CPAN::CacheMgr::scan_cache ;
996     sub scan_cache {
997     my $self = shift;
998     return if $self->{SCAN} eq 'never';
999     $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
1000     unless $self->{SCAN} eq 'atstart';
1001     $CPAN::Frontend->myprint(
1002     sprintf("Scanning cache %s for sizes\n",
1003     $self->{ID}));
1004     my $e;
1005     for $e ($self->entries($self->{ID})) {
1006     next if $e eq ".." || $e eq ".";
1007     $self->disk_usage($e);
1008     return if $CPAN::Signal;
1009     }
1010     $self->tidyup;
1011     }
1012    
1013     package CPAN::Debug;
1014    
1015     #-> sub CPAN::Debug::debug ;
1016     sub debug {
1017     my($self,$arg) = @_;
1018     my($caller,$func,$line,@rest) = caller(1); # caller(0) eg
1019     # Complete, caller(1)
1020     # eg readline
1021     ($caller) = caller(0);
1022     $caller =~ s/.*:://;
1023     $arg = "" unless defined $arg;
1024     my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest;
1025     if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){
1026     if ($arg and ref $arg) {
1027     eval { require Data::Dumper };
1028     if ($@) {
1029     $CPAN::Frontend->myprint($arg->as_string);
1030     } else {
1031     $CPAN::Frontend->myprint(Data::Dumper::Dumper($arg));
1032     }
1033     } else {
1034     $CPAN::Frontend->myprint("Debug($caller:$func,$line,[$rest]): $arg\n");
1035     }
1036     }
1037     }
1038    
1039     package CPAN::Config;
1040    
1041     #-> sub CPAN::Config::edit ;
1042     # returns true on successful action
1043     sub edit {
1044     my($self,@args) = @_;
1045     return unless @args;
1046     CPAN->debug("self[$self]args[".join(" | ",@args)."]");
1047     my($o,$str,$func,$args,$key_exists);
1048     $o = shift @args;
1049     if($can{$o}) {
1050     $self->$o(@args);
1051     return 1;
1052     } else {
1053     CPAN->debug("o[$o]") if $CPAN::DEBUG;
1054     if ($o =~ /list$/) {
1055     $func = shift @args;
1056     $func ||= "";
1057     CPAN->debug("func[$func]") if $CPAN::DEBUG;
1058     my $changed;
1059     # Let's avoid eval, it's easier to comprehend without.
1060     if ($func eq "push") {
1061     push @{$CPAN::Config->{$o}}, @args;
1062     $changed = 1;
1063     } elsif ($func eq "pop") {
1064     pop @{$CPAN::Config->{$o}};
1065     $changed = 1;
1066     } elsif ($func eq "shift") {
1067     shift @{$CPAN::Config->{$o}};
1068     $changed = 1;
1069     } elsif ($func eq "unshift") {
1070     unshift @{$CPAN::Config->{$o}}, @args;
1071     $changed = 1;
1072     } elsif ($func eq "splice") {
1073     splice @{$CPAN::Config->{$o}}, @args;
1074     $changed = 1;
1075     } elsif (@args) {
1076     $CPAN::Config->{$o} = [@args];
1077     $changed = 1;
1078     } else {
1079     $self->prettyprint($o);
1080     }
1081     if ($o eq "urllist" && $changed) {
1082     # reset the cached values
1083     undef $CPAN::FTP::Thesite;
1084     undef $CPAN::FTP::Themethod;
1085     }
1086     return $changed;
1087     } else {
1088     $CPAN::Config->{$o} = $args[0] if defined $args[0];
1089     $self->prettyprint($o);
1090     }
1091     }
1092     }
1093    
1094     sub prettyprint {
1095     my($self,$k) = @_;
1096     my $v = $CPAN::Config->{$k};
1097     if (ref $v) {
1098     my(@report) = ref $v eq "ARRAY" ?
1099     @$v :
1100     map { sprintf(" %-18s => %s\n",
1101     $_,
1102     defined $v->{$_} ? $v->{$_} : "UNDEFINED"
1103     )} keys %$v;
1104     $CPAN::Frontend->myprint(
1105     join(
1106     "",
1107     sprintf(
1108     " %-18s\n",
1109     $k
1110     ),
1111     map {"\t$_\n"} @report
1112     )
1113     );
1114     } elsif (defined $v) {
1115     $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1116     } else {
1117     $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, "UNDEFINED");
1118     }
1119     }
1120    
1121     #-> sub CPAN::Config::commit ;
1122     sub commit {
1123     my($self,$configpm) = @_;
1124     unless (defined $configpm){
1125     $configpm ||= $INC{"CPAN/MyConfig.pm"};
1126     $configpm ||= $INC{"CPAN/Config.pm"};
1127     $configpm || Carp::confess(q{
1128     CPAN::Config::commit called without an argument.
1129     Please specify a filename where to save the configuration or try
1130     "o conf init" to have an interactive course through configing.
1131     });
1132     }
1133     my($mode);
1134     if (-f $configpm) {
1135     $mode = (stat $configpm)[2];
1136     if ($mode && ! -w _) {
1137     Carp::confess("$configpm is not writable");
1138     }
1139     }
1140    
1141     my $msg;
1142     $msg = <<EOF unless $configpm =~ /MyConfig/;
1143    
1144     # This is CPAN.pm's systemwide configuration file. This file provides
1145     # defaults for users, and the values can be changed in a per-user
1146     # configuration file. The user-config file is being looked for as
1147     # ~/.cpan/CPAN/MyConfig.pm.
1148    
1149     EOF
1150     $msg ||= "\n";
1151     my($fh) = FileHandle->new;
1152     rename $configpm, "$configpm~" if -f $configpm;
1153     open $fh, ">$configpm" or
1154     $CPAN::Frontend->mydie("Couldn't open >$configpm: $!");
1155     $fh->print(qq[$msg\$CPAN::Config = \{\n]);
1156     foreach (sort keys %$CPAN::Config) {
1157     $fh->print(
1158     " '$_' => ",
1159     ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$_}),
1160     ",\n"
1161     );
1162     }
1163    
1164     $fh->print("};\n1;\n__END__\n");
1165     close $fh;
1166    
1167     #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
1168     #chmod $mode, $configpm;
1169     ###why was that so? $self->defaults;
1170     $CPAN::Frontend->myprint("commit: wrote $configpm\n");
1171     1;
1172     }
1173    
1174     *default = \&defaults;
1175     #-> sub CPAN::Config::defaults ;
1176     sub defaults {
1177     my($self) = @_;
1178     $self->unload;
1179     $self->load;
1180     1;
1181     }
1182    
1183     sub init {
1184     my($self) = @_;
1185     undef $CPAN::Config->{'inhibit_startup_message'}; # lazy trick to
1186     # have the least
1187     # important
1188     # variable
1189     # undefined
1190     $self->load;
1191     1;
1192     }
1193    
1194     # This is a piece of repeated code that is abstracted here for
1195     # maintainability. RMB
1196     #
1197     sub _configpmtest {
1198     my($configpmdir, $configpmtest) = @_;
1199     if (-w $configpmtest) {
1200     return $configpmtest;
1201     } elsif (-w $configpmdir) {
1202     #_#_# following code dumped core on me with 5.003_11, a.k.
1203     my $configpm_bak = "$configpmtest.bak";
1204     unlink $configpm_bak if -f $configpm_bak;
1205     if( -f $configpmtest ) {
1206     if( rename $configpmtest, $configpm_bak ) {
1207     $CPAN::Frontend->mywarn(<<END)
1208     Old configuration file $configpmtest
1209     moved to $configpm_bak
1210     END
1211     }
1212     }
1213     my $fh = FileHandle->new;
1214     if ($fh->open(">$configpmtest")) {
1215     $fh->print("1;\n");
1216     return $configpmtest;
1217     } else {
1218     # Should never happen
1219     Carp::confess("Cannot open >$configpmtest");
1220     }
1221     } else { return }
1222     }
1223    
1224     #-> sub CPAN::Config::load ;
1225     sub load {
1226     my($self) = shift;
1227     my(@miss);
1228     use Carp;
1229     eval {require CPAN::Config;}; # We eval because of some
1230     # MakeMaker problems
1231     unless ($dot_cpan++){
1232     unshift @INC, File::Spec->catdir($ENV{HOME},".cpan");
1233     eval {require CPAN::MyConfig;}; # where you can override
1234     # system wide settings
1235     shift @INC;
1236     }
1237     return unless @miss = $self->missing_config_data;
1238    
1239     require CPAN::FirstTime;
1240     my($configpm,$fh,$redo,$theycalled);
1241     $redo ||= "";
1242     $theycalled++ if @miss==1 && $miss[0] eq 'inhibit_startup_message';
1243     if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
1244     $configpm = $INC{"CPAN/Config.pm"};
1245     $redo++;
1246     } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
1247     $configpm = $INC{"CPAN/MyConfig.pm"};
1248     $redo++;
1249     } else {
1250     my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
1251     my($configpmdir) = File::Spec->catdir($path_to_cpan,"CPAN");
1252     my($configpmtest) = File::Spec->catfile($configpmdir,"Config.pm");
1253     if (-d $configpmdir or File::Path::mkpath($configpmdir)) {
1254     $configpm = _configpmtest($configpmdir,$configpmtest);
1255     }
1256     unless ($configpm) {
1257     $configpmdir = File::Spec->catdir($ENV{HOME},".cpan","CPAN");
1258     File::Path::mkpath($configpmdir);
1259     $configpmtest = File::Spec->catfile($configpmdir,"MyConfig.pm");
1260     $configpm = _configpmtest($configpmdir,$configpmtest);
1261     unless ($configpm) {
1262     Carp::confess(qq{WARNING: CPAN.pm is unable to }.
1263     qq{create a configuration file.});
1264     }
1265     }
1266     }
1267     local($") = ", ";
1268     $CPAN::Frontend->myprint(<<END) if $redo && ! $theycalled;
1269     We have to reconfigure CPAN.pm due to following uninitialized parameters:
1270    
1271     @miss
1272     END
1273     $CPAN::Frontend->myprint(qq{
1274     $configpm initialized.
1275     });
1276     sleep 2;
1277     CPAN::FirstTime::init($configpm);
1278     }
1279    
1280     #-> sub CPAN::Config::missing_config_data ;
1281     sub missing_config_data {
1282     my(@miss);
1283     for (
1284     "cpan_home", "keep_source_where", "build_dir", "build_cache",
1285     "scan_cache", "index_expire", "gzip", "tar", "unzip", "make",
1286     "pager",
1287     "makepl_arg", "make_arg", "make_install_arg", "urllist",
1288     "inhibit_startup_message", "ftp_proxy", "http_proxy", "no_proxy",
1289     "prerequisites_policy",
1290     "cache_metadata",
1291     ) {
1292     push @miss, $_ unless defined $CPAN::Config->{$_};
1293     }
1294     return @miss;
1295     }
1296    
1297     #-> sub CPAN::Config::unload ;
1298     sub unload {
1299     delete $INC{'CPAN/MyConfig.pm'};
1300     delete $INC{'CPAN/Config.pm'};
1301     }
1302    
1303     #-> sub CPAN::Config::help ;
1304     sub help {
1305     $CPAN::Frontend->myprint(q[
1306     Known options:
1307     defaults reload default config values from disk
1308     commit commit session changes to disk
1309     init go through a dialog to set all parameters
1310    
1311     You may edit key values in the follow fashion (the "o" is a literal
1312     letter o):
1313    
1314     o conf build_cache 15
1315    
1316     o conf build_dir "/foo/bar"
1317    
1318     o conf urllist shift
1319    
1320     o conf urllist unshift ftp://ftp.foo.bar/
1321    
1322     ]);
1323     undef; #don't reprint CPAN::Config
1324     }
1325    
1326     #-> sub CPAN::Config::cpl ;
1327     sub cpl {
1328     my($word,$line,$pos) = @_;
1329     $word ||= "";
1330     CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1331     my(@words) = split " ", substr($line,0,$pos+1);
1332     if (
1333     defined($words[2])
1334     and
1335     (
1336     $words[2] =~ /list$/ && @words == 3
1337     ||
1338     $words[2] =~ /list$/ && @words == 4 && length($word)
1339     )
1340     ) {
1341     return grep /^\Q$word\E/, qw(splice shift unshift pop push);
1342     } elsif (@words >= 4) {
1343     return ();
1344     }
1345     my(@o_conf) = (keys %CPAN::Config::can, keys %$CPAN::Config);
1346     return grep /^\Q$word\E/, @o_conf;
1347     }
1348    
1349     package CPAN::Shell;
1350    
1351     #-> sub CPAN::Shell::h ;
1352     sub h {
1353     my($class,$about) = @_;
1354     if (defined $about) {
1355     $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
1356     } else {
1357     $CPAN::Frontend->myprint(q{
1358     Display Information
1359     command argument description
1360     a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
1361     i WORD or /REGEXP/ about anything of above
1362     r NONE reinstall recommendations
1363     ls AUTHOR about files in the author's directory
1364    
1365     Download, Test, Make, Install...
1366     get download
1367     make make (implies get)
1368     test MODULES, make test (implies make)
1369     install DISTS, BUNDLES make install (implies test)
1370     clean make clean
1371     look open subshell in these dists' directories
1372     readme display these dists' README files
1373    
1374     Other
1375     h,? display this menu ! perl-code eval a perl command
1376     o conf [opt] set and query options q quit the cpan shell
1377     reload cpan load CPAN.pm again reload index load newer indices
1378     autobundle Snapshot force cmd unconditionally do cmd});
1379     }
1380     }
1381    
1382     *help = \&h;
1383    
1384     #-> sub CPAN::Shell::a ;
1385     sub a {
1386     my($self,@arg) = @_;
1387     # authors are always UPPERCASE
1388     for (@arg) {
1389     $_ = uc $_ unless /=/;
1390     }
1391     $CPAN::Frontend->myprint($self->format_result('Author',@arg));
1392     }
1393    
1394     #-> sub CPAN::Shell::ls ;
1395     sub ls {
1396     my($self,@arg) = @_;
1397     my @accept;
1398     for (@arg) {
1399     unless (/^[A-Z\-]+$/i) {
1400     $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
1401     next;
1402     }
1403     push @accept, uc $_;
1404     }
1405     for my $a (@accept){
1406     my $author = $self->expand('Author',$a) or die "No author found for $a";
1407     $author->ls;
1408     }
1409     }
1410    
1411     #-> sub CPAN::Shell::local_bundles ;
1412     sub local_bundles {
1413     my($self,@which) = @_;
1414     my($incdir,$bdir,$dh);
1415     foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
1416     my @bbase = "Bundle";
1417     while (my $bbase = shift @bbase) {
1418     $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
1419     CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
1420     if ($dh = DirHandle->new($bdir)) { # may fail
1421     my($entry);
1422     for $entry ($dh->read) {
1423     next if $entry =~ /^\./;
1424     if (-d File::Spec->catdir($bdir,$entry)){
1425     push @bbase, "$bbase\::$entry";
1426     } else {
1427     next unless $entry =~ s/\.pm(?!\n)\Z//;
1428     $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
1429     }
1430     }
1431     }
1432     }
1433     }
1434     }
1435    
1436     #-> sub CPAN::Shell::b ;
1437     sub b {
1438     my($self,@which) = @_;
1439     CPAN->debug("which[@which]") if $CPAN::DEBUG;
1440     $self->local_bundles;
1441     $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
1442     }
1443    
1444     #-> sub CPAN::Shell::d ;
1445     sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
1446    
1447     #-> sub CPAN::Shell::m ;
1448     sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
1449     my $self = shift;
1450     $CPAN::Frontend->myprint($self->format_result('Module',@_));
1451     }
1452    
1453     #-> sub CPAN::Shell::i ;
1454     sub i {
1455     my($self) = shift;
1456     my(@args) = @_;
1457     my(@type,$type,@m);
1458     @type = qw/Author Bundle Distribution Module/;
1459     @args = '/./' unless @args;
1460     my(@result);
1461     for $type (@type) {
1462     push @result, $self->expand($type,@args);
1463     }
1464     my $result = @result == 1 ?
1465     $result[0]->as_string :
1466     @result == 0 ?
1467     "No objects found of any type for argument @args\n" :
1468     join("",
1469     (map {$_->as_glimpse} @result),
1470     scalar @result, " items found\n",
1471     );
1472     $CPAN::Frontend->myprint($result);
1473     }
1474    
1475     #-> sub CPAN::Shell::o ;
1476    
1477     # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf'
1478     # should have been called set and 'o debug' maybe 'set debug'
1479     sub o {
1480     my($self,$o_type,@o_what) = @_;
1481     $o_type ||= "";
1482     CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1483     if ($o_type eq 'conf') {
1484     shift @o_what if @o_what && $o_what[0] eq 'help';
1485     if (!@o_what) { # print all things, "o conf"
1486     my($k,$v);
1487     $CPAN::Frontend->myprint("CPAN::Config options");
1488     if (exists $INC{'CPAN/Config.pm'}) {
1489     $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1490     }
1491     if (exists $INC{'CPAN/MyConfig.pm'}) {
1492     $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1493     }
1494     $CPAN::Frontend->myprint(":\n");
1495     for $k (sort keys %CPAN::Config::can) {
1496     $v = $CPAN::Config::can{$k};
1497     $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
1498     }
1499     $CPAN::Frontend->myprint("\n");
1500     for $k (sort keys %$CPAN::Config) {
1501     CPAN::Config->prettyprint($k);
1502     }
1503     $CPAN::Frontend->myprint("\n");
1504     } elsif (!CPAN::Config->edit(@o_what)) {
1505     $CPAN::Frontend->myprint(qq{Type 'o conf' to view configuration }.
1506     qq{edit options\n\n});
1507     }
1508     } elsif ($o_type eq 'debug') {
1509     my(%valid);
1510     @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1511     if (@o_what) {
1512     while (@o_what) {
1513     my($what) = shift @o_what;
1514     if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
1515     $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
1516     next;
1517     }
1518     if ( exists $CPAN::DEBUG{$what} ) {
1519     $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1520     } elsif ($what =~ /^\d/) {
1521     $CPAN::DEBUG = $what;
1522     } elsif (lc $what eq 'all') {
1523     my($max) = 0;
1524     for (values %CPAN::DEBUG) {
1525     $max += $_;
1526     }
1527     $CPAN::DEBUG = $max;
1528     } else {
1529     my($known) = 0;
1530     for (keys %CPAN::DEBUG) {
1531     next unless lc($_) eq lc($what);
1532     $CPAN::DEBUG |= $CPAN::DEBUG{$_};
1533     $known = 1;
1534     }
1535     $CPAN::Frontend->myprint("unknown argument [$what]\n")
1536     unless $known;
1537     }
1538     }
1539     } else {
1540     my $raw = "Valid options for debug are ".
1541     join(", ",sort(keys %CPAN::DEBUG), 'all').
1542     qq{ or a number. Completion works on the options. }.
1543     qq{Case is ignored.};
1544     require Text::Wrap;
1545     $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
1546     $CPAN::Frontend->myprint("\n\n");
1547     }
1548     if ($CPAN::DEBUG) {
1549     $CPAN::Frontend->myprint("Options set for debugging:\n");
1550     my($k,$v);
1551     for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1552     $v = $CPAN::DEBUG{$k};
1553     $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
1554     if $v & $CPAN::DEBUG;
1555     }
1556     } else {
1557     $CPAN::Frontend->myprint("Debugging turned off completely.\n");
1558     }
1559     } else {
1560     $CPAN::Frontend->myprint(qq{
1561     Known options:
1562     conf set or get configuration variables
1563     debug set or get debugging options
1564     });
1565     }
1566     }
1567    
1568     sub paintdots_onreload {
1569     my($ref) = shift;
1570     sub {
1571     if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
1572     my($subr) = $1;
1573     ++$$ref;
1574     local($|) = 1;
1575     # $CPAN::Frontend->myprint(".($subr)");
1576     $CPAN::Frontend->myprint(".");
1577     return;
1578     }
1579     warn @_;
1580     };
1581     }
1582    
1583     #-> sub CPAN::Shell::reload ;
1584     sub reload {
1585     my($self,$command,@arg) = @_;
1586     $command ||= "";
1587     $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1588     if ($command =~ /cpan/i) {
1589     for my $f (qw(CPAN.pm CPAN/FirstTime.pm)) {
1590     next unless $INC{$f};
1591     CPAN->debug("reloading the whole $f") if $CPAN::DEBUG;
1592     my $fh = FileHandle->new($INC{$f});
1593     local($/);
1594     my $redef = 0;
1595     local($SIG{__WARN__}) = paintdots_onreload(\$redef);
1596     eval <$fh>;
1597     warn $@ if $@;
1598     $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
1599     }
1600     } elsif ($command =~ /index/) {
1601     CPAN::Index->force_reload;
1602     } else {
1603     $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
1604     index re-reads the index files\n});
1605     }
1606     }
1607    
1608     #-> sub CPAN::Shell::_binary_extensions ;
1609     sub _binary_extensions {
1610     my($self) = shift @_;
1611     my(@result,$module,%seen,%need,$headerdone);
1612     for $module ($self->expand('Module','/./')) {
1613     my $file = $module->cpan_file;
1614     next if $file eq "N/A";
1615     next if $file =~ /^Contact Author/;
1616     my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
1617     next if $dist->isa_perl;
1618     next unless $module->xs_file;
1619     local($|) = 1;
1620     $CPAN::Frontend->myprint(".");
1621     push @result, $module;
1622     }
1623     # print join " | ", @result;
1624     $CPAN::Frontend->myprint("\n");
1625     return @result;
1626     }
1627    
1628     #-> sub CPAN::Shell::recompile ;
1629     sub recompile {
1630     my($self) = shift @_;
1631     my($module,@module,$cpan_file,%dist);
1632     @module = $self->_binary_extensions();
1633     for $module (@module){ # we force now and compile later, so we
1634     # don't do it twice
1635     $cpan_file = $module->cpan_file;
1636     my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1637     $pack->force;
1638     $dist{$cpan_file}++;
1639     }
1640     for $cpan_file (sort keys %dist) {
1641     $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
1642     my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1643     $pack->install;
1644     $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1645     # stop a package from recompiling,
1646     # e.g. IO-1.12 when we have perl5.003_10
1647     }
1648     }
1649    
1650     #-> sub CPAN::Shell::_u_r_common ;
1651     sub _u_r_common {
1652     my($self) = shift @_;
1653     my($what) = shift @_;
1654     CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1655     Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
1656     $what && $what =~ /^[aru]$/;
1657     my(@args) = @_;
1658     @args = '/./' unless @args;
1659     my(@result,$module,%seen,%need,$headerdone,
1660     $version_undefs,$version_zeroes);
1661     $version_undefs = $version_zeroes = 0;
1662     my $sprintf = "%s%-25s%s %9s %9s %s\n";
1663     my @expand = $self->expand('Module',@args);
1664     my $expand = scalar @expand;
1665     if (0) { # Looks like noise to me, was very useful for debugging
1666     # for metadata cache
1667     $CPAN::Frontend->myprint(sprintf "%d matches in the database\n", $expand);
1668     }
1669     for $module (@expand) {
1670     my $file = $module->cpan_file;
1671     next unless defined $file; # ??
1672     my($latest) = $module->cpan_version;
1673     my($inst_file) = $module->inst_file;
1674     my($have);
1675     return if $CPAN::Signal;
1676     if ($inst_file){
1677     if ($what eq "a") {
1678     $have = $module->inst_version;
1679     } elsif ($what eq "r") {
1680     $have = $module->inst_version;
1681     local($^W) = 0;
1682     if ($have eq "undef"){
1683     $version_undefs++;
1684     } elsif ($have == 0){
1685     $version_zeroes++;
1686     }
1687     next unless CPAN::Version->vgt($latest, $have);
1688     # to be pedantic we should probably say:
1689     # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1690     # to catch the case where CPAN has a version 0 and we have a version undef
1691     } elsif ($what eq "u") {
1692     next;
1693     }
1694     } else {
1695     if ($what eq "a") {
1696     next;
1697     } elsif ($what eq "r") {
1698     next;
1699     } elsif ($what eq "u") {
1700     $have = "-";
1701     }
1702     }
1703     return if $CPAN::Signal; # this is sometimes lengthy
1704     $seen{$file} ||= 0;
1705     if ($what eq "a") {
1706     push @result, sprintf "%s %s\n", $module->id, $have;
1707     } elsif ($what eq "r") {
1708     push @result, $module->id;
1709     next if $seen{$file}++;
1710     } elsif ($what eq "u") {
1711     push @result, $module->id;
1712     next if $seen{$file}++;
1713     next if $file =~ /^Contact/;
1714     }
1715     unless ($headerdone++){
1716     $CPAN::Frontend->myprint("\n");
1717     $CPAN::Frontend->myprint(sprintf(
1718     $sprintf,
1719     "",
1720     "Package namespace",
1721     "",
1722     "installed",
1723     "latest",
1724     "in CPAN file"
1725     ));
1726     }
1727     my $color_on = "";
1728     my $color_off = "";
1729     if (
1730     $COLOR_REGISTERED
1731     &&
1732     $CPAN::META->has_inst("Term::ANSIColor")
1733     &&
1734     $module->{RO}{description}
1735     ) {
1736     $color_on = Term::ANSIColor::color("green");
1737     $color_off = Term::ANSIColor::color("reset");
1738     }
1739     $CPAN::Frontend->myprint(sprintf $sprintf,
1740     $color_on,
1741     $module->id,
1742     $color_off,
1743     $have,
1744     $latest,
1745     $file);
1746     $need{$module->id}++;
1747     }
1748     unless (%need) {
1749     if ($what eq "u") {
1750     $CPAN::Frontend->myprint("No modules found for @args\n");
1751     } elsif ($what eq "r") {
1752     $CPAN::Frontend->myprint("All modules are up to date for @args\n");
1753     }
1754     }
1755     if ($what eq "r") {
1756     if ($version_zeroes) {
1757     my $s_has = $version_zeroes > 1 ? "s have" : " has";
1758     $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1759     qq{a version number of 0\n});
1760     }
1761     if ($version_undefs) {
1762     my $s_has = $version_undefs > 1 ? "s have" : " has";
1763     $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1764     qq{parseable version number\n});
1765     }
1766     }
1767     @result;
1768     }
1769    
1770     #-> sub CPAN::Shell::r ;
1771     sub r {
1772     shift->_u_r_common("r",@_);
1773     }
1774    
1775     #-> sub CPAN::Shell::u ;
1776     sub u {
1777     shift->_u_r_common("u",@_);
1778     }
1779    
1780     #-> sub CPAN::Shell::autobundle ;
1781     sub autobundle {
1782     my($self) = shift;
1783     CPAN::Config->load unless $CPAN::Config_loaded++;
1784     my(@bundle) = $self->_u_r_common("a",@_);
1785     my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1786     File::Path::mkpath($todir);
1787     unless (-d $todir) {
1788     $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1789     return;
1790     }
1791     my($y,$m,$d) = (localtime)[5,4,3];
1792     $y+=1900;
1793     $m++;
1794     my($c) = 0;
1795     my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1796     my($to) = File::Spec->catfile($todir,"$me.pm");
1797     while (-f $to) {
1798     $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1799     $to = File::Spec->catfile($todir,"$me.pm");
1800     }
1801     my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1802     $fh->print(
1803     "package Bundle::$me;\n\n",
1804     "\$VERSION = '0.01';\n\n",
1805     "1;\n\n",
1806     "__END__\n\n",
1807     "=head1 NAME\n\n",
1808     "Bundle::$me - Snapshot of installation on ",
1809     $Config::Config{'myhostname'},
1810     " on ",
1811     scalar(localtime),
1812     "\n\n=head1 SYNOPSIS\n\n",
1813     "perl -MCPAN -e 'install Bundle::$me'\n\n",
1814     "=head1 CONTENTS\n\n",
1815     join("\n", @bundle),
1816     "\n\n=head1 CONFIGURATION\n\n",
1817     Config->myconfig,
1818     "\n\n=head1 AUTHOR\n\n",
1819     "This Bundle has been generated automatically ",
1820     "by the autobundle routine in CPAN.pm.\n",
1821     );
1822     $fh->close;
1823     $CPAN::Frontend->myprint("\nWrote bundle file
1824     $to\n\n");
1825     }
1826    
1827     #-> sub CPAN::Shell::expandany ;
1828     sub expandany {
1829     my($self,$s) = @_;
1830     CPAN->debug("s[$s]") if $CPAN::DEBUG;
1831     if ($s =~ m|/|) { # looks like a file
1832     $s = CPAN::Distribution->normalize($s);
1833     return $CPAN::META->instance('CPAN::Distribution',$s);
1834     # Distributions spring into existence, not expand
1835     } elsif ($s =~ m|^Bundle::|) {
1836     $self->local_bundles; # scanning so late for bundles seems
1837     # both attractive and crumpy: always
1838     # current state but easy to forget
1839     # somewhere
1840     return $self->expand('Bundle',$s);
1841     } else {
1842     return $self->expand('Module',$s)
1843     if $CPAN::META->exists('CPAN::Module',$s);
1844     }
1845     return;
1846     }
1847    
1848     #-> sub CPAN::Shell::expand ;
1849     sub expand {
1850     shift;
1851     my($type,@args) = @_;
1852     my($arg,@m);
1853     CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1854     for $arg (@args) {
1855     my($regex,$command);
1856     if ($arg =~ m|^/(.*)/$|) {
1857     $regex = $1;
1858     } elsif ($arg =~ m/=/) {
1859     $command = 1;
1860     }
1861     my $class = "CPAN::$type";
1862     my $obj;
1863     CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1864     $class,
1865     defined $regex ? $regex : "UNDEFINED",
1866     $command || "UNDEFINED",
1867     ) if $CPAN::DEBUG;
1868     if (defined $regex) {
1869     for $obj (
1870     sort
1871     {$a->id cmp $b->id}
1872     $CPAN::META->all_objects($class)
1873     ) {
1874     unless ($obj->id){
1875     # BUG, we got an empty object somewhere
1876     require Data::Dumper;
1877     CPAN->debug(sprintf(
1878     "Bug in CPAN: Empty id on obj[%s][%s]",
1879     $obj,
1880     Data::Dumper::Dumper($obj)
1881     )) if $CPAN::DEBUG;
1882     next;
1883     }
1884     push @m, $obj
1885     if $obj->id =~ /$regex/i
1886     or
1887     (
1888     (
1889     $] < 5.00303 ### provide sort of
1890     ### compatibility with 5.003
1891     ||
1892     $obj->can('name')
1893     )
1894     &&
1895     $obj->name =~ /$regex/i
1896     );
1897     }
1898     } elsif ($command) {
1899     die "equal sign in command disabled (immature interface), ".
1900     "you can set
1901     ! \$CPAN::Shell::ADVANCED_QUERY=1
1902     to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1903     that may go away anytime.\n"
1904     unless $ADVANCED_QUERY;
1905     my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1906     my($matchcrit) = $criterion =~ m/^~(.+)/;
1907     for my $self (
1908     sort
1909     {$a->id cmp $b->id}
1910     $CPAN::META->all_objects($class)
1911     ) {
1912     my $lhs = $self->$method() or next; # () for 5.00503
1913     if ($matchcrit) {
1914     push @m, $self if $lhs =~ m/$matchcrit/;
1915     } else {
1916     push @m, $self if $lhs eq $criterion;
1917     }
1918     }
1919     } else {
1920     my($xarg) = $arg;
1921     if ( $type eq 'Bundle' ) {
1922     $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1923     } elsif ($type eq "Distribution") {
1924     $xarg = CPAN::Distribution->normalize($arg);
1925     }
1926     if ($CPAN::META->exists($class,$xarg)) {
1927     $obj = $CPAN::META->instance($class,$xarg);
1928     } elsif ($CPAN::META->exists($class,$arg)) {
1929     $obj = $CPAN::META->instance($class,$arg);
1930     } else {
1931     next;
1932     }
1933     push @m, $obj;
1934     }
1935     }
1936     return wantarray ? @m : $m[0];
1937     }
1938    
1939     #-> sub CPAN::Shell::format_result ;
1940     sub format_result {
1941     my($self) = shift;
1942     my($type,@args) = @_;
1943     @args = '/./' unless @args;
1944     my(@result) = $self->expand($type,@args);
1945     my $result = @result == 1 ?
1946     $result[0]->as_string :
1947     @result == 0 ?
1948     "No objects of type $type found for argument @args\n" :
1949     join("",
1950     (map {$_->as_glimpse} @result),
1951     scalar @result, " items found\n",
1952     );
1953     $result;
1954     }
1955    
1956     # The only reason for this method is currently to have a reliable
1957     # debugging utility that reveals which output is going through which
1958     # channel. No, I don't like the colors ;-)
1959    
1960     #-> sub CPAN::Shell::print_ornameted ;
1961     sub print_ornamented {
1962     my($self,$what,$ornament) = @_;
1963     my $longest = 0;
1964     return unless defined $what;
1965    
1966     if ($CPAN::Config->{term_is_latin}){
1967     # courtesy jhi:
1968     $what
1969     =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
1970     }
1971     if ($PRINT_ORNAMENTING) {
1972     unless (defined &color) {
1973     if ($CPAN::META->has_inst("Term::ANSIColor")) {
1974     import Term::ANSIColor "color";
1975     } else {
1976     *color = sub { return "" };
1977     }
1978     }
1979     my $line;
1980     for $line (split /\n/, $what) {
1981     $longest = length($line) if length($line) > $longest;
1982     }
1983     my $sprintf = "%-" . $longest . "s";
1984     while ($what){
1985     $what =~ s/(.*\n?)//m;
1986     my $line = $1;
1987     last unless $line;
1988     my($nl) = chomp $line ? "\n" : "";
1989     # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
1990     print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
1991     }
1992     } else {
1993     # chomp $what;
1994     # $what .= "\n"; # newlines unless $PRINT_ORNAMENTING
1995     print $what;
1996     }
1997     }
1998    
1999     sub myprint {
2000     my($self,$what) = @_;
2001    
2002     $self->print_ornamented($what, 'bold blue on_yellow');
2003     }
2004    
2005     sub myexit {
2006     my($self,$what) = @_;
2007     $self->myprint($what);
2008     exit;
2009     }
2010    
2011     sub mywarn {
2012     my($self,$what) = @_;
2013     $self->print_ornamented($what, 'bold red on_yellow');
2014     }
2015    
2016     sub myconfess {
2017     my($self,$what) = @_;
2018     $self->print_ornamented($what, 'bold red on_white');
2019     Carp::confess "died";
2020     }
2021    
2022     sub mydie {
2023     my($self,$what) = @_;
2024     $self->print_ornamented($what, 'bold red on_white');
2025     die "\n";
2026     }
2027    
2028     sub setup_output {
2029     return if -t STDOUT;
2030     my $odef = select STDERR;
2031     $| = 1;
2032     select STDOUT;
2033     $| = 1;
2034     select $odef;
2035     }
2036    
2037     #-> sub CPAN::Shell::rematein ;
2038     # RE-adme||MA-ke||TE-st||IN-stall
2039     sub rematein {
2040     shift;
2041     my($meth,@some) = @_;
2042     my $pragma = "";
2043     if ($meth eq 'force') {
2044     $pragma = $meth;
2045     $meth = shift @some;
2046     }
2047     setup_output();
2048     CPAN->debug("pragma[$pragma]meth[$meth] some[@some]") if $CPAN::DEBUG;
2049    
2050     # Here is the place to set "test_count" on all involved parties to
2051     # 0. We then can pass this counter on to the involved
2052     # distributions and those can refuse to test if test_count > X. In
2053     # the first stab at it we could use a 1 for "X".
2054    
2055     # But when do I reset the distributions to start with 0 again?
2056     # Jost suggested to have a random or cycling interaction ID that
2057     # we pass through. But the ID is something that is just left lying
2058     # around in addition to the counter, so I'd prefer to set the
2059     # counter to 0 now, and repeat at the end of the loop. But what
2060     # about dependencies? They appear later and are not reset, they
2061     # enter the queue but not its copy. How do they get a sensible
2062     # test_count?
2063    
2064     # construct the queue
2065     my($s,@s,@qcopy);
2066     foreach $s (@some) {
2067     my $obj;
2068     if (ref $s) {
2069     CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
2070     $obj = $s;
2071     } elsif ($s =~ m|^/|) { # looks like a regexp
2072     $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
2073     "not supported\n");
2074     sleep 2;
2075     next;
2076     } else {
2077     CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
2078     $obj = CPAN::Shell->expandany($s);
2079     }
2080     if (ref $obj) {
2081     $obj->color_cmd_tmps(0,1);
2082     CPAN::Queue->new($obj->id);
2083     push @qcopy, $obj;
2084     } elsif ($CPAN::META->exists('CPAN::Author',$s)) {
2085     $obj = $CPAN::META->instance('CPAN::Author',$s);
2086     if ($meth =~ /^(dump|ls)$/) {
2087     $obj->$meth();
2088     } else {
2089     $CPAN::Frontend->myprint(
2090     join "",
2091     "Don't be silly, you can't $meth ",
2092     $obj->fullname,
2093     " ;-)\n"
2094     );
2095     sleep 2;
2096     }
2097     } else {
2098     $CPAN::Frontend
2099     ->myprint(qq{Warning: Cannot $meth $s, }.
2100     qq{don\'t know what it is.
2101     Try the command
2102    
2103     i /$s/
2104    
2105     to find objects with matching identifiers.
2106     });
2107     sleep 2;
2108     }
2109     }
2110    
2111     # queuerunner (please be warned: when I started to change the
2112     # queue to hold objects instead of names, I made one or two
2113     # mistakes and never found which. I reverted back instead)
2114     while ($s = CPAN::Queue->first) {
2115     my $obj;
2116     if (ref $s) {
2117     $obj = $s; # I do not believe, we would survive if this happened
2118     } else {
2119     $obj = CPAN::Shell->expandany($s);
2120     }
2121     if ($pragma
2122     &&
2123     ($] < 5.00303 || $obj->can($pragma))){
2124     ### compatibility with 5.003
2125     $obj->$pragma($meth); # the pragma "force" in
2126     # "CPAN::Distribution" must know
2127     # what we are intending
2128     }
2129     if ($]>=5.00303 && $obj->can('called_for')) {
2130     $obj->called_for($s);
2131     }
2132     CPAN->debug(
2133     qq{pragma[$pragma]meth[$meth]obj[$obj]as_string\[}.
2134     $obj->as_string.
2135     qq{\]}
2136     ) if $CPAN::DEBUG;
2137    
2138     if ($obj->$meth()){
2139     CPAN::Queue->delete($s);
2140     } else {
2141     CPAN->debug("failed");
2142     }
2143    
2144     $obj->undelay;
2145     CPAN::Queue->delete_first($s);
2146     }
2147     for my $obj (@qcopy) {
2148     $obj->color_cmd_tmps(0,0);
2149     }
2150     }
2151    
2152     #-> sub CPAN::Shell::dump ;
2153     sub dump { shift->rematein('dump',@_); }
2154     #-> sub CPAN::Shell::force ;
2155     sub force { shift->rematein('force',@_); }
2156     #-> sub CPAN::Shell::get ;
2157     sub get { shift->rematein('get',@_); }
2158     #-> sub CPAN::Shell::readme ;
2159     sub readme { shift->rematein('readme',@_); }
2160     #-> sub CPAN::Shell::make ;
2161     sub make { shift->rematein('make',@_); }
2162     #-> sub CPAN::Shell::test ;
2163     sub test { shift->rematein('test',@_); }
2164     #-> sub CPAN::Shell::install ;
2165     sub install { shift->rematein('install',@_); }
2166     #-> sub CPAN::Shell::clean ;
2167     sub clean { shift->rematein('clean',@_); }
2168     #-> sub CPAN::Shell::look ;
2169     sub look { shift->rematein('look',@_); }
2170     #-> sub CPAN::Shell::cvs_import ;
2171     sub cvs_import { shift->rematein('cvs_import',@_); }
2172    
2173     package CPAN::LWP::UserAgent;
2174    
2175     sub config {
2176     return if $SETUPDONE;
2177     if ($CPAN::META->has_usable('LWP::UserAgent')) {
2178     require LWP::UserAgent;
2179     @ISA = qw(Exporter LWP::UserAgent);
2180     $SETUPDONE++;
2181     } else {
2182     $CPAN::Frontend->mywarn("LWP::UserAgent not available\n");
2183     }
2184     }
2185    
2186     sub get_basic_credentials {
2187     my($self, $realm, $uri, $proxy) = @_;
2188     return unless $proxy;
2189     if ($USER && $PASSWD) {
2190     } elsif (defined $CPAN::Config->{proxy_user} &&
2191     defined $CPAN::Config->{proxy_pass}) {
2192     $USER = $CPAN::Config->{proxy_user};
2193     $PASSWD = $CPAN::Config->{proxy_pass};
2194     } else {
2195     require ExtUtils::MakeMaker;
2196     ExtUtils::MakeMaker->import(qw(prompt));
2197     $USER = prompt("Proxy authentication needed!
2198     (Note: to permanently configure username and password run
2199     o conf proxy_user your_username
2200     o conf proxy_pass your_password
2201     )\nUsername:");
2202     if ($CPAN::META->has_inst("Term::ReadKey")) {
2203     Term::ReadKey::ReadMode("noecho");
2204     } else {
2205     $CPAN::Frontend->mywarn("Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n");
2206     }
2207     $PASSWD = prompt("Password:");
2208     if ($CPAN::META->has_inst("Term::ReadKey")) {
2209     Term::ReadKey::ReadMode("restore");
2210     }
2211     $CPAN::Frontend->myprint("\n\n");
2212     }
2213     return($USER,$PASSWD);
2214     }
2215    
2216     # mirror(): Its purpose is to deal with proxy authentication. When we
2217     # call SUPER::mirror, we relly call the mirror method in
2218     # LWP::UserAgent. LWP::UserAgent will then call
2219     # $self->get_basic_credentials or some equivalent and this will be
2220     # $self->dispatched to our own get_basic_credentials method.
2221    
2222     # Our own get_basic_credentials sets $USER and $PASSWD, two globals.
2223    
2224     # 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
2225     # although we have gone through our get_basic_credentials, the proxy
2226     # server refuses to connect. This could be a case where the username or
2227     # password has changed in the meantime, so I'm trying once again without
2228     # $USER and $PASSWD to give the get_basic_credentials routine another
2229     # chance to set $USER and $PASSWD.
2230    
2231     sub mirror {
2232     my($self,$url,$aslocal) = @_;
2233     my $result = $self->SUPER::mirror($url,$aslocal);
2234     if ($result->code == 407) {
2235     undef $USER;
2236     undef $PASSWD;
2237     $result = $self->SUPER::mirror($url,$aslocal);
2238     }
2239     $result;
2240     }
2241    
2242     package CPAN::FTP;
2243    
2244     #-> sub CPAN::FTP::ftp_get ;
2245     sub ftp_get {
2246     my($class,$host,$dir,$file,$target) = @_;
2247     $class->debug(
2248     qq[Going to fetch file [$file] from dir [$dir]
2249     on host [$host] as local [$target]\n]
2250     ) if $CPAN::DEBUG;
2251     my $ftp = Net::FTP->new($host);
2252     return 0 unless defined $ftp;
2253     $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
2254     $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
2255     unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
2256     warn "Couldn't login on $host";
2257     return;
2258     }
2259     unless ( $ftp->cwd($dir) ){
2260     warn "Couldn't cwd $dir";
2261     return;
2262     }
2263     $ftp->binary;
2264     $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
2265     unless ( $ftp->get($file,$target) ){
2266     warn "Couldn't fetch $file from $host\n";
2267     return;
2268     }
2269     $ftp->quit; # it's ok if this fails
2270     return 1;
2271     }
2272    
2273     # If more accuracy is wanted/needed, Chris Leach sent me this patch...
2274    
2275     # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
2276     # > --- /tmp/cp Wed Sep 24 13:26:40 1997
2277     # > ***************
2278     # > *** 1562,1567 ****
2279     # > --- 1562,1580 ----
2280     # > return 1 if substr($url,0,4) eq "file";
2281     # > return 1 unless $url =~ m|://([^/]+)|;
2282     # > my $host = $1;
2283     # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
2284     # > + if ($proxy) {
2285     # > + $proxy =~ m|://([^/:]+)|;
2286     # > + $proxy = $1;
2287     # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
2288     # > + if ($noproxy) {
2289     # > + if ($host !~ /$noproxy$/) {
2290     # > + $host = $proxy;
2291     # > + }
2292     # > + } else {
2293     # > + $host = $proxy;
2294     # > + }
2295     # > + }
2296     # > require Net::Ping;
2297     # > return 1 unless $Net::Ping::VERSION >= 2;
2298     # > my $p;
2299    
2300    
2301     #-> sub CPAN::FTP::localize ;
2302     sub localize {
2303     my($self,$file,$aslocal,$force) = @_;
2304     $force ||= 0;
2305     Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
2306     unless defined $aslocal;
2307     $self->debug("file[$file] aslocal[$aslocal] force[$force]")
2308     if $CPAN::DEBUG;
2309    
2310     if ($^O eq 'MacOS') {
2311     # Comment by AK on 2000-09-03: Uniq short filenames would be
2312     # available in CHECKSUMS file
2313     my($name, $path) = File::Basename::fileparse($aslocal, '');
2314     if (length($name) > 31) {
2315     $name =~ s/(
2316     \.(
2317     readme(\.(gz|Z))? |
2318     (tar\.)?(gz|Z) |
2319     tgz |
2320     zip |
2321     pm\.(gz|Z)
2322     )
2323     )$//x;
2324     my $suf = $1;
2325     my $size = 31 - length($suf);
2326     while (length($name) > $size) {
2327     chop $name;
2328     }
2329     $name .= $suf;
2330     $aslocal = File::Spec->catfile($path, $name);
2331     }
2332     }
2333    
2334     return $aslocal if -f $aslocal && -r _ && !($force & 1);
2335     my($restore) = 0;
2336     if (-f $aslocal){
2337     rename $aslocal, "$aslocal.bak";
2338     $restore++;
2339     }
2340    
2341     my($aslocal_dir) = File::Basename::dirname($aslocal);
2342     File::Path::mkpath($aslocal_dir);
2343     $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
2344     qq{directory "$aslocal_dir".
2345     I\'ll continue, but if you encounter problems, they may be due
2346     to insufficient permissions.\n}) unless -w $aslocal_dir;
2347    
2348     # Inheritance is not easier to manage than a few if/else branches
2349     if ($CPAN::META->has_usable('LWP::UserAgent')) {
2350     unless ($Ua) {
2351     CPAN::LWP::UserAgent->config;
2352     eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
2353     if ($@) {
2354     $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
2355     if $CPAN::DEBUG;
2356     } else {
2357     my($var);
2358     $Ua->proxy('ftp', $var)
2359     if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
2360     $Ua->proxy('http', $var)
2361     if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
2362    
2363    
2364     # >>>>> On Wed, 13 Dec 2000 09:21:34 -0500, "Robison, Jonathon (J.M.)" <jrobiso2@visteon.com> said:
2365     #
2366     # > I note that although CPAN.pm can use proxies, it doesn't seem equipped to
2367     # > use ones that require basic autorization.
2368     #
2369     # > Example of when I use it manually in my own stuff:
2370     #
2371     # > $ua->proxy(['http','ftp'], http://my.proxy.server:83');
2372     # > $req->proxy_authorization_basic("username","password");
2373     # > $res = $ua->request($req);
2374     #
2375    
2376     $Ua->no_proxy($var)
2377     if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
2378     }
2379     }
2380     }
2381     for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
2382     $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
2383     }
2384    
2385     # Try the list of urls for each single object. We keep a record
2386     # where we did get a file from
2387     my(@reordered,$last);
2388     $CPAN::Config->{urllist} ||= [];
2389     unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
2390     warn "Malformed urllist; ignoring. Configuration file corrupt?\n";
2391     }
2392     $last = $#{$CPAN::Config->{urllist}};
2393     if ($force & 2) { # local cpans probably out of date, don't reorder
2394     @reordered = (0..$last);
2395     } else {
2396     @reordered =
2397     sort {
2398     (substr($CPAN::Config->{urllist}[$b],0,4) eq "file")
2399     <=>
2400     (substr($CPAN::Config->{urllist}[$a],0,4) eq "file")
2401     or
2402     defined($Thesite)
2403     and
2404     ($b == $Thesite)
2405     <=>
2406     ($a == $Thesite)
2407     } 0..$last;
2408     }
2409     my(@levels);
2410     if ($Themethod) {
2411     @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/);
2412     } else {
2413     @levels = qw/easy hard hardest/;
2414     }
2415     @levels = qw/easy/ if $^O eq 'MacOS';
2416     my($levelno);
2417     for $levelno (0..$#levels) {
2418     my $level = $levels[$levelno];
2419     my $method = "host$level";
2420     my @host_seq = $level eq "easy" ?
2421     @reordered : 0..$last; # reordered has CDROM up front
2422     @host_seq = (0) unless @host_seq;
2423     my $ret = $self->$method(\@host_seq,$file,$aslocal);
2424     if ($ret) {
2425     $Themethod = $level;
2426     my $now = time;
2427     # utime $now, $now, $aslocal; # too bad, if we do that, we
2428     # might alter a local mirror
2429     $self->debug("level[$level]") if $CPAN::DEBUG;
2430     return $ret;
2431     } else {
2432     unlink $aslocal;
2433     last if $CPAN::Signal; # need to cleanup
2434     }
2435     }
2436     unless ($CPAN::Signal) {
2437     my(@mess);
2438     push @mess,
2439     qq{Please check, if the URLs I found in your configuration file \(}.
2440     join(", ", @{$CPAN::Config->{urllist}}).
2441     qq{\) are valid. The urllist can be edited.},
2442     qq{E.g. with 'o conf urllist push ftp://myurl/'};
2443     $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n");
2444     sleep 2;
2445     $CPAN::Frontend->myprint("Could not fetch $file\n");
2446     }
2447     if ($restore) {
2448     rename "$aslocal.bak", $aslocal;
2449     $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
2450     $self->ls($aslocal));
2451     return $aslocal;
2452     }
2453     return;
2454     }
2455    
2456     sub hosteasy {
2457     my($self,$host_seq,$file,$aslocal) = @_;
2458     my($i);
2459     HOSTEASY: for $i (@$host_seq) {
2460     my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2461     $url .= "/" unless substr($url,-1) eq "/";
2462     $url .= $file;
2463     $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
2464     if ($url =~ /^file:/) {
2465     my $l;
2466     if ($CPAN::META->has_inst('URI::URL')) {
2467     my $u = URI::URL->new($url);
2468     $l = $u->path;
2469     } else { # works only on Unix, is poorly constructed, but
2470     # hopefully better than nothing.
2471     # RFC 1738 says fileurl BNF is
2472     # fileurl = "file://" [ host | "localhost" ] "/" fpath
2473     # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
2474     # the code
2475     ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
2476     $l =~ s|^file:||; # assume they
2477     # meant
2478     # file://localhost
2479     $l =~ s|^/||s unless -f $l; # e.g. /P:
2480     $self->debug("without URI::URL we try local file $l") if $CPAN::DEBUG;
2481     }
2482     if ( -f $l && -r _) {
2483     $Thesite = $i;
2484     return $l;
2485     }
2486     # Maybe mirror has compressed it?
2487     if (-f "$l.gz") {
2488     $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
2489     CPAN::Tarzip->gunzip("$l.gz", $aslocal);
2490     if ( -f $aslocal) {
2491     $Thesite = $i;
2492     return $aslocal;
2493     }
2494     }
2495     }
2496     if ($CPAN::META->has_usable('LWP')) {
2497     $CPAN::Frontend->myprint("Fetching with LWP:
2498     $url
2499     ");
2500     unless ($Ua) {
2501     CPAN::LWP::UserAgent->config;
2502     eval { $Ua = CPAN::LWP::UserAgent->new; };
2503     if ($@) {
2504     $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
2505     }
2506     }
2507     my $res = $Ua->mirror($url, $aslocal);
2508     if ($res->is_success) {
2509     $Thesite = $i;
2510     my $now = time;
2511     utime $now, $now, $aslocal; # download time is more
2512     # important than upload time
2513     return $aslocal;
2514     } elsif ($url !~ /\.gz(?!\n)\Z/) {
2515     my $gzurl = "$url.gz";
2516     $CPAN::Frontend->myprint("Fetching with LWP:
2517     $gzurl
2518     ");
2519     $res = $Ua->mirror($gzurl, "$aslocal.gz");
2520     if ($res->is_success &&
2521     CPAN::Tarzip->gunzip("$aslocal.gz",$aslocal)
2522     ) {
2523     $Thesite = $i;
2524     return $aslocal;
2525     }
2526     } else {
2527     $CPAN::Frontend->myprint(sprintf(
2528     "LWP failed with code[%s] message[%s]\n",
2529     $res->code,
2530     $res->message,
2531     ));
2532     # Alan Burlison informed me that in firewall environments
2533     # Net::FTP can still succeed where LWP fails. So we do not
2534     # skip Net::FTP anymore when LWP is available.
2535     }
2536     } else {
2537     $CPAN::Frontend->myprint("LWP not available\n");
2538     }
2539     return if $CPAN::Signal;
2540     if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2541     # that's the nice and easy way thanks to Graham
2542     my($host,$dir,$getfile) = ($1,$2,$3);
2543     if ($CPAN::META->has_usable('Net::FTP')) {
2544     $dir =~ s|/+|/|g;
2545     $CPAN::Frontend->myprint("Fetching with Net::FTP:
2546     $url
2547     ");
2548     $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
2549     "aslocal[$aslocal]") if $CPAN::DEBUG;
2550     if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
2551     $Thesite = $i;
2552     return $aslocal;
2553     }
2554     if ($aslocal !~ /\.gz(?!\n)\Z/) {
2555     my $gz = "$aslocal.gz";
2556     $CPAN::Frontend->myprint("Fetching with Net::FTP
2557     $url.gz
2558     ");
2559     if (CPAN::FTP->ftp_get($host,
2560     $dir,
2561     "$getfile.gz",
2562     $gz) &&
2563     CPAN::Tarzip->gunzip($gz,$aslocal)
2564     ){
2565     $Thesite = $i;
2566     return $aslocal;
2567     }
2568     }
2569     # next HOSTEASY;
2570     }
2571     }
2572     return if $CPAN::Signal;
2573     }
2574     }
2575    
2576     sub hosthard {
2577     my($self,$host_seq,$file,$aslocal) = @_;
2578    
2579     # Came back if Net::FTP couldn't establish connection (or
2580     # failed otherwise) Maybe they are behind a firewall, but they
2581     # gave us a socksified (or other) ftp program...
2582    
2583     my($i);
2584     my($devnull) = $CPAN::Config->{devnull} || "";
2585     # < /dev/null ";
2586     my($aslocal_dir) = File::Basename::dirname($aslocal);
2587     File::Path::mkpath($aslocal_dir);
2588     HOSTHARD: for $i (@$host_seq) {
2589     my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2590     $url .= "/" unless substr($url,-1) eq "/";
2591     $url .= $file;
2592     my($proto,$host,$dir,$getfile);
2593    
2594     # Courtesy Mark Conty mark_conty@cargill.com change from
2595     # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2596     # to
2597     if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
2598     # proto not yet used
2599     ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
2600     } else {
2601     next HOSTHARD; # who said, we could ftp anything except ftp?
2602     }
2603     next HOSTHARD if $proto eq "file"; # file URLs would have had
2604     # success above. Likely a bogus URL
2605    
2606     $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
2607     my($f,$funkyftp);
2608     for $f ('lynx','ncftpget','ncftp','wget') {
2609     next unless exists $CPAN::Config->{$f};
2610     $funkyftp = $CPAN::Config->{$f};
2611     next unless defined $funkyftp;
2612     next if $funkyftp =~ /^\s*$/;
2613     my($asl_ungz, $asl_gz);
2614     ($asl_ungz = $aslocal) =~ s/\.gz//;
2615     $asl_gz = "$asl_ungz.gz";
2616     my($src_switch) = "";
2617     if ($f eq "lynx"){
2618     $src_switch = " -source";
2619     } elsif ($f eq "ncftp"){
2620     $src_switch = " -c";
2621     } elsif ($f eq "wget"){
2622     $src_switch = " -O -";
2623     }
2624     my($chdir) = "";
2625     my($stdout_redir) = " > $asl_ungz";
2626     if ($f eq "ncftpget"){
2627     $chdir = "cd $aslocal_dir && ";
2628     $stdout_redir = "";
2629     }
2630     $CPAN::Frontend->myprint(
2631     qq[
2632     Trying with "$funkyftp$src_switch" to get
2633     $url
2634     ]);
2635     my($system) =
2636     "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
2637     $self->debug("system[$system]") if $CPAN::DEBUG;
2638     my($wstatus);
2639     if (($wstatus = system($system)) == 0
2640     &&
2641     ($f eq "lynx" ?
2642     -s $asl_ungz # lynx returns 0 when it fails somewhere
2643     : 1
2644     )
2645     ) {
2646     if (-s $aslocal) {
2647     # Looks good
2648     } elsif ($asl_ungz ne $aslocal) {
2649     # test gzip integrity
2650     if (CPAN::Tarzip->gtest($asl_ungz)) {
2651     # e.g. foo.tar is gzipped --> foo.tar.gz
2652     rename $asl_ungz, $aslocal;
2653     } else {
2654     CPAN::Tarzip->gzip($asl_ungz,$asl_gz);
2655     }
2656     }
2657     $Thesite = $i;
2658     return $aslocal;
2659     } elsif ($url !~ /\.gz(?!\n)\Z/) {
2660     unlink $asl_ungz if
2661     -f $asl_ungz && -s _ == 0;
2662     my $gz = "$aslocal.gz";
2663     my $gzurl = "$url.gz";
2664     $CPAN::Frontend->myprint(
2665     qq[
2666     Trying with "$funkyftp$src_switch" to get
2667     $url.gz
2668     ]);
2669     my($system) = "$funkyftp$src_switch \"$url.gz\" $devnull > $asl_gz";
2670     $self->debug("system[$system]") if $CPAN::DEBUG;
2671     my($wstatus);
2672     if (($wstatus = system($system)) == 0
2673     &&
2674     -s $asl_gz
2675     ) {
2676     # test gzip integrity
2677     if (CPAN::Tarzip->gtest($asl_gz)) {
2678     CPAN::Tarzip->gunzip($asl_gz,$aslocal);
2679     } else {
2680     # somebody uncompressed file for us?
2681     rename $asl_ungz, $aslocal;
2682     }
2683     $Thesite = $i;
2684     return $aslocal;
2685     } else {
2686     unlink $asl_gz if -f $asl_gz;
2687     }
2688     } else {
2689     my $estatus = $wstatus >> 8;
2690     my $size = -f $aslocal ?
2691     ", left\n$aslocal with size ".-s _ :
2692     "\nWarning: expected file [$aslocal] doesn't exist";
2693     $CPAN::Frontend->myprint(qq{
2694     System call "$system"
2695     returned status $estatus (wstat $wstatus)$size
2696     });
2697     }
2698     return if $CPAN::Signal;
2699     } # lynx,ncftpget,ncftp
2700     } # host
2701     }
2702    
2703     sub hosthardest {
2704     my($self,$host_seq,$file,$aslocal) = @_;
2705    
2706     my($i);
2707     my($aslocal_dir) = File::Basename::dirname($aslocal);
2708     File::Path::mkpath($aslocal_dir);
2709     my $ftpbin = $CPAN::Config->{ftp};
2710     HOSTHARDEST: for $i (@$host_seq) {
2711     unless (length $ftpbin && MM->maybe_command($ftpbin)) {
2712     $CPAN::Frontend->myprint("No external ftp command available\n\n");
2713     last HOSTHARDEST;
2714     }
2715     my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
2716     $url .= "/" unless substr($url,-1) eq "/";
2717     $url .= $file;
2718     $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
2719     unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2720     next;
2721     }
2722     my($host,$dir,$getfile) = ($1,$2,$3);
2723     my $timestamp = 0;
2724     my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
2725     $ctime,$blksize,$blocks) = stat($aslocal);
2726     $timestamp = $mtime ||= 0;
2727     my($netrc) = CPAN::FTP::netrc->new;
2728     my($netrcfile) = $netrc->netrc;
2729     my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
2730     my $targetfile = File::Basename::basename($aslocal);
2731     my(@dialog);
2732     push(
2733     @dialog,
2734     "lcd $aslocal_dir",
2735     "cd /",
2736     map("cd $_", split /\//, $dir), # RFC 1738
2737     "bin",
2738     "get $getfile $targetfile",
2739     "quit"
2740     );
2741     if (! $netrcfile) {
2742     CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
2743     } elsif ($netrc->hasdefault || $netrc->contains($host)) {
2744     CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
2745     $netrc->hasdefault,
2746     $netrc->contains($host))) if $CPAN::DEBUG;
2747     if ($netrc->protected) {
2748     $CPAN::Frontend->myprint(qq{
2749     Trying with external ftp to get
2750     $url
2751     As this requires some features that are not thoroughly tested, we\'re
2752     not sure, that we get it right....
2753    
2754     }
2755     );
2756     $self->talk_ftp("$ftpbin$verbose $host",
2757     @dialog);
2758     ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2759     $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2760     $mtime ||= 0;
2761     if ($mtime > $timestamp) {
2762     $CPAN::Frontend->myprint("GOT $aslocal\n");
2763     $Thesite = $i;
2764     return $aslocal;
2765     } else {
2766     $CPAN::Frontend->myprint("Hmm... Still failed!\n");
2767     }
2768     return if $CPAN::Signal;
2769     } else {
2770     $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
2771     qq{correctly protected.\n});
2772     }
2773     } else {
2774     $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
2775     nor does it have a default entry\n");
2776     }
2777    
2778     # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
2779     # then and login manually to host, using e-mail as
2780     # password.
2781     $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n});
2782     unshift(
2783     @dialog,
2784     "open $host",
2785     "user anonymous $Config::Config{'cf_email'}"
2786     );
2787     $self->talk_ftp("$ftpbin$verbose -n", @dialog);
2788     ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2789     $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2790     $mtime ||= 0;
2791     if ($mtime > $timestamp) {
2792     $CPAN::Frontend->myprint("GOT $aslocal\n");
2793     $Thesite = $i;
2794     return $aslocal;
2795     } else {
2796     $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
2797     }
2798     return if $CPAN::Signal;
2799     $CPAN::Frontend->myprint("Can't access URL $url.\n\n");
2800     sleep 2;
2801     } # host
2802     }
2803    
2804     sub talk_ftp {
2805     my($self,$command,@dialog) = @_;
2806     my $fh = FileHandle->new;
2807     $fh->open("|$command") or die "Couldn't open ftp: $!";
2808     foreach (@dialog) { $fh->print("$_\n") }
2809     $fh->close; # Wait for process to complete
2810     my $wstatus = $?;
2811     my $estatus = $wstatus >> 8;
2812     $CPAN::Frontend->myprint(qq{
2813     Subprocess "|$command"
2814     returned status $estatus (wstat $wstatus)
2815     }) if $wstatus;
2816     }
2817    
2818     # find2perl needs modularization, too, all the following is stolen
2819     # from there
2820     # CPAN::FTP::ls
2821     sub ls {
2822     my($self,$name) = @_;
2823     my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
2824     $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
2825    
2826     my($perms,%user,%group);
2827     my $pname = $name;
2828    
2829     if ($blocks) {
2830     $blocks = int(($blocks + 1) / 2);
2831     }
2832     else {
2833     $blocks = int(($sizemm + 1023) / 1024);
2834     }
2835    
2836     if (-f _) { $perms = '-'; }
2837     elsif (-d _) { $perms = 'd'; }
2838     elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
2839     elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
2840     elsif (-p _) { $perms = 'p'; }
2841     elsif (-S _) { $perms = 's'; }
2842     else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
2843    
2844     my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
2845     my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
2846     my $tmpmode = $mode;
2847     my $tmp = $rwx[$tmpmode & 7];
2848     $tmpmode >>= 3;
2849     $tmp = $rwx[$tmpmode & 7] . $tmp;
2850     $tmpmode >>= 3;
2851     $tmp = $rwx[$tmpmode & 7] . $tmp;
2852     substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
2853     substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
2854     substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
2855     $perms .= $tmp;
2856    
2857     my $user = $user{$uid} || $uid; # too lazy to implement lookup
2858     my $group = $group{$gid} || $gid;
2859    
2860     my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
2861     my($timeyear);
2862     my($moname) = $moname[$mon];
2863     if (-M _ > 365.25 / 2) {
2864     $timeyear = $year + 1900;
2865     }
2866     else {
2867     $timeyear = sprintf("%02d:%02d", $hour, $min);
2868     }
2869    
2870     sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
2871     $ino,
2872     $blocks,
2873     $perms,
2874     $nlink,
2875     $user,
2876     $group,
2877     $sizemm,
2878     $moname,
2879     $mday,
2880     $timeyear,
2881     $pname;
2882     }
2883    
2884     package CPAN::FTP::netrc;
2885    
2886     sub new {
2887     my($class) = @_;
2888     my $file = File::Spec->catfile($ENV{HOME},".netrc");
2889    
2890     my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2891     $atime,$mtime,$ctime,$blksize,$blocks)
2892     = stat($file);
2893     $mode ||= 0;
2894     my $protected = 0;
2895    
2896     my($fh,@machines,$hasdefault);
2897     $hasdefault = 0;
2898     $fh = FileHandle->new or die "Could not create a filehandle";
2899    
2900     if($fh->open($file)){
2901     $protected = ($mode & 077) == 0;
2902     local($/) = "";
2903     NETRC: while (<$fh>) {
2904     my(@tokens) = split " ", $_;
2905     TOKEN: while (@tokens) {
2906     my($t) = shift @tokens;
2907     if ($t eq "default"){
2908     $hasdefault++;
2909     last NETRC;
2910     }
2911     last TOKEN if $t eq "macdef";
2912     if ($t eq "machine") {
2913     push @machines, shift @tokens;
2914     }
2915     }
2916     }
2917     } else {
2918     $file = $hasdefault = $protected = "";
2919     }
2920    
2921     bless {
2922     'mach' => [@machines],
2923     'netrc' => $file,
2924     'hasdefault' => $hasdefault,
2925     'protected' => $protected,
2926     }, $class;
2927     }
2928    
2929     # CPAN::FTP::hasdefault;
2930     sub hasdefault { shift->{'hasdefault'} }
2931     sub netrc { shift->{'netrc'} }
2932     sub protected { shift->{'protected'} }
2933     sub contains {
2934     my($self,$mach) = @_;
2935     for ( @{$self->{'mach'}} ) {
2936     return 1 if $_ eq $mach;
2937     }
2938     return 0;
2939     }
2940    
2941     package CPAN::Complete;
2942    
2943     sub gnu_cpl {
2944     my($text, $line, $start, $end) = @_;
2945     my(@perlret) = cpl($text, $line, $start);
2946     # find longest common match. Can anybody show me how to peruse
2947     # T::R::Gnu to have this done automatically? Seems expensive.
2948     return () unless @perlret;
2949     my($newtext) = $text;
2950     for (my $i = length($text)+1;;$i++) {
2951     last unless length($perlret[0]) && length($perlret[0]) >= $i;
2952     my $try = substr($perlret[0],0,$i);
2953     my @tries = grep {substr($_,0,$i) eq $try} @perlret;
2954     # warn "try[$try]tries[@tries]";
2955     if (@tries == @perlret) {
2956     $newtext = $try;
2957     } else {
2958     last;
2959     }
2960     }
2961     ($newtext,@perlret);
2962     }
2963    
2964     #-> sub CPAN::Complete::cpl ;
2965     sub cpl {
2966     my($word,$line,$pos) = @_;
2967     $word ||= "";
2968     $line ||= "";
2969     $pos ||= 0;
2970     CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2971     $line =~ s/^\s*//;
2972     if ($line =~ s/^(force\s*)//) {
2973     $pos -= length($1);
2974     }
2975     my @return;
2976     if ($pos == 0) {
2977     @return = grep /^$word/, @CPAN::Complete::COMMANDS;
2978     } elsif ( $line !~ /^[\!abcdghimorutl]/ ) {
2979     @return = ();
2980     } elsif ($line =~ /^(a|ls)\s/) {
2981     @return = cplx('CPAN::Author',uc($word));
2982     } elsif ($line =~ /^b\s/) {
2983     CPAN::Shell->local_bundles;
2984     @return = cplx('CPAN::Bundle',$word);
2985     } elsif ($line =~ /^d\s/) {
2986     @return = cplx('CPAN::Distribution',$word);
2987     } elsif ($line =~ m/^(
2988     [mru]|make|clean|dump|get|test|install|readme|look|cvs_import
2989     )\s/x ) {
2990     if ($word =~ /^Bundle::/) {
2991     CPAN::Shell->local_bundles;
2992     }
2993     @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
2994     } elsif ($line =~ /^i\s/) {
2995     @return = cpl_any($word);
2996     } elsif ($line =~ /^reload\s/) {
2997     @return = cpl_reload($word,$line,$pos);
2998     } elsif ($line =~ /^o\s/) {
2999     @return = cpl_option($word,$line,$pos);
3000     } elsif ($line =~ m/^\S+\s/ ) {
3001     # fallback for future commands and what we have forgotten above
3002     @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
3003     } else {
3004     @return = ();
3005     }
3006     return @return;
3007     }
3008    
3009     #-> sub CPAN::Complete::cplx ;
3010     sub cplx {
3011     my($class, $word) = @_;
3012     # I believed for many years that this was sorted, today I
3013     # realized, it wasn't sorted anymore. Now (rev 1.301 / v 1.55) I
3014     # make it sorted again. Maybe sort was dropped when GNU-readline
3015     # support came in? The RCS file is difficult to read on that:-(
3016     sort grep /^\Q$word\E/, map { $_->id } $CPAN::META->all_objects($class);
3017     }
3018    
3019     #-> sub CPAN::Complete::cpl_any ;
3020     sub cpl_any {
3021     my($word) = shift;
3022     return (
3023     cplx('CPAN::Author',$word),
3024     cplx('CPAN::Bundle',$word),
3025     cplx('CPAN::Distribution',$word),
3026     cplx('CPAN::Module',$word),
3027     );
3028     }
3029    
3030     #-> sub CPAN::Complete::cpl_reload ;
3031     sub cpl_reload {
3032     my($word,$line,$pos) = @_;
3033     $word ||= "";
3034     my(@words) = split " ", $line;
3035     CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3036     my(@ok) = qw(cpan index);
3037     return @ok if @words == 1;
3038     return grep /^\Q$word\E/, @ok if @words == 2 && $word;
3039     }
3040    
3041     #-> sub CPAN::Complete::cpl_option ;
3042     sub cpl_option {
3043     my($word,$line,$pos) = @_;
3044     $word ||= "";
3045     my(@words) = split " ", $line;
3046     CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
3047     my(@ok) = qw(conf debug);
3048     return @ok if @words == 1;
3049     return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
3050     if (0) {
3051     } elsif ($words[1] eq 'index') {
3052     return ();
3053     } elsif ($words[1] eq 'conf') {
3054     return CPAN::Config::cpl(@_);
3055     } elsif ($words[1] eq 'debug') {
3056     return sort grep /^\Q$word\E/, sort keys %CPAN::DEBUG, 'all';
3057     }
3058     }
3059    
3060     package CPAN::Index;
3061    
3062     #-> sub CPAN::Index::force_reload ;
3063     sub force_reload {
3064     my($class) = @_;
3065     $CPAN::Index::LAST_TIME = 0;
3066     $class->reload(1);
3067     }
3068    
3069     #-> sub CPAN::Index::reload ;
3070     sub reload {
3071     my($cl,$force) = @_;
3072     my $time = time;
3073    
3074     # XXX check if a newer one is available. (We currently read it
3075     # from time to time)
3076     for ($CPAN::Config->{index_expire}) {
3077     $_ = 0.001 unless $_ && $_ > 0.001;
3078     }
3079     unless (1 || $CPAN::Have_warned->{readmetadatacache}++) {
3080     # debug here when CPAN doesn't seem to read the Metadata
3081     require Carp;
3082     Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]");
3083     }
3084     unless ($CPAN::META->{PROTOCOL}) {
3085     $cl->read_metadata_cache;
3086     $CPAN::META->{PROTOCOL} ||= "1.0";
3087     }
3088     if ( $CPAN::META->{PROTOCOL} < PROTOCOL ) {
3089     # warn "Setting last_time to 0";
3090     $LAST_TIME = 0; # No warning necessary
3091     }
3092     return if $LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time
3093     and ! $force;
3094     if (0) {
3095     # IFF we are developing, it helps to wipe out the memory
3096     # between reloads, otherwise it is not what a user expects.
3097     undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274)
3098     $CPAN::META = CPAN->new;
3099     }
3100     {
3101     my($debug,$t2);
3102     local $LAST_TIME = $time;
3103     local $CPAN::META->{PROTOCOL} = PROTOCOL;
3104    
3105     my $needshort = $^O eq "dos";
3106    
3107     $cl->rd_authindex($cl
3108     ->reload_x(
3109     "authors/01mailrc.txt.gz",
3110     $needshort ?
3111     File::Spec->catfile('authors', '01mailrc.gz') :
3112     File::Spec->catfile('authors', '01mailrc.txt.gz'),
3113     $force));
3114     $t2 = time;
3115     $debug = "timing reading 01[".($t2 - $time)."]";
3116     $time = $t2;
3117     return if $CPAN::Signal; # this is sometimes lengthy
3118     $cl->rd_modpacks($cl
3119     ->reload_x(
3120     "modules/02packages.details.txt.gz",
3121     $needshort ?
3122     File::Spec->catfile('modules', '02packag.gz') :
3123     File::Spec->catfile('modules', '02packages.details.txt.gz'),
3124     $force));
3125     $t2 = time;
3126     $debug .= "02[".($t2 - $time)."]";
3127     $time = $t2;
3128     return if $CPAN::Signal; # this is sometimes lengthy
3129     $cl->rd_modlist($cl
3130     ->reload_x(
3131     "modules/03modlist.data.gz",
3132     $needshort ?
3133     File::Spec->catfile('modules', '03mlist.gz') :
3134     File::Spec->catfile('modules', '03modlist.data.gz'),
3135     $force));
3136     $cl->write_metadata_cache;
3137     $t2 = time;
3138     $debug .= "03[".($t2 - $time)."]";
3139     $time = $t2;
3140     CPAN->debug($debug) if $CPAN::DEBUG;
3141     }
3142     $LAST_TIME = $time;
3143     $CPAN::META->{PROTOCOL} = PROTOCOL;
3144     }
3145    
3146     #-> sub CPAN::Index::reload_x ;
3147     sub reload_x {
3148     my($cl,$wanted,$localname,$force) = @_;
3149     $force |= 2; # means we're dealing with an index here
3150     CPAN::Config->load; # we should guarantee loading wherever we rely
3151     # on Config XXX
3152     $localname ||= $wanted;
3153     my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'},
3154     $localname);
3155     if (
3156     -f $abs_wanted &&
3157     -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
3158     !($force & 1)
3159     ) {
3160     my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
3161     $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
3162     qq{day$s. I\'ll use that.});
3163     return $abs_wanted;
3164     } else {
3165     $force |= 1; # means we're quite serious about it.
3166     }
3167     return CPAN::FTP->localize($wanted,$abs_wanted,$force);
3168     }
3169    
3170     #-> sub CPAN::Index::rd_authindex ;
3171     sub rd_authindex {
3172     my($cl, $index_target) = @_;
3173     my @lines;
3174     return unless defined $index_target;
3175     $CPAN::Frontend->myprint("Going to read $index_target\n");
3176     local(*FH);
3177     tie *FH, CPAN::Tarzip, $index_target;
3178     local($/) = "\n";
3179     push @lines, split /\012/ while <FH>;
3180     foreach (@lines) {
3181     my($userid,$fullname,$email) =
3182     m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
3183     next unless $userid && $fullname && $email;
3184    
3185     # instantiate an author object
3186     my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
3187     $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
3188     return if $CPAN::Signal;
3189     }
3190     }
3191    
3192     sub userid {
3193     my($self,$dist) = @_;
3194     $dist = $self->{'id'} unless defined $dist;
3195     my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
3196     $ret;
3197     }
3198    
3199     #-> sub CPAN::Index::rd_modpacks ;
3200     sub rd_modpacks {
3201     my($self, $index_target) = @_;
3202     my @lines;
3203     return unless defined $index_target;
3204     $CPAN::Frontend->myprint("Going to read $index_target\n");
3205     my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3206     local($/) = "\n";
3207     while ($_ = $fh->READLINE) {
3208     s/\012/\n/g;
3209     my @ls = map {"$_\n"} split /\n/, $_;
3210     unshift @ls, "\n" x length($1) if /^(\n+)/;
3211     push @lines, @ls;
3212     }
3213     # read header
3214     my($line_count,$last_updated);
3215     while (@lines) {
3216     my $shift = shift(@lines);
3217     last if $shift =~ /^\s*$/;
3218     $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1;
3219     $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1;
3220     }
3221     if (not defined $line_count) {
3222    
3223     warn qq{Warning: Your $index_target does not contain a Line-Count header.
3224     Please check the validity of the index file by comparing it to more
3225     than one CPAN mirror. I'll continue but problems seem likely to
3226     happen.\a
3227     };
3228    
3229     sleep 5;
3230     } elsif ($line_count != scalar @lines) {
3231    
3232     warn sprintf qq{Warning: Your %s
3233     contains a Line-Count header of %d but I see %d lines there. Please
3234     check the validity of the index file by comparing it to more than one
3235     CPAN mirror. I'll continue but problems seem likely to happen.\a\n},
3236     $index_target, $line_count, scalar(@lines);
3237    
3238     }
3239     if (not defined $last_updated) {
3240    
3241     warn qq{Warning: Your $index_target does not contain a Last-Updated header.
3242     Please check the validity of the index file by comparing it to more
3243     than one CPAN mirror. I'll continue but problems seem likely to
3244     happen.\a
3245     };
3246    
3247     sleep 5;
3248     } else {
3249    
3250     $CPAN::Frontend
3251     ->myprint(sprintf qq{ Database was generated on %s\n},
3252     $last_updated);
3253     $DATE_OF_02 = $last_updated;
3254    
3255     if ($CPAN::META->has_inst(HTTP::Date)) {
3256     require HTTP::Date;
3257     my($age) = (time - HTTP::Date::str2time($last_updated))/3600/24;
3258     if ($age > 30) {
3259    
3260     $CPAN::Frontend
3261     ->mywarn(sprintf
3262     qq{Warning: This index file is %d days old.
3263     Please check the host you chose as your CPAN mirror for staleness.
3264     I'll continue but problems seem likely to happen.\a\n},
3265     $age);
3266    
3267     }
3268     } else {
3269     $CPAN::Frontend->myprint(" HTTP::Date not available\n");
3270     }
3271     }
3272    
3273    
3274     # A necessity since we have metadata_cache: delete what isn't
3275     # there anymore
3276     my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN");
3277     CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
3278     my(%exists);
3279     foreach (@lines) {
3280     chomp;
3281     # before 1.56 we split into 3 and discarded the rest. From
3282     # 1.57 we assign remaining text to $comment thus allowing to
3283     # influence isa_perl
3284     my($mod,$version,$dist,$comment) = split " ", $_, 4;
3285     my($bundle,$id,$userid);
3286    
3287     if ($mod eq 'CPAN' &&
3288     ! (
3289     CPAN::Queue->exists('Bundle::CPAN') ||
3290     CPAN::Queue->exists('CPAN')
3291     )
3292     ) {
3293     local($^W)= 0;
3294     if ($version > $CPAN::VERSION){
3295     $CPAN::Frontend->myprint(qq{
3296     There's a new CPAN.pm version (v$version) available!
3297     [Current version is v$CPAN::VERSION]
3298     You might want to try
3299     install Bundle::CPAN
3300     reload cpan
3301     without quitting the current session. It should be a seamless upgrade
3302     while we are running...
3303     }); #});
3304     sleep 2;
3305     $CPAN::Frontend->myprint(qq{\n});
3306     }
3307     last if $CPAN::Signal;
3308     } elsif ($mod =~ /^Bundle::(.*)/) {
3309     $bundle = $1;
3310     }
3311    
3312     if ($bundle){
3313     $id = $CPAN::META->instance('CPAN::Bundle',$mod);
3314     # Let's make it a module too, because bundles have so much
3315     # in common with modules.
3316    
3317     # Changed in 1.57_63: seems like memory bloat now without
3318     # any value, so commented out
3319    
3320     # $CPAN::META->instance('CPAN::Module',$mod);
3321    
3322     } else {
3323    
3324     # instantiate a module object
3325     $id = $CPAN::META->instance('CPAN::Module',$mod);
3326    
3327     }
3328    
3329     if ($id->cpan_file ne $dist){ # update only if file is
3330     # different. CPAN prohibits same
3331     # name with different version
3332     $userid = $id->userid || $self->userid($dist);
3333     $id->set(
3334     'CPAN_USERID' => $userid,
3335     'CPAN_VERSION' => $version,
3336     'CPAN_FILE' => $dist,
3337     );
3338     }
3339    
3340     # instantiate a distribution object
3341     if ($CPAN::META->exists('CPAN::Distribution',$dist)) {
3342     # we do not need CONTAINSMODS unless we do something with
3343     # this dist, so we better produce it on demand.
3344    
3345     ## my $obj = $CPAN::META->instance(
3346     ## 'CPAN::Distribution' => $dist
3347     ## );
3348     ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental
3349     } else {
3350     $CPAN::META->instance(
3351     'CPAN::Distribution' => $dist
3352     )->set(
3353     'CPAN_USERID' => $userid,
3354     'CPAN_COMMENT' => $comment,
3355     );
3356     }
3357     if ($secondtime) {
3358     for my $name ($mod,$dist) {
3359     CPAN->debug("exists name[$name]") if $CPAN::DEBUG;
3360     $exists{$name} = undef;
3361     }
3362     }
3363     return if $CPAN::Signal;
3364     }
3365     undef $fh;
3366     if ($secondtime) {
3367     for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) {
3368     for my $o ($CPAN::META->all_objects($class)) {
3369     next if exists $exists{$o->{ID}};
3370     $CPAN::META->delete($class,$o->{ID});
3371     CPAN->debug("deleting ID[$o->{ID}] in class[$class]")
3372     if $CPAN::DEBUG;
3373     }
3374     }
3375     }
3376     }
3377    
3378     #-> sub CPAN::Index::rd_modlist ;
3379     sub rd_modlist {
3380     my($cl,$index_target) = @_;
3381     return unless defined $index_target;
3382     $CPAN::Frontend->myprint("Going to read $index_target\n");
3383     my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
3384     my @eval;
3385     local($/) = "\n";
3386     while ($_ = $fh->READLINE) {
3387     s/\012/\n/g;
3388     my @ls = map {"$_\n"} split /\n/, $_;
3389     unshift @ls, "\n" x length($1) if /^(\n+)/;
3390     push @eval, @ls;
3391     }
3392     while (@eval) {
3393     my $shift = shift(@eval);
3394     if ($shift =~ /^Date:\s+(.*)/){
3395     return if $DATE_OF_03 eq $1;
3396     ($DATE_OF_03) = $1;
3397     }
3398     last if $shift =~ /^\s*$/;
3399     }
3400     undef $fh;
3401     push @eval, q{CPAN::Modulelist->data;};
3402     local($^W) = 0;
3403     my($comp) = Safe->new("CPAN::Safe1");
3404     my($eval) = join("", @eval);
3405     my $ret = $comp->reval($eval);
3406     Carp::confess($@) if $@;
3407     return if $CPAN::Signal;
3408     for (keys %$ret) {
3409     my $obj = $CPAN::META->instance("CPAN::Module",$_);
3410     delete $ret->{$_}{modid}; # not needed here, maybe elsewhere
3411     $obj->set(%{$ret->{$_}});
3412     return if $CPAN::Signal;
3413     }
3414     }
3415    
3416     #-> sub CPAN::Index::write_metadata_cache ;
3417     sub write_metadata_cache {
3418     my($self) = @_;
3419     return unless $CPAN::Config->{'cache_metadata'};
3420     return unless $CPAN::META->has_usable("Storable");
3421     my $cache;
3422     foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module
3423     CPAN::Distribution)) {
3424     $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok
3425     }
3426     my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3427     $cache->{last_time} = $LAST_TIME;
3428     $cache->{DATE_OF_02} = $DATE_OF_02;
3429     $cache->{PROTOCOL} = PROTOCOL;
3430     $CPAN::Frontend->myprint("Going to write $metadata_file\n");
3431     eval { Storable::nstore($cache, $metadata_file) };
3432     $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3433     }
3434    
3435     #-> sub CPAN::Index::read_metadata_cache ;
3436     sub read_metadata_cache {
3437     my($self) = @_;
3438     return unless $CPAN::Config->{'cache_metadata'};
3439     return unless $CPAN::META->has_usable("Storable");
3440     my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
3441     return unless -r $metadata_file and -f $metadata_file;
3442     $CPAN::Frontend->myprint("Going to read $metadata_file\n");
3443     my $cache;
3444     eval { $cache = Storable::retrieve($metadata_file) };
3445     $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
3446     if (!$cache || ref $cache ne 'HASH'){
3447     $LAST_TIME = 0;
3448     return;
3449     }
3450     if (exists $cache->{PROTOCOL}) {
3451     if (PROTOCOL > $cache->{PROTOCOL}) {
3452     $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ".
3453     "with protocol v%s, requiring v%s\n",
3454     $cache->{PROTOCOL},
3455     PROTOCOL)
3456     );
3457     return;
3458     }
3459     } else {
3460     $CPAN::Frontend->mywarn("Ignoring Metadata cache written ".
3461     "with protocol v1.0\n");
3462     return;
3463     }
3464     my $clcnt = 0;
3465     my $idcnt = 0;
3466     while(my($class,$v) = each %$cache) {
3467     next unless $class =~ /^CPAN::/;
3468     $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok
3469     while (my($id,$ro) = each %$v) {
3470     $CPAN::META->{readwrite}{$class}{$id} ||=
3471     $class->new(ID=>$id, RO=>$ro);
3472     $idcnt++;
3473     }
3474     $clcnt++;
3475     }
3476     unless ($clcnt) { # sanity check
3477     $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n");
3478     return;
3479     }
3480     if ($idcnt < 1000) {
3481     $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ".
3482     "in $metadata_file\n");
3483     return;
3484     }
3485     $CPAN::META->{PROTOCOL} ||=
3486     $cache->{PROTOCOL}; # reading does not up or downgrade, but it
3487     # does initialize to some protocol
3488     $LAST_TIME = $cache->{last_time};
3489     $DATE_OF_02 = $cache->{DATE_OF_02};
3490     $CPAN::Frontend->myprint(" Database was generated on $DATE_OF_02\n")
3491     if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
3492     return;
3493     }
3494    
3495     package CPAN::InfoObj;
3496    
3497     # Accessors
3498     sub cpan_userid {
3499     my $self = shift;
3500     $self->{RO}{CPAN_USERID}
3501     }
3502    
3503     sub id { shift->{ID}; }
3504    
3505     #-> sub CPAN::InfoObj::new ;
3506     sub new {
3507     my $this = bless {}, shift;
3508     %$this = @_;
3509     $this
3510     }
3511    
3512     # The set method may only be used by code that reads index data or
3513     # otherwise "objective" data from the outside world. All session
3514     # related material may do anything else with instance variables but
3515     # must not touch the hash under the RO attribute. The reason is that
3516     # the RO hash gets written to Metadata file and is thus persistent.
3517    
3518     #-> sub CPAN::InfoObj::set ;
3519     sub set {
3520     my($self,%att) = @_;
3521     my $class = ref $self;
3522    
3523     # This must be ||=, not ||, because only if we write an empty
3524     # reference, only then the set method will write into the readonly
3525     # area. But for Distributions that spring into existence, maybe
3526     # because of a typo, we do not like it that they are written into
3527     # the readonly area and made permanent (at least for a while) and
3528     # that is why we do not "allow" other places to call ->set.
3529     unless ($self->id) {
3530     CPAN->debug("Bug? Empty ID, rejecting");
3531     return;
3532     }
3533     my $ro = $self->{RO} =
3534     $CPAN::META->{readonly}{$class}{$self->id} ||= {};
3535    
3536     while (my($k,$v) = each %att) {
3537     $ro->{$k} = $v;
3538     }
3539     }
3540    
3541     #-> sub CPAN::InfoObj::as_glimpse ;
3542     sub as_glimpse {
3543     my($self) = @_;
3544     my(@m);
3545     my $class = ref($self);
3546     $class =~ s/^CPAN:://;
3547     push @m, sprintf "%-15s %s\n", $class, $self->{ID};
3548     join "", @m;
3549     }
3550    
3551     #-> sub CPAN::InfoObj::as_string ;
3552     sub as_string {
3553     my($self) = @_;
3554     my(@m);
3555     my $class = ref($self);
3556     $class =~ s/^CPAN:://;
3557     push @m, $class, " id = $self->{ID}\n";
3558     for (sort keys %{$self->{RO}}) {
3559     # next if m/^(ID|RO)$/;
3560     my $extra = "";
3561     if ($_ eq "CPAN_USERID") {
3562     $extra .= " (".$self->author;
3563     my $email; # old perls!
3564     if ($email = $CPAN::META->instance("CPAN::Author",
3565     $self->cpan_userid
3566     )->email) {
3567     $extra .= " <$email>";
3568     } else {
3569     $extra .= " <no email>";
3570     }
3571     $extra .= ")";
3572     } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
3573     push @m, sprintf " %-12s %s\n", $_, $self->fullname;
3574     next;
3575     }
3576     next unless defined $self->{RO}{$_};
3577     push @m, sprintf " %-12s %s%s\n", $_, $self->{RO}{$_}, $extra;
3578     }
3579     for (sort keys %$self) {
3580     next if m/^(ID|RO)$/;
3581     if (ref($self->{$_}) eq "ARRAY") {
3582     push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
3583     } elsif (ref($self->{$_}) eq "HASH") {
3584     push @m, sprintf(
3585     " %-12s %s\n",
3586     $_,
3587     join(" ",keys %{$self->{$_}}),
3588     );
3589     } else {
3590     push @m, sprintf " %-12s %s\n", $_, $self->{$_};
3591     }
3592     }
3593     join "", @m, "\n";
3594     }
3595    
3596     #-> sub CPAN::InfoObj::author ;
3597     sub author {
3598     my($self) = @_;
3599     $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
3600     }
3601    
3602     #-> sub CPAN::InfoObj::dump ;
3603     sub dump {
3604     my($self) = @_;
3605     require Data::Dumper;
3606     print Data::Dumper::Dumper($self);
3607     }
3608    
3609     package CPAN::Author;
3610    
3611     #-> sub CPAN::Author::id
3612     sub id {
3613     my $self = shift;
3614     my $id = $self->{ID};
3615     $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
3616     $id;
3617     }
3618    
3619     #-> sub CPAN::Author::as_glimpse ;
3620     sub as_glimpse {
3621     my($self) = @_;
3622     my(@m);
3623     my $class = ref($self);
3624     $class =~ s/^CPAN:://;
3625     push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
3626     $class,
3627     $self->{ID},
3628     $self->fullname,
3629     $self->email);
3630     join "", @m;
3631     }
3632    
3633     #-> sub CPAN::Author::fullname ;
3634     sub fullname {
3635     shift->{RO}{FULLNAME};
3636     }
3637     *name = \&fullname;
3638    
3639     #-> sub CPAN::Author::email ;
3640     sub email { shift->{RO}{EMAIL}; }
3641    
3642     #-> sub CPAN::Author::ls ;
3643     sub ls {
3644     my $self = shift;
3645     my $id = $self->id;
3646    
3647     # adapted from CPAN::Distribution::verifyMD5 ;
3648     my(@csf); # chksumfile
3649     @csf = $self->id =~ /(.)(.)(.*)/;
3650     $csf[1] = join "", @csf[0,1];
3651     $csf[2] = join "", @csf[1,2];
3652     my(@dl);
3653     @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0);
3654     unless (grep {$_->[2] eq $csf[1]} @dl) {
3655     $CPAN::Frontend->myprint("No files in the directory of $id\n");
3656     return;
3657     }
3658     @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0);
3659     unless (grep {$_->[2] eq $csf[2]} @dl) {
3660     $CPAN::Frontend->myprint("No files in the directory of $id\n");
3661     return;
3662     }
3663     @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1);
3664     $CPAN::Frontend->myprint(join "", map {
3665     sprintf("%8d %10s %s/%s\n", $_->[0], $_->[1], $id, $_->[2])
3666     } sort { $a->[2] cmp $b->[2] } @dl);
3667     }
3668    
3669     # returns an array of arrays, the latter contain (size,mtime,filename)
3670     #-> sub CPAN::Author::dir_listing ;
3671     sub dir_listing {
3672     my $self = shift;
3673     my $chksumfile = shift;
3674     my $recursive = shift;
3675     my $lc_want =
3676     File::Spec->catfile($CPAN::Config->{keep_source_where},
3677     "authors", "id", @$chksumfile);
3678     local($") = "/";
3679     # connect "force" argument with "index_expire".
3680     my $force = 0;
3681     if (my @stat = stat $lc_want) {
3682     $force = $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
3683     }
3684     my $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3685     $lc_want,$force);
3686     unless ($lc_file) {
3687     $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
3688     $chksumfile->[-1] .= ".gz";
3689     $lc_file = CPAN::FTP->localize("authors/id/@$chksumfile",
3690     "$lc_want.gz",1);
3691     if ($lc_file) {
3692     $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
3693     CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
3694     } else {
3695     return;
3696     }
3697     }
3698    
3699     # adapted from CPAN::Distribution::MD5_check_file ;
3700     my $fh = FileHandle->new;
3701     my($cksum);
3702     if (open $fh, $lc_file){
3703     local($/);
3704     my $eval = <$fh>;
3705     $eval =~ s/\015?\012/\n/g;
3706     close $fh;
3707     my($comp) = Safe->new();
3708     $cksum = $comp->reval($eval);
3709     if ($@) {
3710     rename $lc_file, "$lc_file.bad";
3711     Carp::confess($@) if $@;
3712     }
3713     } else {
3714     Carp::carp "Could not open $lc_file for reading";
3715     }
3716     my(@result,$f);
3717     for $f (sort keys %$cksum) {
3718     if (exists $cksum->{$f}{isdir}) {
3719     if ($recursive) {
3720     my(@dir) = @$chksumfile;
3721     pop @dir;
3722     push @dir, $f, "CHECKSUMS";
3723     push @result, map {
3724     [$_->[0], $_->[1], "$f/$_->[2]"]
3725     } $self->dir_listing(\@dir,1);
3726     } else {
3727     push @result, [ 0, "-", $f ];
3728     }
3729     } else {
3730     push @result, [
3731     ($cksum->{$f}{"size"}||0),
3732     $cksum->{$f}{"mtime"}||"---",
3733     $f
3734     ];
3735     }
3736     }
3737     @result;
3738     }
3739    
3740     package CPAN::Distribution;
3741    
3742     # Accessors
3743     sub cpan_comment { shift->{RO}{CPAN_COMMENT} }
3744    
3745     sub undelay {
3746     my $self = shift;
3747     delete $self->{later};
3748     }
3749    
3750     # CPAN::Distribution::normalize
3751     sub normalize {
3752     my($self,$s) = @_;
3753     $s = $self->id unless defined $s;
3754     if (
3755     $s =~ tr|/|| == 1
3756     or
3757     $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
3758     ) {
3759     return $s if $s =~ m:^N/A|^Contact Author: ;
3760     $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4| or
3761     $CPAN::Frontend->mywarn("Strange distribution name [$s]\n");
3762     CPAN->debug("s[$s]") if $CPAN::DEBUG;
3763     }
3764     $s;
3765     }
3766    
3767     #-> sub CPAN::Distribution::color_cmd_tmps ;
3768     sub color_cmd_tmps {
3769     my($self) = shift;
3770     my($depth) = shift || 0;
3771     my($color) = shift || 0;
3772     my($ancestors) = shift || [];
3773     # a distribution needs to recurse into its prereq_pms
3774    
3775     return if exists $self->{incommandcolor}
3776     && $self->{incommandcolor}==$color;
3777     if ($depth>=100){
3778     $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
3779     }
3780     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
3781     my $prereq_pm = $self->prereq_pm;
3782     if (defined $prereq_pm) {
3783     for my $pre (keys %$prereq_pm) {
3784     my $premo = CPAN::Shell->expand("Module",$pre);
3785     $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
3786     }
3787     }
3788     if ($color==0) {
3789     delete $self->{sponsored_mods};
3790     delete $self->{badtestcnt};
3791     }
3792     $self->{incommandcolor} = $color;
3793     }
3794    
3795     #-> sub CPAN::Distribution::as_string ;
3796     sub as_string {
3797     my $self = shift;
3798     $self->containsmods;
3799     $self->SUPER::as_string(@_);
3800     }
3801    
3802     #-> sub CPAN::Distribution::containsmods ;
3803     sub containsmods {
3804     my $self = shift;
3805     return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
3806     my $dist_id = $self->{ID};
3807     for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
3808     my $mod_file = $mod->cpan_file or next;
3809     my $mod_id = $mod->{ID} or next;
3810     # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
3811     # sleep 1;
3812     $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
3813     }
3814     keys %{$self->{CONTAINSMODS}};
3815     }
3816    
3817     #-> sub CPAN::Distribution::uptodate ;
3818     sub uptodate {
3819     my($self) = @_;
3820     my $c;
3821     foreach $c ($self->containsmods) {
3822     my $obj = CPAN::Shell->expandany($c);
3823     return 0 unless $obj->uptodate;
3824     }
3825     return 1;
3826     }
3827    
3828     #-> sub CPAN::Distribution::called_for ;
3829     sub called_for {
3830     my($self,$id) = @_;
3831     $self->{CALLED_FOR} = $id if defined $id;
3832     return $self->{CALLED_FOR};
3833     }
3834    
3835     #-> sub CPAN::Distribution::safe_chdir ;
3836     sub safe_chdir {
3837     my($self,$todir) = @_;
3838     # we die if we cannot chdir and we are debuggable
3839     Carp::confess("safe_chdir called without todir argument")
3840     unless defined $todir and length $todir;
3841     if (chdir $todir) {
3842     $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
3843     if $CPAN::DEBUG;
3844     } else {
3845     my $cwd = CPAN::anycwd();
3846     $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
3847     qq{to todir[$todir]: $!});
3848     }
3849     }
3850    
3851     #-> sub CPAN::Distribution::get ;
3852     sub get {
3853     my($self) = @_;
3854     EXCUSE: {
3855     my @e;
3856     exists $self->{'build_dir'} and push @e,
3857     "Is already unwrapped into directory $self->{'build_dir'}";
3858     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
3859     }
3860     my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
3861    
3862     #
3863     # Get the file on local disk
3864     #
3865    
3866     my($local_file);
3867     my($local_wanted) =
3868     File::Spec->catfile(
3869     $CPAN::Config->{keep_source_where},
3870     "authors",
3871     "id",
3872     split(/\//,$self->id)
3873     );
3874    
3875     $self->debug("Doing localize") if $CPAN::DEBUG;
3876     unless ($local_file =
3877     CPAN::FTP->localize("authors/id/$self->{ID}",
3878     $local_wanted)) {
3879     my $note = "";
3880     if ($CPAN::Index::DATE_OF_02) {
3881     $note = "Note: Current database in memory was generated ".
3882     "on $CPAN::Index::DATE_OF_02\n";
3883     }
3884     $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
3885     }
3886     $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
3887     $self->{localfile} = $local_file;
3888     return if $CPAN::Signal;
3889    
3890     #
3891     # Check integrity
3892     #
3893     if ($CPAN::META->has_inst("Digest::MD5")) {
3894     $self->debug("Digest::MD5 is installed, verifying");
3895     $self->verifyMD5;
3896     } else {
3897     $self->debug("Digest::MD5 is NOT installed");
3898     }
3899     return if $CPAN::Signal;
3900    
3901     #
3902     # Create a clean room and go there
3903     #
3904     $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
3905     my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
3906     $self->safe_chdir($builddir);
3907     $self->debug("Removing tmp") if $CPAN::DEBUG;
3908     File::Path::rmtree("tmp");
3909     mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!";
3910     if ($CPAN::Signal){
3911     $self->safe_chdir($sub_wd);
3912     return;
3913     }
3914     $self->safe_chdir("tmp");
3915    
3916     #
3917     # Unpack the goods
3918     #
3919     if ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)(?!\n)\Z/i){
3920     $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3921     $self->untar_me($local_file);
3922     } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
3923     $self->unzip_me($local_file);
3924     } elsif ( $local_file =~ /\.pm\.(gz|Z)(?!\n)\Z/) {
3925     $self->{was_uncompressed}++ unless CPAN::Tarzip->gtest($local_file);
3926     $self->pm2dir_me($local_file);
3927     } else {
3928     $self->{archived} = "NO";
3929     $self->safe_chdir($sub_wd);
3930     return;
3931     }
3932    
3933     # we are still in the tmp directory!
3934     # Let's check if the package has its own directory.
3935     my $dh = DirHandle->new(File::Spec->curdir)
3936     or Carp::croak("Couldn't opendir .: $!");
3937     my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
3938     $dh->close;
3939     my ($distdir,$packagedir);
3940     if (@readdir == 1 && -d $readdir[0]) {
3941     $distdir = $readdir[0];
3942     $packagedir = File::Spec->catdir($builddir,$distdir);
3943     $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]")
3944     if $CPAN::DEBUG;
3945     -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
3946     "$packagedir\n");
3947     File::Path::rmtree($packagedir);
3948     rename($distdir,$packagedir) or
3949     Carp::confess("Couldn't rename $distdir to $packagedir: $!");
3950     $self->debug(sprintf("renamed distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
3951     $distdir,
3952     $packagedir,
3953     -e $packagedir,
3954     -d $packagedir,
3955     )) if $CPAN::DEBUG;
3956     } else {
3957     my $userid = $self->cpan_userid;
3958     unless ($userid) {
3959     CPAN->debug("no userid? self[$self]");
3960     $userid = "anon";
3961     }
3962     my $pragmatic_dir = $userid . '000';
3963     $pragmatic_dir =~ s/\W_//g;
3964     $pragmatic_dir++ while -d "../$pragmatic_dir";
3965     $packagedir = File::Spec->catdir($builddir,$pragmatic_dir);
3966     $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG;
3967     File::Path::mkpath($packagedir);
3968     my($f);
3969     for $f (@readdir) { # is already without "." and ".."
3970     my $to = File::Spec->catdir($packagedir,$f);
3971     rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!");
3972     }
3973     }
3974     if ($CPAN::Signal){
3975     $self->safe_chdir($sub_wd);
3976     return;
3977     }
3978    
3979     $self->{'build_dir'} = $packagedir;
3980     $self->safe_chdir($builddir);
3981     File::Path::rmtree("tmp");
3982    
3983     my($mpl) = File::Spec->catfile($packagedir,"Makefile.PL");
3984     my($mpl_exists) = -f $mpl;
3985     unless ($mpl_exists) {
3986     # NFS has been reported to have racing problems after the
3987     # renaming of a directory in some environments.
3988     # This trick helps.
3989     sleep 1;
3990     my $mpldh = DirHandle->new($packagedir)
3991     or Carp::croak("Couldn't opendir $packagedir: $!");
3992     $mpl_exists = grep /^Makefile\.PL$/, $mpldh->read;
3993     $mpldh->close;
3994     }
3995     unless ($mpl_exists) {
3996     $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
3997     $mpl,
3998     CPAN::anycwd(),
3999     )) if $CPAN::DEBUG;
4000     my($configure) = File::Spec->catfile($packagedir,"Configure");
4001     if (-f $configure) {
4002     # do we have anything to do?
4003     $self->{'configure'} = $configure;
4004     } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
4005     $CPAN::Frontend->myprint(qq{
4006     Package comes with a Makefile and without a Makefile.PL.
4007     We\'ll try to build it with that Makefile then.
4008     });
4009     $self->{writemakefile} = "YES";
4010     sleep 2;
4011     } else {
4012     my $cf = $self->called_for || "unknown";
4013     if ($cf =~ m|/|) {
4014     $cf =~ s|.*/||;
4015     $cf =~ s|\W.*||;
4016     }
4017     $cf =~ s|[/\\:]||g; # risk of filesystem damage
4018     $cf = "unknown" unless length($cf);
4019     $CPAN::Frontend->myprint(qq{Package seems to come without Makefile.PL.
4020     (The test -f "$mpl" returned false.)
4021     Writing one on our own (setting NAME to $cf)\a\n});
4022     $self->{had_no_makefile_pl}++;
4023     sleep 3;
4024    
4025     # Writing our own Makefile.PL
4026    
4027     my $fh = FileHandle->new;
4028     $fh->open(">$mpl")
4029     or Carp::croak("Could not open >$mpl: $!");
4030     $fh->print(
4031     qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
4032     # because there was no Makefile.PL supplied.
4033     # Autogenerated on: }.scalar localtime().qq{
4034    
4035     use ExtUtils::MakeMaker;
4036     WriteMakefile(NAME => q[$cf]);
4037    
4038     });
4039     $fh->close;
4040     }
4041     }
4042    
4043     return $self;
4044     }
4045    
4046     # CPAN::Distribution::untar_me ;
4047     sub untar_me {
4048     my($self,$local_file) = @_;
4049     $self->{archived} = "tar";
4050     if (CPAN::Tarzip->untar($local_file)) {
4051     $self->{unwrapped} = "YES";
4052     } else {
4053     $self->{unwrapped} = "NO";
4054     }
4055     }
4056    
4057     # CPAN::Distribution::unzip_me ;
4058     sub unzip_me {
4059     my($self,$local_file) = @_;
4060     $self->{archived} = "zip";
4061     if (CPAN::Tarzip->unzip($local_file)) {
4062     $self->{unwrapped} = "YES";
4063     } else {
4064     $self->{unwrapped} = "NO";
4065     }
4066     return;
4067     }
4068    
4069     sub pm2dir_me {
4070     my($self,$local_file) = @_;
4071     $self->{archived} = "pm";
4072     my $to = File::Basename::basename($local_file);
4073     $to =~ s/\.(gz|Z)(?!\n)\Z//;
4074     if (CPAN::Tarzip->gunzip($local_file,$to)) {
4075     $self->{unwrapped} = "YES";
4076     } else {
4077     $self->{unwrapped} = "NO";
4078     }
4079     }
4080    
4081     #-> sub CPAN::Distribution::new ;
4082     sub new {
4083     my($class,%att) = @_;
4084    
4085     # $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();
4086    
4087     my $this = { %att };
4088     return bless $this, $class;
4089     }
4090    
4091     #-> sub CPAN::Distribution::look ;
4092     sub look {
4093     my($self) = @_;
4094    
4095     if ($^O eq 'MacOS') {
4096     $self->Mac::BuildTools::look;
4097     return;
4098     }
4099    
4100     if ( $CPAN::Config->{'shell'} ) {
4101     $CPAN::Frontend->myprint(qq{
4102     Trying to open a subshell in the build directory...
4103     });
4104     } else {
4105     $CPAN::Frontend->myprint(qq{
4106     Your configuration does not define a value for subshells.
4107     Please define it with "o conf shell <your shell>"
4108     });
4109     return;
4110     }
4111     my $dist = $self->id;
4112     my $dir;
4113     unless ($dir = $self->dir) {
4114     $self->get;
4115     }
4116     unless ($dir ||= $self->dir) {
4117     $CPAN::Frontend->mywarn(qq{
4118     Could not determine which directory to use for looking at $dist.
4119     });
4120     return;
4121     }
4122     my $pwd = CPAN::anycwd();
4123     $self->safe_chdir($dir);
4124     $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4125     unless (system($CPAN::Config->{'shell'}) == 0) {
4126     my $code = $? >> 8;
4127     $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
4128     }
4129     $self->safe_chdir($pwd);
4130     }
4131    
4132     # CPAN::Distribution::cvs_import ;
4133     sub cvs_import {
4134     my($self) = @_;
4135     $self->get;
4136     my $dir = $self->dir;
4137    
4138     my $package = $self->called_for;
4139     my $module = $CPAN::META->instance('CPAN::Module', $package);
4140     my $version = $module->cpan_version;
4141    
4142     my $userid = $self->cpan_userid;
4143    
4144     my $cvs_dir = (split /\//, $dir)[-1];
4145     $cvs_dir =~ s/-\d+[^-]+(?!\n)\Z//;
4146     my $cvs_root =
4147     $CPAN::Config->{cvsroot} || $ENV{CVSROOT};
4148     my $cvs_site_perl =
4149     $CPAN::Config->{cvs_site_perl} || $ENV{CVS_SITE_PERL};
4150     if ($cvs_site_perl) {
4151     $cvs_dir = "$cvs_site_perl/$cvs_dir";
4152     }
4153     my $cvs_log = qq{"imported $package $version sources"};
4154     $version =~ s/\./_/g;
4155     my @cmd = ('cvs', '-d', $cvs_root, 'import', '-m', $cvs_log,
4156     "$cvs_dir", $userid, "v$version");
4157    
4158     my $pwd = CPAN::anycwd();
4159     chdir($dir) or $CPAN::Frontend->mydie(qq{Could not chdir to "$dir": $!});
4160    
4161     $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
4162    
4163     $CPAN::Frontend->myprint(qq{@cmd\n});
4164     system(@cmd) == 0 or
4165     $CPAN::Frontend->mydie("cvs import failed");
4166     chdir($pwd) or $CPAN::Frontend->mydie(qq{Could not chdir to "$pwd": $!});
4167     }
4168    
4169     #-> sub CPAN::Distribution::readme ;
4170     sub readme {
4171     my($self) = @_;
4172     my($dist) = $self->id;
4173     my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/;
4174     $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG;
4175     my($local_file);
4176     my($local_wanted) =
4177     File::Spec->catfile(
4178     $CPAN::Config->{keep_source_where},
4179     "authors",
4180     "id",
4181     split(/\//,"$sans.readme"),
4182     );
4183     $self->debug("Doing localize") if $CPAN::DEBUG;
4184     $local_file = CPAN::FTP->localize("authors/id/$sans.readme",
4185     $local_wanted)
4186     or $CPAN::Frontend->mydie(qq{No $sans.readme found});;
4187    
4188     if ($^O eq 'MacOS') {
4189     Mac::BuildTools::launch_file($local_file);
4190     return;
4191     }
4192    
4193     my $fh_pager = FileHandle->new;
4194     local($SIG{PIPE}) = "IGNORE";
4195     $fh_pager->open("|$CPAN::Config->{'pager'}")
4196     or die "Could not open pager $CPAN::Config->{'pager'}: $!";
4197     my $fh_readme = FileHandle->new;
4198     $fh_readme->open($local_file)
4199     or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!});
4200     $CPAN::Frontend->myprint(qq{
4201     Displaying file
4202     $local_file
4203     with pager "$CPAN::Config->{'pager'}"
4204     });
4205     sleep 2;
4206     $fh_pager->print(<$fh_readme>);
4207     }
4208    
4209     #-> sub CPAN::Distribution::verifyMD5 ;
4210     sub verifyMD5 {
4211     my($self) = @_;
4212     EXCUSE: {
4213     my @e;
4214     $self->{MD5_STATUS} ||= "";
4215     $self->{MD5_STATUS} eq "OK" and push @e, "MD5 Checksum was ok";
4216     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4217     }
4218     my($lc_want,$lc_file,@local,$basename);
4219     @local = split(/\//,$self->id);
4220     pop @local;
4221     push @local, "CHECKSUMS";
4222     $lc_want =
4223     File::Spec->catfile($CPAN::Config->{keep_source_where},
4224     "authors", "id", @local);
4225     local($") = "/";
4226     if (
4227     -s $lc_want
4228     &&
4229     $self->MD5_check_file($lc_want)
4230     ) {
4231     return $self->{MD5_STATUS} = "OK";
4232     }
4233     $lc_file = CPAN::FTP->localize("authors/id/@local",
4234     $lc_want,1);
4235     unless ($lc_file) {
4236     $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
4237     $local[-1] .= ".gz";
4238     $lc_file = CPAN::FTP->localize("authors/id/@local",
4239     "$lc_want.gz",1);
4240     if ($lc_file) {
4241     $lc_file =~ s/\.gz(?!\n)\Z//;
4242     CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
4243     } else {
4244     return;
4245     }
4246     }
4247     $self->MD5_check_file($lc_file);
4248     }
4249    
4250     #-> sub CPAN::Distribution::MD5_check_file ;
4251     sub MD5_check_file {
4252     my($self,$chk_file) = @_;
4253     my($cksum,$file,$basename);
4254     $file = $self->{localfile};
4255     $basename = File::Basename::basename($file);
4256     my $fh = FileHandle->new;
4257     if (open $fh, $chk_file){
4258     local($/);
4259     my $eval = <$fh>;
4260     $eval =~ s/\015?\012/\n/g;
4261     close $fh;
4262     my($comp) = Safe->new();
4263     $cksum = $comp->reval($eval);
4264     if ($@) {
4265     rename $chk_file, "$chk_file.bad";
4266     Carp::confess($@) if $@;
4267     }
4268     } else {
4269     Carp::carp "Could not open $chk_file for reading";
4270     }
4271    
4272     if (exists $cksum->{$basename}{md5}) {
4273     $self->debug("Found checksum for $basename:" .
4274     "$cksum->{$basename}{md5}\n") if $CPAN::DEBUG;
4275    
4276     open($fh, $file);
4277     binmode $fh;
4278     my $eq = $self->eq_MD5($fh,$cksum->{$basename}{'md5'});
4279     $fh->close;
4280     $fh = CPAN::Tarzip->TIEHANDLE($file);
4281    
4282     unless ($eq) {
4283     # had to inline it, when I tied it, the tiedness got lost on
4284     # the call to eq_MD5. (Jan 1998)
4285     my $md5 = Digest::MD5->new;
4286     my($data,$ref);
4287     $ref = \$data;
4288     while ($fh->READ($ref, 4096) > 0){
4289     $md5->add($data);
4290     }
4291     my $hexdigest = $md5->hexdigest;
4292     $eq += $hexdigest eq $cksum->{$basename}{'md5-ungz'};
4293     }
4294    
4295     if ($eq) {
4296     $CPAN::Frontend->myprint("Checksum for $file ok\n");
4297     return $self->{MD5_STATUS} = "OK";
4298     } else {
4299     $CPAN::Frontend->myprint(qq{\nChecksum mismatch for }.
4300     qq{distribution file. }.
4301     qq{Please investigate.\n\n}.
4302     $self->as_string,
4303     $CPAN::META->instance(
4304     'CPAN::Author',
4305     $self->cpan_userid
4306     )->as_string);
4307    
4308     my $wrap = qq{I\'d recommend removing $file. Its MD5
4309     checksum is incorrect. Maybe you have configured your 'urllist' with
4310     a bad URL. Please check this array with 'o conf urllist', and
4311     retry.};
4312    
4313     $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
4314    
4315     # former versions just returned here but this seems a
4316     # serious threat that deserves a die
4317    
4318     # $CPAN::Frontend->myprint("\n\n");
4319     # sleep 3;
4320     # return;
4321     }
4322     # close $fh if fileno($fh);
4323     } else {
4324     $self->{MD5_STATUS} ||= "";
4325     if ($self->{MD5_STATUS} eq "NIL") {
4326     $CPAN::Frontend->mywarn(qq{
4327     Warning: No md5 checksum for $basename in $chk_file.
4328    
4329     The cause for this may be that the file is very new and the checksum
4330     has not yet been calculated, but it may also be that something is
4331     going awry right now.
4332     });
4333     my $answer = ExtUtils::MakeMaker::prompt("Proceed?", "yes");
4334     $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.");
4335     }
4336     $self->{MD5_STATUS} = "NIL";
4337     return;
4338     }
4339     }
4340    
4341     #-> sub CPAN::Distribution::eq_MD5 ;
4342     sub eq_MD5 {
4343     my($self,$fh,$expectMD5) = @_;
4344     my $md5 = Digest::MD5->new;
4345     my($data);
4346     while (read($fh, $data, 4096)){
4347     $md5->add($data);
4348     }
4349     # $md5->addfile($fh);
4350     my $hexdigest = $md5->hexdigest;
4351     # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]";
4352     $hexdigest eq $expectMD5;
4353     }
4354    
4355     #-> sub CPAN::Distribution::force ;
4356    
4357     # Both modules and distributions know if "force" is in effect by
4358     # autoinspection, not by inspecting a global variable. One of the
4359     # reason why this was chosen to work that way was the treatment of
4360     # dependencies. They should not autpomatically inherit the force
4361     # status. But this has the downside that ^C and die() will return to
4362     # the prompt but will not be able to reset the force_update
4363     # attributes. We try to correct for it currently in the read_metadata
4364     # routine, and immediately before we check for a Signal. I hope this
4365     # works out in one of v1.57_53ff
4366    
4367     sub force {
4368     my($self, $method) = @_;
4369     for my $att (qw(
4370     MD5_STATUS archived build_dir localfile make install unwrapped
4371     writemakefile
4372     )) {
4373     delete $self->{$att};
4374     }
4375     if ($method && $method eq "install") {
4376     $self->{"force_update"}++; # name should probably have been force_install
4377     }
4378     }
4379    
4380     #-> sub CPAN::Distribution::unforce ;
4381     sub unforce {
4382     my($self) = @_;
4383     delete $self->{'force_update'};
4384     }
4385    
4386     #-> sub CPAN::Distribution::isa_perl ;
4387     sub isa_perl {
4388     my($self) = @_;
4389     my $file = File::Basename::basename($self->id);
4390     if ($file =~ m{ ^ perl
4391     -?
4392     (5)
4393     ([._-])
4394     (
4395     \d{3}(_[0-4][0-9])?
4396     |
4397     \d*[24680]\.\d+
4398     )
4399     \.tar[._-]gz
4400     (?!\n)\Z
4401     }xs){
4402     return "$1.$3";
4403     } elsif ($self->cpan_comment
4404     &&
4405     $self->cpan_comment =~ /isa_perl\(.+?\)/){
4406     return $1;
4407     }
4408     }
4409    
4410     #-> sub CPAN::Distribution::perl ;
4411     sub perl {
4412     my($self) = @_;
4413     my($perl) = File::Spec->file_name_is_absolute($^X) ? $^X : "";
4414     my $pwd = CPAN::anycwd();
4415     my $candidate = File::Spec->catfile($pwd,$^X);
4416     $perl ||= $candidate if MM->maybe_command($candidate);
4417     unless ($perl) {
4418     my ($component,$perl_name);
4419     DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
4420     PATH_COMPONENT: foreach $component (File::Spec->path(),
4421     $Config::Config{'binexp'}) {
4422     next unless defined($component) && $component;
4423     my($abs) = File::Spec->catfile($component,$perl_name);
4424     if (MM->maybe_command($abs)) {
4425     $perl = $abs;
4426     last DIST_PERLNAME;
4427     }
4428     }
4429     }
4430     }
4431     $perl;
4432     }
4433    
4434     #-> sub CPAN::Distribution::make ;
4435     sub make {
4436     my($self) = @_;
4437     $CPAN::Frontend->myprint(sprintf "Running make for %s\n", $self->id);
4438     # Emergency brake if they said install Pippi and get newest perl
4439     if ($self->isa_perl) {
4440     if (
4441     $self->called_for ne $self->id &&
4442     ! $self->{force_update}
4443     ) {
4444     # if we die here, we break bundles
4445     $CPAN::Frontend->mywarn(sprintf qq{
4446     The most recent version "%s" of the module "%s"
4447     comes with the current version of perl (%s).
4448     I\'ll build that only if you ask for something like
4449     force install %s
4450     or
4451     install %s
4452     },
4453     $CPAN::META->instance(
4454     'CPAN::Module',
4455     $self->called_for
4456     )->cpan_version,
4457     $self->called_for,
4458     $self->isa_perl,
4459     $self->called_for,
4460     $self->id);
4461     sleep 5; return;
4462     }
4463     }
4464     $self->get;
4465     EXCUSE: {
4466     my @e;
4467     $self->{archived} eq "NO" and push @e,
4468     "Is neither a tar nor a zip archive.";
4469    
4470     $self->{unwrapped} eq "NO" and push @e,
4471     "had problems unarchiving. Please build manually";
4472    
4473     exists $self->{writemakefile} &&
4474     $self->{writemakefile} =~ m/ ^ NO\s* ( .* ) /sx and push @e,
4475     $1 || "Had some problem writing Makefile";
4476    
4477     defined $self->{'make'} and push @e,
4478     "Has already been processed within this session";
4479    
4480     exists $self->{later} and length($self->{later}) and
4481     push @e, $self->{later};
4482    
4483     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4484     }
4485     $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n");
4486     my $builddir = $self->dir;
4487     chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
4488     $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;
4489    
4490     if ($^O eq 'MacOS') {
4491     Mac::BuildTools::make($self);
4492     return;
4493     }
4494    
4495     my $system;
4496     if ($self->{'configure'}) {
4497     $system = $self->{'configure'};
4498     } else {
4499     my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
4500     my $switch = "";
4501     # This needs a handler that can be turned on or off:
4502     # $switch = "-MExtUtils::MakeMaker ".
4503     # "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
4504     # if $] > 5.00310;
4505     $system = "$perl $switch Makefile.PL $CPAN::Config->{makepl_arg}";
4506     }
4507     unless (exists $self->{writemakefile}) {
4508     local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
4509     my($ret,$pid);
4510     $@ = "";
4511     if ($CPAN::Config->{inactivity_timeout}) {
4512     eval {
4513     alarm $CPAN::Config->{inactivity_timeout};
4514     local $SIG{CHLD}; # = sub { wait };
4515     if (defined($pid = fork)) {
4516     if ($pid) { #parent
4517     # wait;
4518     waitpid $pid, 0;
4519     } else { #child
4520     # note, this exec isn't necessary if
4521     # inactivity_timeout is 0. On the Mac I'd
4522     # suggest, we set it always to 0.
4523     exec $system;
4524     }
4525     } else {
4526     $CPAN::Frontend->myprint("Cannot fork: $!");
4527     return;
4528     }
4529     };
4530     alarm 0;
4531     if ($@){
4532     kill 9, $pid;
4533     waitpid $pid, 0;
4534     $CPAN::Frontend->myprint($@);
4535     $self->{writemakefile} = "NO $@";
4536     $@ = "";
4537     return;
4538     }
4539     } else {
4540     $ret = system($system);
4541     if ($ret != 0) {
4542     $self->{writemakefile} = "NO Makefile.PL returned status $ret";
4543     return;
4544     }
4545     }
4546     if (-f "Makefile") {
4547     $self->{writemakefile} = "YES";
4548     delete $self->{make_clean}; # if cleaned before, enable next
4549     } else {
4550     $self->{writemakefile} =
4551     qq{NO Makefile.PL refused to write a Makefile.};
4552     # It's probably worth it to record the reason, so let's retry
4553     # local $/;
4554     # my $fh = IO::File->new("$system |"); # STDERR? STDIN?
4555     # $self->{writemakefile} .= <$fh>;
4556     }
4557     }
4558     if ($CPAN::Signal){
4559     delete $self->{force_update};
4560     return;
4561     }
4562     if (my @prereq = $self->unsat_prereq){
4563     return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
4564     }
4565     $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg};
4566     if (system($system) == 0) {
4567     $CPAN::Frontend->myprint(" $system -- OK\n");
4568     $self->{'make'} = "YES";
4569     } else {
4570     $self->{writemakefile} ||= "YES";
4571     $self->{'make'} = "NO";
4572     $CPAN::Frontend->myprint(" $system -- NOT OK\n");
4573     }
4574     }
4575    
4576     sub follow_prereqs {
4577     my($self) = shift;
4578     my(@prereq) = @_;
4579     my $id = $self->id;
4580     $CPAN::Frontend->myprint("---- Unsatisfied dependencies detected ".
4581     "during [$id] -----\n");
4582    
4583     for my $p (@prereq) {
4584     $CPAN::Frontend->myprint(" $p\n");
4585     }
4586     my $follow = 0;
4587     if ($CPAN::Config->{prerequisites_policy} eq "follow") {
4588     $follow = 1;
4589     } elsif ($CPAN::Config->{prerequisites_policy} eq "ask") {
4590     require ExtUtils::MakeMaker;
4591     my $answer = ExtUtils::MakeMaker::prompt(
4592     "Shall I follow them and prepend them to the queue
4593     of modules we are processing right now?", "yes");
4594     $follow = $answer =~ /^\s*y/i;
4595     } else {
4596     local($") = ", ";
4597     $CPAN::Frontend->
4598     myprint(" Ignoring dependencies on modules @prereq\n");
4599     }
4600     if ($follow) {
4601     # color them as dirty
4602     for my $p (@prereq) {
4603     # warn "calling color_cmd_tmps(0,1)";
4604     CPAN::Shell->expandany($p)->color_cmd_tmps(0,1);
4605     }
4606     CPAN::Queue->jumpqueue(@prereq,$id); # queue them and requeue yourself
4607     $self->{later} = "Delayed until after prerequisites";
4608     return 1; # signal success to the queuerunner
4609     }
4610     }
4611    
4612     #-> sub CPAN::Distribution::unsat_prereq ;
4613     sub unsat_prereq {
4614     my($self) = @_;
4615     my $prereq_pm = $self->prereq_pm or return;
4616     my(@need);
4617     NEED: while (my($need_module, $need_version) = each %$prereq_pm) {
4618     my $nmo = $CPAN::META->instance("CPAN::Module",$need_module);
4619     # we were too demanding:
4620     next if $nmo->uptodate;
4621    
4622     # if they have not specified a version, we accept any installed one
4623     if (not defined $need_version or
4624     $need_version == 0 or
4625     $need_version eq "undef") {
4626     next if defined $nmo->inst_file;
4627     }
4628    
4629     # We only want to install prereqs if either they're not installed
4630     # or if the installed version is too old. We cannot omit this
4631     # check, because if 'force' is in effect, nobody else will check.
4632     {
4633     local($^W) = 0;
4634     if (
4635     defined $nmo->inst_file &&
4636     ! CPAN::Version->vgt($need_version, $nmo->inst_version)
4637     ){
4638     CPAN->debug(sprintf "id[%s]inst_file[%s]inst_version[%s]need_version[%s]",
4639     $nmo->id,
4640     $nmo->inst_file,
4641     $nmo->inst_version,
4642     CPAN::Version->readable($need_version)
4643     );
4644     next NEED;
4645     }
4646     }
4647    
4648     if ($self->{sponsored_mods}{$need_module}++){
4649     # We have already sponsored it and for some reason it's still
4650     # not available. So we do nothing. Or what should we do?
4651     # if we push it again, we have a potential infinite loop
4652     next;
4653     }
4654     push @need, $need_module;
4655     }
4656     @need;
4657     }
4658    
4659     #-> sub CPAN::Distribution::prereq_pm ;
4660     sub prereq_pm {
4661     my($self) = @_;
4662     return $self->{prereq_pm} if
4663     exists $self->{prereq_pm_detected} && $self->{prereq_pm_detected};
4664     return unless $self->{writemakefile}; # no need to have succeeded
4665     # but we must have run it
4666     my $build_dir = $self->{build_dir} or die "Panic: no build_dir?";
4667     my $makefile = File::Spec->catfile($build_dir,"Makefile");
4668     my(%p) = ();
4669     my $fh;
4670     if (-f $makefile
4671     and
4672     $fh = FileHandle->new("<$makefile\0")) {
4673    
4674     local($/) = "\n";
4675    
4676     # A.Speer @p -> %p, where %p is $p{Module::Name}=Required_Version
4677     while (<$fh>) {
4678     last if /MakeMaker post_initialize section/;
4679     my($p) = m{^[\#]
4680     \s+PREREQ_PM\s+=>\s+(.+)
4681     }x;
4682     next unless $p;
4683     # warn "Found prereq expr[$p]";
4684    
4685     # Regexp modified by A.Speer to remember actual version of file
4686     # PREREQ_PM hash key wants, then add to
4687     while ( $p =~ m/(?:\s)([\w\:]+)=>q\[(.*?)\],?/g ){
4688     # In case a prereq is mentioned twice, complain.
4689     if ( defined $p{$1} ) {
4690     warn "Warning: PREREQ_PM mentions $1 more than once, last mention wins";
4691     }
4692     $p{$1} = $2;
4693     }
4694     last;
4695     }
4696     }
4697     $self->{prereq_pm_detected}++;
4698     return $self->{prereq_pm} = \%p;
4699     }
4700    
4701     #-> sub CPAN::Distribution::test ;
4702     sub test {
4703     my($self) = @_;
4704     $self->make;
4705     if ($CPAN::Signal){
4706     delete $self->{force_update};
4707     return;
4708     }
4709     $CPAN::Frontend->myprint("Running make test\n");
4710     if (my @prereq = $self->unsat_prereq){
4711     return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
4712     }
4713     EXCUSE: {
4714     my @e;
4715     exists $self->{make} or exists $self->{later} or push @e,
4716     "Make had some problems, maybe interrupted? Won't test";
4717    
4718     exists $self->{'make'} and
4719     $self->{'make'} eq 'NO' and
4720     push @e, "Can't test without successful make";
4721    
4722     exists $self->{build_dir} or push @e, "Has no own directory";
4723     $self->{badtestcnt} ||= 0;
4724     $self->{badtestcnt} > 0 and
4725     push @e, "Won't repeat unsuccessful test during this command";
4726    
4727     exists $self->{later} and length($self->{later}) and
4728     push @e, $self->{later};
4729    
4730     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4731     }
4732     chdir $self->{'build_dir'} or
4733     Carp::croak("Couldn't chdir to $self->{'build_dir'}");
4734     $self->debug("Changed directory to $self->{'build_dir'}")
4735     if $CPAN::DEBUG;
4736    
4737     if ($^O eq 'MacOS') {
4738     Mac::BuildTools::make_test($self);
4739     return;
4740     }
4741    
4742     local $ENV{PERL5LIB} = $ENV{PERL5LIB} || "";
4743     $CPAN::META->set_perl5lib;
4744     my $system = join " ", $CPAN::Config->{'make'}, "test";
4745     if (system($system) == 0) {
4746     $CPAN::Frontend->myprint(" $system -- OK\n");
4747     $CPAN::META->is_tested($self->{'build_dir'});
4748     $self->{make_test} = "YES";
4749     } else {
4750     $self->{make_test} = "NO";
4751     $self->{badtestcnt}++;
4752     $CPAN::Frontend->myprint(" $system -- NOT OK\n");
4753     }
4754     }
4755    
4756     #-> sub CPAN::Distribution::clean ;
4757     sub clean {
4758     my($self) = @_;
4759     $CPAN::Frontend->myprint("Running make clean\n");
4760     EXCUSE: {
4761     my @e;
4762     exists $self->{make_clean} and $self->{make_clean} eq "YES" and
4763     push @e, "make clean already called once";
4764     exists $self->{build_dir} or push @e, "Has no own directory";
4765     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4766     }
4767     chdir $self->{'build_dir'} or
4768     Carp::croak("Couldn't chdir to $self->{'build_dir'}");
4769     $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG;
4770    
4771     if ($^O eq 'MacOS') {
4772     Mac::BuildTools::make_clean($self);
4773     return;
4774     }
4775    
4776     my $system = join " ", $CPAN::Config->{'make'}, "clean";
4777     if (system($system) == 0) {
4778     $CPAN::Frontend->myprint(" $system -- OK\n");
4779    
4780     # $self->force;
4781    
4782     # Jost Krieger pointed out that this "force" was wrong because
4783     # it has the effect that the next "install" on this distribution
4784     # will untar everything again. Instead we should bring the
4785     # object's state back to where it is after untarring.
4786    
4787     delete $self->{force_update};
4788     delete $self->{install};
4789     delete $self->{writemakefile};
4790     delete $self->{make};
4791     delete $self->{make_test}; # no matter if yes or no, tests must be redone
4792     $self->{make_clean} = "YES";
4793    
4794     } else {
4795     # Hmmm, what to do if make clean failed?
4796    
4797     $CPAN::Frontend->myprint(qq{ $system -- NOT OK
4798    
4799     make clean did not succeed, marking directory as unusable for further work.
4800     });
4801     $self->force("make"); # so that this directory won't be used again
4802    
4803     }
4804     }
4805    
4806     #-> sub CPAN::Distribution::install ;
4807     sub install {
4808     my($self) = @_;
4809     $self->test;
4810     if ($CPAN::Signal){
4811     delete $self->{force_update};
4812     return;
4813     }
4814     $CPAN::Frontend->myprint("Running make install\n");
4815     EXCUSE: {
4816     my @e;
4817     exists $self->{build_dir} or push @e, "Has no own directory";
4818    
4819     exists $self->{make} or exists $self->{later} or push @e,
4820     "Make had some problems, maybe interrupted? Won't install";
4821    
4822     exists $self->{'make'} and
4823     $self->{'make'} eq 'NO' and
4824     push @e, "make had returned bad status, install seems impossible";
4825    
4826     push @e, "make test had returned bad status, ".
4827     "won't install without force"
4828     if exists $self->{'make_test'} and
4829     $self->{'make_test'} eq 'NO' and
4830     ! $self->{'force_update'};
4831    
4832     exists $self->{'install'} and push @e,
4833     $self->{'install'} eq "YES" ?
4834     "Already done" : "Already tried without success";
4835    
4836     exists $self->{later} and length($self->{later}) and
4837     push @e, $self->{later};
4838    
4839     $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
4840     }
4841     chdir $self->{'build_dir'} or
4842     Carp::croak("Couldn't chdir to $self->{'build_dir'}");
4843     $self->debug("Changed directory to $self->{'build_dir'}")
4844     if $CPAN::DEBUG;
4845    
4846     if ($^O eq 'MacOS') {
4847     Mac::BuildTools::make_install($self);
4848     return;
4849     }
4850    
4851     my $system = join(" ", $CPAN::Config->{'make'},
4852     "install", $CPAN::Config->{make_install_arg});
4853     my($stderr) = $^O =~ /Win/i ? "" : " 2>&1 ";
4854     my($pipe) = FileHandle->new("$system $stderr |");
4855     my($makeout) = "";
4856     while (<$pipe>){
4857     $CPAN::Frontend->myprint($_);
4858     $makeout .= $_;
4859     }
4860     $pipe->close;
4861     if ($?==0) {
4862     $CPAN::Frontend->myprint(" $system -- OK\n");
4863     $CPAN::META->is_installed($self->{'build_dir'});
4864     return $self->{'install'} = "YES";
4865     } else {
4866     $self->{'install'} = "NO";
4867     $CPAN::Frontend->myprint(" $system -- NOT OK\n");
4868     if ($makeout =~ /permission/s && $> > 0) {
4869     $CPAN::Frontend->myprint(qq{ You may have to su }.
4870     qq{to root to install the package\n});
4871     }
4872     }
4873     delete $self->{force_update};
4874     }
4875    
4876     #-> sub CPAN::Distribution::dir ;
4877     sub dir {
4878     shift->{'build_dir'};
4879     }
4880    
4881     package CPAN::Bundle;
4882    
4883     sub look {
4884     my $self = shift;
4885     $CPAN::Frontend->myprint($self->as_string);
4886     }
4887    
4888     sub undelay {
4889     my $self = shift;
4890     delete $self->{later};
4891     for my $c ( $self->contains ) {
4892     my $obj = CPAN::Shell->expandany($c) or next;
4893     $obj->undelay;
4894     }
4895     }
4896    
4897     #-> sub CPAN::Bundle::color_cmd_tmps ;
4898     sub color_cmd_tmps {
4899     my($self) = shift;
4900     my($depth) = shift || 0;
4901     my($color) = shift || 0;
4902     my($ancestors) = shift || [];
4903     # a module needs to recurse to its cpan_file, a distribution needs
4904     # to recurse into its prereq_pms, a bundle needs to recurse into its modules
4905    
4906     return if exists $self->{incommandcolor}
4907     && $self->{incommandcolor}==$color;
4908     if ($depth>=100){
4909     $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
4910     }
4911     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
4912    
4913     for my $c ( $self->contains ) {
4914     my $obj = CPAN::Shell->expandany($c) or next;
4915     CPAN->debug("c[$c]obj[$obj]") if $CPAN::DEBUG;
4916     $obj->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
4917     }
4918     if ($color==0) {
4919     delete $self->{badtestcnt};
4920     }
4921     $self->{incommandcolor} = $color;
4922     }
4923    
4924     #-> sub CPAN::Bundle::as_string ;
4925     sub as_string {
4926     my($self) = @_;
4927     $self->contains;
4928     # following line must be "=", not "||=" because we have a moving target
4929     $self->{INST_VERSION} = $self->inst_version;
4930     return $self->SUPER::as_string;
4931     }
4932    
4933     #-> sub CPAN::Bundle::contains ;
4934     sub contains {
4935     my($self) = @_;
4936     my($inst_file) = $self->inst_file || "";
4937     my($id) = $self->id;
4938     $self->debug("inst_file[$inst_file]id[$id]") if $CPAN::DEBUG;
4939     unless ($inst_file) {
4940     # Try to get at it in the cpan directory
4941     $self->debug("no inst_file") if $CPAN::DEBUG;
4942     my $cpan_file;
4943     $CPAN::Frontend->mydie("I don't know a bundle with ID $id\n") unless
4944     $cpan_file = $self->cpan_file;
4945     if ($cpan_file eq "N/A") {
4946     $CPAN::Frontend->mydie("Bundle $id not found on disk and not on CPAN.
4947     Maybe stale symlink? Maybe removed during session? Giving up.\n");
4948     }
4949     my $dist = $CPAN::META->instance('CPAN::Distribution',
4950     $self->cpan_file);
4951     $dist->get;
4952     $self->debug($dist->as_string) if $CPAN::DEBUG;
4953     my($todir) = $CPAN::Config->{'cpan_home'};
4954     my(@me,$from,$to,$me);
4955     @me = split /::/, $self->id;
4956     $me[-1] .= ".pm";
4957     $me = File::Spec->catfile(@me);
4958     $from = $self->find_bundle_file($dist->{'build_dir'},$me);
4959     $to = File::Spec->catfile($todir,$me);
4960     File::Path::mkpath(File::Basename::dirname($to));
4961     File::Copy::copy($from, $to)
4962     or Carp::confess("Couldn't copy $from to $to: $!");
4963     $inst_file = $to;
4964     }
4965     my @result;
4966     my $fh = FileHandle->new;
4967     local $/ = "\n";
4968     open($fh,$inst_file) or die "Could not open '$inst_file': $!";
4969     my $in_cont = 0;
4970     $self->debug("inst_file[$inst_file]") if $CPAN::DEBUG;
4971     while (<$fh>) {
4972     $in_cont = m/^=(?!head1\s+CONTENTS)/ ? 0 :
4973     m/^=head1\s+CONTENTS/ ? 1 : $in_cont;
4974     next unless $in_cont;
4975     next if /^=/;
4976     s/\#.*//;
4977     next if /^\s+$/;
4978     chomp;
4979     push @result, (split " ", $_, 2)[0];
4980     }
4981     close $fh;
4982     delete $self->{STATUS};
4983     $self->{CONTAINS} = \@result;
4984     $self->debug("CONTAINS[@result]") if $CPAN::DEBUG;
4985     unless (@result) {
4986     $CPAN::Frontend->mywarn(qq{
4987     The bundle file "$inst_file" may be a broken
4988     bundlefile. It seems not to contain any bundle definition.
4989     Please check the file and if it is bogus, please delete it.
4990     Sorry for the inconvenience.
4991     });
4992     }
4993     @result;
4994     }
4995    
4996     #-> sub CPAN::Bundle::find_bundle_file
4997     sub find_bundle_file {
4998     my($self,$where,$what) = @_;
4999     $self->debug("where[$where]what[$what]") if $CPAN::DEBUG;
5000     ### The following two lines let CPAN.pm become Bundle/CPAN.pm :-(
5001     ### my $bu = File::Spec->catfile($where,$what);
5002     ### return $bu if -f $bu;
5003     my $manifest = File::Spec->catfile($where,"MANIFEST");
5004     unless (-f $manifest) {
5005     require ExtUtils::Manifest;
5006     my $cwd = CPAN::anycwd();
5007     chdir $where or $CPAN::Frontend->mydie(qq{Could not chdir to "$where": $!});
5008     ExtUtils::Manifest::mkmanifest();
5009     chdir $cwd or $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd": $!});
5010     }
5011     my $fh = FileHandle->new($manifest)
5012     or Carp::croak("Couldn't open $manifest: $!");
5013     local($/) = "\n";
5014     my $what2 = $what;
5015     if ($^O eq 'MacOS') {
5016     $what =~ s/^://;
5017     $what =~ tr|:|/|;
5018     $what2 =~ s/:Bundle://;
5019     $what2 =~ tr|:|/|;
5020     } else {
5021     $what2 =~ s|Bundle[/\\]||;
5022     }
5023     my $bu;
5024     while (<$fh>) {
5025     next if /^\s*\#/;
5026     my($file) = /(\S+)/;
5027     if ($file =~ m|\Q$what\E$|) {
5028     $bu = $file;
5029     # return File::Spec->catfile($where,$bu); # bad
5030     last;
5031     }
5032     # retry if she managed to
5033     # have no Bundle directory
5034     $bu = $file if $file =~ m|\Q$what2\E$|;
5035     }
5036     $bu =~ tr|/|:| if $^O eq 'MacOS';
5037     return File::Spec->catfile($where, $bu) if $bu;
5038     Carp::croak("Couldn't find a Bundle file in $where");
5039     }
5040    
5041     # needs to work quite differently from Module::inst_file because of
5042     # cpan_home/Bundle/ directory and the possibility that we have
5043     # shadowing effect. As it makes no sense to take the first in @INC for
5044     # Bundles, we parse them all for $VERSION and take the newest.
5045    
5046     #-> sub CPAN::Bundle::inst_file ;
5047     sub inst_file {
5048     my($self) = @_;
5049     my($inst_file);
5050     my(@me);
5051     @me = split /::/, $self->id;
5052     $me[-1] .= ".pm";
5053     my($incdir,$bestv);
5054     foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
5055     my $bfile = File::Spec->catfile($incdir, @me);
5056     CPAN->debug("bfile[$bfile]") if $CPAN::DEBUG;
5057     next unless -f $bfile;
5058     my $foundv = MM->parse_version($bfile);
5059     if (!$bestv || CPAN::Version->vgt($foundv,$bestv)) {
5060     $self->{INST_FILE} = $bfile;
5061     $self->{INST_VERSION} = $bestv = $foundv;
5062     }
5063     }
5064     $self->{INST_FILE};
5065     }
5066    
5067     #-> sub CPAN::Bundle::inst_version ;
5068     sub inst_version {
5069     my($self) = @_;
5070     $self->inst_file; # finds INST_VERSION as side effect
5071     $self->{INST_VERSION};
5072     }
5073    
5074     #-> sub CPAN::Bundle::rematein ;
5075     sub rematein {
5076     my($self,$meth) = @_;
5077     $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG;
5078     my($id) = $self->id;
5079     Carp::croak "Can't $meth $id, don't have an associated bundle file. :-(\n"
5080     unless $self->inst_file || $self->cpan_file;
5081     my($s,%fail);
5082     for $s ($self->contains) {
5083     my($type) = $s =~ m|/| ? 'CPAN::Distribution' :
5084     $s =~ m|^Bundle::| ? 'CPAN::Bundle' : 'CPAN::Module';
5085     if ($type eq 'CPAN::Distribution') {
5086     $CPAN::Frontend->mywarn(qq{
5087     The Bundle }.$self->id.qq{ contains
5088     explicitly a file $s.
5089     });
5090     sleep 3;
5091     }
5092     # possibly noisy action:
5093     $self->debug("type[$type] s[$s]") if $CPAN::DEBUG;
5094     my $obj = $CPAN::META->instance($type,$s);
5095     $obj->$meth();
5096     if ($obj->isa(CPAN::Bundle)
5097     &&
5098     exists $obj->{install_failed}
5099     &&
5100     ref($obj->{install_failed}) eq "HASH"
5101     ) {
5102     for (keys %{$obj->{install_failed}}) {
5103     $self->{install_failed}{$_} = undef; # propagate faiure up
5104     # to me in a
5105     # recursive call
5106     $fail{$s} = 1; # the bundle itself may have succeeded but
5107     # not all children
5108     }
5109     } else {
5110     my $success;
5111     $success = $obj->can("uptodate") ? $obj->uptodate : 0;
5112     $success ||= $obj->{'install'} && $obj->{'install'} eq "YES";
5113     if ($success) {
5114     delete $self->{install_failed}{$s};
5115     } else {
5116     $fail{$s} = 1;
5117     }
5118     }
5119     }
5120    
5121     # recap with less noise
5122     if ( $meth eq "install" ) {
5123     if (%fail) {
5124     require Text::Wrap;
5125     my $raw = sprintf(qq{Bundle summary:
5126     The following items in bundle %s had installation problems:},
5127     $self->id
5128     );
5129     $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
5130     $CPAN::Frontend->myprint("\n");
5131     my $paragraph = "";
5132     my %reported;
5133     for $s ($self->contains) {
5134     if ($fail{$s}){
5135     $paragraph .= "$s ";
5136     $self->{install_failed}{$s} = undef;
5137     $reported{$s} = undef;
5138     }
5139     }
5140     my $report_propagated;
5141     for $s (sort keys %{$self->{install_failed}}) {
5142     next if exists $reported{$s};
5143     $paragraph .= "and the following items had problems
5144     during recursive bundle calls: " unless $report_propagated++;
5145     $paragraph .= "$s ";
5146     }
5147     $CPAN::Frontend->myprint(Text::Wrap::fill(" "," ",$paragraph));
5148     $CPAN::Frontend->myprint("\n");
5149     } else {
5150     $self->{'install'} = 'YES';
5151     }
5152     }
5153     }
5154    
5155     #sub CPAN::Bundle::xs_file
5156     sub xs_file {
5157     # If a bundle contains another that contains an xs_file we have
5158     # here, we just don't bother I suppose
5159     return 0;
5160     }
5161    
5162     #-> sub CPAN::Bundle::force ;
5163     sub force { shift->rematein('force',@_); }
5164     #-> sub CPAN::Bundle::get ;
5165     sub get { shift->rematein('get',@_); }
5166     #-> sub CPAN::Bundle::make ;
5167     sub make { shift->rematein('make',@_); }
5168     #-> sub CPAN::Bundle::test ;
5169     sub test {
5170     my $self = shift;
5171     $self->{badtestcnt} ||= 0;
5172     $self->rematein('test',@_);
5173     }
5174     #-> sub CPAN::Bundle::install ;
5175     sub install {
5176     my $self = shift;
5177     $self->rematein('install',@_);
5178     }
5179     #-> sub CPAN::Bundle::clean ;
5180     sub clean { shift->rematein('clean',@_); }
5181    
5182     #-> sub CPAN::Bundle::uptodate ;
5183     sub uptodate {
5184     my($self) = @_;
5185     return 0 unless $self->SUPER::uptodate; # we mut have the current Bundle def
5186     my $c;
5187     foreach $c ($self->contains) {
5188     my $obj = CPAN::Shell->expandany($c);
5189     return 0 unless $obj->uptodate;
5190     }
5191     return 1;
5192     }
5193    
5194     #-> sub CPAN::Bundle::readme ;
5195     sub readme {
5196     my($self) = @_;
5197     my($file) = $self->cpan_file or $CPAN::Frontend->myprint(qq{
5198     No File found for bundle } . $self->id . qq{\n}), return;
5199     $self->debug("self[$self] file[$file]") if $CPAN::DEBUG;
5200     $CPAN::META->instance('CPAN::Distribution',$file)->readme;
5201     }
5202    
5203     package CPAN::Module;
5204    
5205     # Accessors
5206     # sub CPAN::Module::userid
5207     sub userid {
5208     my $self = shift;
5209     return unless exists $self->{RO}; # should never happen
5210     return $self->{RO}{userid} || $self->{RO}{CPAN_USERID};
5211     }
5212     # sub CPAN::Module::description
5213     sub description { shift->{RO}{description} }
5214    
5215     sub undelay {
5216     my $self = shift;
5217     delete $self->{later};
5218     if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
5219     $dist->undelay;
5220     }
5221     }
5222    
5223     #-> sub CPAN::Module::color_cmd_tmps ;
5224     sub color_cmd_tmps {
5225     my($self) = shift;
5226     my($depth) = shift || 0;
5227     my($color) = shift || 0;
5228     my($ancestors) = shift || [];
5229     # a module needs to recurse to its cpan_file
5230    
5231     return if exists $self->{incommandcolor}
5232     && $self->{incommandcolor}==$color;
5233     if ($depth>=100){
5234     $CPAN::Frontend->mydie(CPAN::Exception::RecursiveDependency->new($ancestors));
5235     }
5236     # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
5237    
5238     if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
5239     $dist->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
5240     }
5241     if ($color==0) {
5242     delete $self->{badtestcnt};
5243     }
5244     $self->{incommandcolor} = $color;
5245     }
5246    
5247     #-> sub CPAN::Module::as_glimpse ;
5248     sub as_glimpse {
5249     my($self) = @_;
5250     my(@m);
5251     my $class = ref($self);
5252     $class =~ s/^CPAN:://;
5253     my $color_on = "";
5254     my $color_off = "";
5255     if (
5256     $CPAN::Shell::COLOR_REGISTERED
5257     &&
5258     $CPAN::META->has_inst("Term::ANSIColor")
5259     &&
5260     $self->{RO}{description}
5261     ) {
5262     $color_on = Term::ANSIColor::color("green");
5263     $color_off = Term::ANSIColor::color("reset");
5264     }
5265     push @m, sprintf("%-15s %s%-15s%s (%s)\n",
5266     $class,
5267     $color_on,
5268     $self->id,
5269     $color_off,
5270     $self->cpan_file);
5271     join "", @m;
5272     }
5273    
5274     #-> sub CPAN::Module::as_string ;
5275     sub as_string {
5276     my($self) = @_;
5277     my(@m);
5278     CPAN->debug("$self entering as_string") if $CPAN::DEBUG;
5279     my $class = ref($self);
5280     $class =~ s/^CPAN:://;
5281     local($^W) = 0;
5282     push @m, $class, " id = $self->{ID}\n";
5283     my $sprintf = " %-12s %s\n";
5284     push @m, sprintf($sprintf, 'DESCRIPTION', $self->description)
5285     if $self->description;
5286     my $sprintf2 = " %-12s %s (%s)\n";
5287     my($userid);
5288     $userid = $self->userid;
5289     if ( $userid ){
5290     my $author;
5291     if ($author = CPAN::Shell->expand('Author',$userid)) {
5292     my $email = "";
5293     my $m; # old perls
5294     if ($m = $author->email) {
5295     $email = " <$m>";
5296     }
5297     push @m, sprintf(
5298     $sprintf2,
5299     'CPAN_USERID',
5300     $userid,
5301     $author->fullname . $email
5302     );
5303     }
5304     }
5305     push @m, sprintf($sprintf, 'CPAN_VERSION', $self->cpan_version)
5306     if $self->cpan_version;
5307     push @m, sprintf($sprintf, 'CPAN_FILE', $self->cpan_file)
5308     if $self->cpan_file;
5309     my $sprintf3 = " %-12s %1s%1s%1s%1s (%s,%s,%s,%s)\n";
5310     my(%statd,%stats,%statl,%stati);
5311     @statd{qw,? i c a b R M S,} = qw,unknown idea
5312     pre-alpha alpha beta released mature standard,;
5313     @stats{qw,? m d u n a,} = qw,unknown mailing-list
5314     developer comp.lang.perl.* none abandoned,;
5315     @statl{qw,? p c + o h,} = qw,unknown perl C C++ other hybrid,;
5316     @stati{qw,? f r O h,} = qw,unknown functions
5317     references+ties object-oriented hybrid,;
5318     $statd{' '} = 'unknown';
5319     $stats{' '} = 'unknown';
5320     $statl{' '} = 'unknown';
5321     $stati{' '} = 'unknown';
5322     push @m, sprintf(
5323     $sprintf3,
5324     'DSLI_STATUS',
5325     $self->{RO}{statd},
5326     $self->{RO}{stats},
5327     $self->{RO}{statl},
5328     $self->{RO}{stati},
5329     $statd{$self->{RO}{statd}},
5330     $stats{$self->{RO}{stats}},
5331     $statl{$self->{RO}{statl}},
5332     $stati{$self->{RO}{stati}}
5333     ) if $self->{RO}{statd};
5334     my $local_file = $self->inst_file;
5335     unless ($self->{MANPAGE}) {
5336     if ($local_file) {
5337     $self->{MANPAGE} = $self->manpage_headline($local_file);
5338     } else {
5339     # If we have already untarred it, we should look there
5340     my $dist = $CPAN::META->instance('CPAN::Distribution',
5341     $self->cpan_file);
5342     # warn "dist[$dist]";
5343     # mff=manifest file; mfh=manifest handle
5344     my($mff,$mfh);
5345     if (
5346     $dist->{build_dir}
5347     and
5348     (-f ($mff = File::Spec->catfile($dist->{build_dir}, "MANIFEST")))
5349     and
5350     $mfh = FileHandle->new($mff)
5351     ) {
5352     CPAN->debug("mff[$mff]") if $CPAN::DEBUG;
5353     my $lfre = $self->id; # local file RE
5354     $lfre =~ s/::/./g;
5355     $lfre .= "\\.pm\$";
5356     my($lfl); # local file file
5357     local $/ = "\n";
5358     my(@mflines) = <$mfh>;
5359     for (@mflines) {
5360     s/^\s+//;
5361     s/\s.*//s;
5362     }
5363     while (length($lfre)>5 and !$lfl) {
5364     ($lfl) = grep /$lfre/, @mflines;
5365     CPAN->debug("lfl[$lfl]lfre[$lfre]") if $CPAN::DEBUG;
5366     $lfre =~ s/.+?\.//;
5367     }
5368     $lfl =~ s/\s.*//; # remove comments
5369     $lfl =~ s/\s+//g; # chomp would maybe be too system-specific
5370     my $lfl_abs = File::Spec->catfile($dist->{build_dir},$lfl);
5371     # warn "lfl_abs[$lfl_abs]";
5372     if (-f $lfl_abs) {
5373     $self->{MANPAGE} = $self->manpage_headline($lfl_abs);
5374     }
5375     }
5376     }
5377     }
5378     my($item);
5379     for $item (qw/MANPAGE/) {
5380     push @m, sprintf($sprintf, $item, $self->{$item})
5381     if exists $self->{$item};
5382     }
5383     for $item (qw/CONTAINS/) {
5384     push @m, sprintf($sprintf, $item, join(" ",@{$self->{$item}}))
5385     if exists $self->{$item} && @{$self->{$item}};
5386     }
5387     push @m, sprintf($sprintf, 'INST_FILE',
5388     $local_file || "(not installed)");
5389     push @m, sprintf($sprintf, 'INST_VERSION',
5390     $self->inst_version) if $local_file;
5391     join "", @m, "\n";
5392     }
5393    
5394     sub manpage_headline {
5395     my($self,$local_file) = @_;
5396     my(@local_file) = $local_file;
5397     $local_file =~ s/\.pm(?!\n)\Z/.pod/;
5398     push @local_file, $local_file;
5399     my(@result,$locf);
5400     for $locf (@local_file) {
5401     next unless -f $locf;
5402     my $fh = FileHandle->new($locf)
5403     or $Carp::Frontend->mydie("Couldn't open $locf: $!");
5404     my $inpod = 0;
5405     local $/ = "\n";
5406     while (<$fh>) {
5407     $inpod = m/^=(?!head1\s+NAME\s*$)/ ? 0 :
5408     m/^=head1\s+NAME\s*$/ ? 1 : $inpod;
5409     next unless $inpod;
5410     next if /^=/;
5411     next if /^\s+$/;
5412     chomp;
5413     push @result, $_;
5414     }
5415     close $fh;
5416     last if @result;
5417     }
5418     join " ", @result;
5419     }
5420    
5421     #-> sub CPAN::Module::cpan_file ;
5422     # Note: also inherited by CPAN::Bundle
5423     sub cpan_file {
5424     my $self = shift;
5425     CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
5426     unless (defined $self->{RO}{CPAN_FILE}) {
5427     CPAN::Index->reload;
5428     }
5429     if (exists $self->{RO}{CPAN_FILE} && defined $self->{RO}{CPAN_FILE}){
5430     return $self->{RO}{CPAN_FILE};
5431     } else {
5432     my $userid = $self->userid;
5433     if ( $userid ) {
5434     if ($CPAN::META->exists("CPAN::Author",$userid)) {
5435     my $author = $CPAN::META->instance("CPAN::Author",
5436     $userid);
5437     my $fullname = $author->fullname;
5438     my $email = $author->email;
5439     unless (defined $fullname && defined $email) {
5440     return sprintf("Contact Author %s",
5441     $userid,
5442     );
5443     }
5444     return "Contact Author $fullname <$email>";
5445     } else {
5446     return "Contact Author $userid (Email address not available)";
5447     }
5448     } else {
5449     return "N/A";
5450     }
5451     }
5452     }
5453    
5454     #-> sub CPAN::Module::cpan_version ;
5455     sub cpan_version {
5456     my $self = shift;
5457    
5458     $self->{RO}{CPAN_VERSION} = 'undef'
5459     unless defined $self->{RO}{CPAN_VERSION};
5460     # I believe this is always a bug in the index and should be reported
5461     # as such, but usually I find out such an error and do not want to
5462     # provoke too many bugreports
5463    
5464     $self->{RO}{CPAN_VERSION};
5465     }
5466    
5467     #-> sub CPAN::Module::force ;
5468     sub force {
5469     my($self) = @_;
5470     $self->{'force_update'}++;
5471     }
5472    
5473     #-> sub CPAN::Module::rematein ;
5474     sub rematein {
5475     my($self,$meth) = @_;
5476     $CPAN::Frontend->myprint(sprintf("Running %s for module %s\n",
5477     $meth,
5478     $self->id));
5479     my $cpan_file = $self->cpan_file;
5480     if ($cpan_file eq "N/A" || $cpan_file =~ /^Contact Author/){
5481     $CPAN::Frontend->mywarn(sprintf qq{
5482     The module %s isn\'t available on CPAN.
5483    
5484     Either the module has not yet been uploaded to CPAN, or it is
5485     temporary unavailable. Please contact the author to find out
5486     more about the status. Try 'i %s'.
5487     },
5488     $self->id,
5489     $self->id,
5490     );
5491     return;
5492     }
5493     my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
5494     $pack->called_for($self->id);
5495     $pack->force($meth) if exists $self->{'force_update'};
5496     $pack->$meth();
5497     $pack->unforce if $pack->can("unforce") && exists $self->{'force_update'};
5498     delete $self->{'force_update'};
5499     }
5500    
5501     #-> sub CPAN::Module::readme ;
5502     sub readme { shift->rematein('readme') }
5503     #-> sub CPAN::Module::look ;
5504     sub look { shift->rematein('look') }
5505     #-> sub CPAN::Module::cvs_import ;
5506     sub cvs_import { shift->rematein('cvs_import') }
5507     #-> sub CPAN::Module::get ;
5508     sub get { shift->rematein('get',@_); }
5509     #-> sub CPAN::Module::make ;
5510     sub make {
5511     my $self = shift;
5512     $self->rematein('make');
5513     }
5514     #-> sub CPAN::Module::test ;
5515     sub test {
5516     my $self = shift;
5517     $self->{badtestcnt} ||= 0;
5518     $self->rematein('test',@_);
5519     }
5520     #-> sub CPAN::Module::uptodate ;
5521     sub uptodate {
5522     my($self) = @_;
5523     my($latest) = $self->cpan_version;
5524     $latest ||= 0;
5525     my($inst_file) = $self->inst_file;
5526     my($have) = 0;
5527     if (defined $inst_file) {
5528     $have = $self->inst_version;
5529     }
5530     local($^W)=0;
5531     if ($inst_file
5532     &&
5533     ! CPAN::Version->vgt($latest, $have)
5534     ) {
5535     CPAN->debug("returning uptodate. inst_file[$inst_file] ".
5536     "latest[$latest] have[$have]") if $CPAN::DEBUG;
5537     return 1;
5538     }
5539     return;
5540     }
5541     #-> sub CPAN::Module::install ;
5542     sub install {
5543     my($self) = @_;
5544     my($doit) = 0;
5545     if ($self->uptodate
5546     &&
5547     not exists $self->{'force_update'}
5548     ) {
5549     $CPAN::Frontend->myprint( $self->id. " is up to date.\n");
5550     } else {
5551     $doit = 1;
5552     }
5553     if ($self->{RO}{stats} && $self->{RO}{stats} eq "a") {
5554     $CPAN::Frontend->mywarn(qq{
5555     \n\n\n ***WARNING***
5556     The module $self->{ID} has no active maintainer.\n\n\n
5557     });
5558     sleep 5;
5559     }
5560     $self->rematein('install') if $doit;
5561     }
5562     #-> sub CPAN::Module::clean ;
5563     sub clean { shift->rematein('clean') }
5564    
5565     #-> sub CPAN::Module::inst_file ;
5566     sub inst_file {
5567     my($self) = @_;
5568     my($dir,@packpath);
5569     @packpath = split /::/, $self->{ID};
5570     $packpath[-1] .= ".pm";
5571     foreach $dir (@INC) {
5572     my $pmfile = File::Spec->catfile($dir,@packpath);
5573     if (-f $pmfile){
5574     return $pmfile;
5575     }
5576     }
5577     return;
5578     }
5579    
5580     #-> sub CPAN::Module::xs_file ;
5581     sub xs_file {
5582     my($self) = @_;
5583     my($dir,@packpath);
5584     @packpath = split /::/, $self->{ID};
5585     push @packpath, $packpath[-1];
5586     $packpath[-1] .= "." . $Config::Config{'dlext'};
5587     foreach $dir (@INC) {
5588     my $xsfile = File::Spec->catfile($dir,'auto',@packpath);
5589     if (-f $xsfile){
5590     return $xsfile;
5591     }
5592     }
5593     return;
5594     }
5595    
5596     #-> sub CPAN::Module::inst_version ;
5597     sub inst_version {
5598     my($self) = @_;
5599     my $parsefile = $self->inst_file or return;
5600     local($^W) = 0 if $] < 5.00303 && $ExtUtils::MakeMaker::VERSION < 5.38;
5601     my $have;
5602    
5603     # there was a bug in 5.6.0 that let lots of unini warnings out of
5604     # parse_version. Fixed shortly after 5.6.0 by PMQS. We can remove
5605     # the following workaround after 5.6.1 is out.
5606     local($SIG{__WARN__}) = sub { my $w = shift;
5607     return if $w =~ /uninitialized/i;
5608     warn $w;
5609     };
5610    
5611     $have = MM->parse_version($parsefile) || "undef";
5612     $have =~ s/^ //; # since the %vd hack these two lines here are needed
5613     $have =~ s/ $//; # trailing whitespace happens all the time
5614    
5615     # My thoughts about why %vd processing should happen here
5616    
5617     # Alt1 maintain it as string with leading v:
5618     # read index files do nothing
5619     # compare it use utility for compare
5620     # print it do nothing
5621    
5622     # Alt2 maintain it as what it is
5623     # read index files convert
5624     # compare it use utility because there's still a ">" vs "gt" issue
5625     # print it use CPAN::Version for print
5626    
5627     # Seems cleaner to hold it in memory as a string starting with a "v"
5628    
5629     # If the author of this module made a mistake and wrote a quoted
5630     # "v1.13" instead of v1.13, we simply leave it at that with the
5631     # effect that *we* will treat it like a v-tring while the rest of
5632     # perl won't. Seems sensible when we consider that any action we
5633     # could take now would just add complexity.
5634    
5635     $have = CPAN::Version->readable($have);
5636    
5637     $have =~ s/\s*//g; # stringify to float around floating point issues
5638     $have; # no stringify needed, \s* above matches always
5639     }
5640    
5641     package CPAN::Tarzip;
5642    
5643     # CPAN::Tarzip::gzip
5644     sub gzip {
5645     my($class,$read,$write) = @_;
5646     if ($CPAN::META->has_inst("Compress::Zlib")) {
5647     my($buffer,$fhw);
5648     $fhw = FileHandle->new($read)
5649     or $CPAN::Frontend->mydie("Could not open $read: $!");
5650     my $gz = Compress::Zlib::gzopen($write, "wb")
5651     or $CPAN::Frontend->mydie("Cannot gzopen $write: $!\n");
5652     $gz->gzwrite($buffer)
5653     while read($fhw,$buffer,4096) > 0 ;
5654     $gz->gzclose() ;
5655     $fhw->close;
5656     return 1;
5657     } else {
5658     system("$CPAN::Config->{gzip} -c $read > $write")==0;
5659     }
5660     }
5661    
5662    
5663     # CPAN::Tarzip::gunzip
5664     sub gunzip {
5665     my($class,$read,$write) = @_;
5666     if ($CPAN::META->has_inst("Compress::Zlib")) {
5667     my($buffer,$fhw);
5668     $fhw = FileHandle->new(">$write")
5669     or $CPAN::Frontend->mydie("Could not open >$write: $!");
5670     my $gz = Compress::Zlib::gzopen($read, "rb")
5671     or $CPAN::Frontend->mydie("Cannot gzopen $read: $!\n");
5672     $fhw->print($buffer)
5673     while $gz->gzread($buffer) > 0 ;
5674     $CPAN::Frontend->mydie("Error reading from $read: $!\n")
5675     if $gz->gzerror != Compress::Zlib::Z_STREAM_END();
5676     $gz->gzclose() ;
5677     $fhw->close;
5678     return 1;
5679     } else {
5680     system("$CPAN::Config->{gzip} -dc $read > $write")==0;
5681     }
5682     }
5683    
5684    
5685     # CPAN::Tarzip::gtest
5686     sub gtest {
5687     my($class,$read) = @_;
5688     # After I had reread the documentation in zlib.h, I discovered that
5689     # uncompressed files do not lead to an gzerror (anymore?).
5690     if ( $CPAN::META->has_inst("Compress::Zlib") ) {
5691     my($buffer,$len);
5692     $len = 0;
5693     my $gz = Compress::Zlib::gzopen($read, "rb")
5694     or $CPAN::Frontend->mydie(sprintf("Cannot gzopen %s: %s\n",
5695     $read,
5696     $Compress::Zlib::gzerrno));
5697     while ($gz->gzread($buffer) > 0 ){
5698     $len += length($buffer);
5699     $buffer = "";
5700     }
5701     my $err = $gz->gzerror;
5702     my $success = ! $err || $err == Compress::Zlib::Z_STREAM_END();
5703     if ($len == -s $read){
5704     $success = 0;
5705     CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG;
5706     }
5707     $gz->gzclose();
5708     CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG;
5709     return $success;
5710     } else {
5711     return system("$CPAN::Config->{gzip} -dt $read")==0;
5712     }
5713     }
5714    
5715    
5716     # CPAN::Tarzip::TIEHANDLE
5717     sub TIEHANDLE {
5718     my($class,$file) = @_;
5719     my $ret;
5720     $class->debug("file[$file]");
5721     if ($CPAN::META->has_inst("Compress::Zlib")) {
5722     my $gz = Compress::Zlib::gzopen($file,"rb") or
5723     die "Could not gzopen $file";
5724     $ret = bless {GZ => $gz}, $class;
5725     } else {
5726     my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $file |";
5727     my $fh = FileHandle->new($pipe) or die "Could not pipe[$pipe]: $!";
5728     binmode $fh;
5729     $ret = bless {FH => $fh}, $class;
5730     }
5731     $ret;
5732     }
5733    
5734    
5735     # CPAN::Tarzip::READLINE
5736     sub READLINE {
5737     my($self) = @_;
5738     if (exists $self->{GZ}) {
5739     my $gz = $self->{GZ};
5740     my($line,$bytesread);
5741     $bytesread = $gz->gzreadline($line);
5742     return undef if $bytesread <= 0;
5743     return $line;
5744     } else {
5745     my $fh = $self->{FH};
5746     return scalar <$fh>;
5747     }
5748     }
5749    
5750    
5751     # CPAN::Tarzip::READ
5752     sub READ {
5753     my($self,$ref,$length,$offset) = @_;
5754     die "read with offset not implemented" if defined $offset;
5755     if (exists $self->{GZ}) {
5756     my $gz = $self->{GZ};
5757     my $byteread = $gz->gzread($$ref,$length);# 30eaf79e8b446ef52464b5422da328a8
5758     return $byteread;
5759     } else {
5760     my $fh = $self->{FH};
5761     return read($fh,$$ref,$length);
5762     }
5763     }
5764    
5765    
5766     # CPAN::Tarzip::DESTROY
5767     sub DESTROY {
5768     my($self) = @_;
5769     if (exists $self->{GZ}) {
5770     my $gz = $self->{GZ};
5771     $gz->gzclose() if defined $gz; # hard to say if it is allowed
5772     # to be undef ever. AK, 2000-09
5773     } else {
5774     my $fh = $self->{FH};
5775     $fh->close if defined $fh;
5776     }
5777     undef $self;
5778     }
5779    
5780    
5781     # CPAN::Tarzip::untar
5782     sub untar {
5783     my($class,$file) = @_;
5784     my($prefer) = 0;
5785    
5786     if (0) { # makes changing order easier
5787     } elsif ($BUGHUNTING){
5788     $prefer=2;
5789     } elsif (MM->maybe_command($CPAN::Config->{gzip})
5790     &&
5791     MM->maybe_command($CPAN::Config->{'tar'})) {
5792     # should be default until Archive::Tar is fixed
5793     $prefer = 1;
5794     } elsif (
5795     $CPAN::META->has_inst("Archive::Tar")
5796     &&
5797     $CPAN::META->has_inst("Compress::Zlib") ) {
5798     $prefer = 2;
5799     } else {
5800     $CPAN::Frontend->mydie(qq{
5801     CPAN.pm needs either both external programs tar and gzip installed or
5802     both the modules Archive::Tar and Compress::Zlib. Neither prerequisite
5803     is available. Can\'t continue.
5804     });
5805     }
5806     if ($prefer==1) { # 1 => external gzip+tar
5807     my($system);
5808     my $is_compressed = $class->gtest($file);
5809     if ($is_compressed) {
5810     $system = "$CPAN::Config->{gzip} --decompress --stdout " .
5811     "< $file | $CPAN::Config->{tar} xvf -";
5812     } else {
5813     $system = "$CPAN::Config->{tar} xvf $file";
5814     }
5815     if (system($system) != 0) {
5816     # people find the most curious tar binaries that cannot handle
5817     # pipes
5818     if ($is_compressed) {
5819     (my $ungzf = $file) =~ s/\.gz(?!\n)\Z//;
5820     if (CPAN::Tarzip->gunzip($file, $ungzf)) {
5821     $CPAN::Frontend->myprint(qq{Uncompressed $file successfully\n});
5822     } else {
5823     $CPAN::Frontend->mydie(qq{Couldn\'t uncompress $file\n});
5824     }
5825     $file = $ungzf;
5826     }
5827     $system = "$CPAN::Config->{tar} xvf $file";
5828     $CPAN::Frontend->myprint(qq{Using Tar:$system:\n});
5829     if (system($system)==0) {
5830     $CPAN::Frontend->myprint(qq{Untarred $file successfully\n});
5831     } else {
5832     $CPAN::Frontend->mydie(qq{Couldn\'t untar $file\n});
5833     }
5834     return 1;
5835     } else {
5836     return 1;
5837     }
5838     } elsif ($prefer==2) { # 2 => modules
5839     my $tar = Archive::Tar->new($file,1);
5840     my $af; # archive file
5841     my @af;
5842     if ($BUGHUNTING) {
5843     # RCS 1.337 had this code, it turned out unacceptable slow but
5844     # it revealed a bug in Archive::Tar. Code is only here to hunt
5845     # the bug again. It should never be enabled in published code.
5846     # GDGraph3d-0.53 was an interesting case according to Larry
5847     # Virden.
5848     warn(">>>Bughunting code enabled<<< " x 20);
5849     for $af ($tar->list_files) {
5850     if ($af =~ m!^(/|\.\./)!) {
5851     $CPAN::Frontend->mydie("ALERT: Archive contains ".
5852     "illegal member [$af]");
5853     }
5854     $CPAN::Frontend->myprint("$af\n");
5855     $tar->extract($af); # slow but effective for finding the bug
5856     return if $CPAN::Signal;
5857     }
5858     } else {
5859     for $af ($tar->list_files) {
5860     if ($af =~ m!^(/|\.\./)!) {
5861     $CPAN::Frontend->mydie("ALERT: Archive contains ".
5862     "illegal member [$af]");
5863     }
5864     $CPAN::Frontend->myprint("$af\n");
5865     push @af, $af;
5866     return if $CPAN::Signal;
5867     }
5868     $tar->extract(@af);
5869     }
5870    
5871     Mac::BuildTools::convert_files([$tar->list_files], 1)
5872     if ($^O eq 'MacOS');
5873    
5874     return 1;
5875     }
5876     }
5877    
5878     sub unzip {
5879     my($class,$file) = @_;
5880     if ($CPAN::META->has_inst("Archive::Zip")) {
5881     # blueprint of the code from Archive::Zip::Tree::extractTree();
5882     my $zip = Archive::Zip->new();
5883     my $status;
5884     $status = $zip->read($file);
5885     die "Read of file[$file] failed\n" if $status != Archive::Zip::AZ_OK();
5886     $CPAN::META->debug("Successfully read file[$file]") if $CPAN::DEBUG;
5887     my @members = $zip->members();
5888     for my $member ( @members ) {
5889     my $af = $member->fileName();
5890     if ($af =~ m!^(/|\.\./)!) {
5891     $CPAN::Frontend->mydie("ALERT: Archive contains ".
5892     "illegal member [$af]");
5893     }
5894     my $status = $member->extractToFileNamed( $af );
5895     $CPAN::META->debug("af[$af]status[$status]") if $CPAN::DEBUG;
5896     die "Extracting of file[$af] from zipfile[$file] failed\n" if
5897     $status != Archive::Zip::AZ_OK();
5898     return if $CPAN::Signal;
5899     }
5900     return 1;
5901     } else {
5902     my $unzip = $CPAN::Config->{unzip} or
5903     $CPAN::Frontend->mydie("Cannot unzip, no unzip program available");
5904     my @system = ($unzip, $file);
5905     return system(@system) == 0;
5906     }
5907     }
5908    
5909    
5910     package CPAN::Version;
5911     # CPAN::Version::vcmp courtesy Jost Krieger
5912     sub vcmp {
5913     my($self,$l,$r) = @_;
5914     local($^W) = 0;
5915     CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;
5916    
5917     return 0 if $l eq $r; # short circuit for quicker success
5918    
5919     if ($l=~/^v/ <=> $r=~/^v/) {
5920     for ($l,$r) {
5921     next if /^v/;
5922     $_ = $self->float2vv($_);
5923     }
5924     }
5925    
5926     return
5927     ($l ne "undef") <=> ($r ne "undef") ||
5928     ($] >= 5.006 &&
5929     $l =~ /^v/ &&
5930     $r =~ /^v/ &&
5931     $self->vstring($l) cmp $self->vstring($r)) ||
5932     $l <=> $r ||
5933     $l cmp $r;
5934     }
5935    
5936     sub vgt {
5937     my($self,$l,$r) = @_;
5938     $self->vcmp($l,$r) > 0;
5939     }
5940    
5941     sub vstring {
5942     my($self,$n) = @_;
5943     $n =~ s/^v// or die "CPAN::Version::vstring() called with invalid arg [$n]";
5944     pack "U*", split /\./, $n;
5945     }
5946    
5947     # vv => visible vstring
5948     sub float2vv {
5949     my($self,$n) = @_;
5950     my($rev) = int($n);
5951     $rev ||= 0;
5952     my($mantissa) = $n =~ /\.(\d{1,12})/; # limit to 12 digits to limit
5953     # architecture influence
5954     $mantissa ||= 0;
5955     $mantissa .= "0" while length($mantissa)%3;
5956     my $ret = "v" . $rev;
5957     while ($mantissa) {
5958     $mantissa =~ s/(\d{1,3})// or
5959     die "Panic: length>0 but not a digit? mantissa[$mantissa]";
5960     $ret .= ".".int($1);
5961     }
5962     # warn "n[$n]ret[$ret]";
5963     $ret;
5964     }
5965    
5966     sub readable {
5967     my($self,$n) = @_;
5968     $n =~ /^([\w\-\+\.]+)/;
5969    
5970     return $1 if defined $1 && length($1)>0;
5971     # if the first user reaches version v43, he will be treated as "+".
5972     # We'll have to decide about a new rule here then, depending on what
5973     # will be the prevailing versioning behavior then.
5974    
5975     if ($] < 5.006) { # or whenever v-strings were introduced
5976     # we get them wrong anyway, whatever we do, because 5.005 will
5977     # have already interpreted 0.2.4 to be "0.24". So even if he
5978     # indexer sends us something like "v0.2.4" we compare wrongly.
5979    
5980     # And if they say v1.2, then the old perl takes it as "v12"
5981    
5982     $CPAN::Frontend->mywarn("Suspicious version string seen [$n]\n");
5983     return $n;
5984     }
5985     my $better = sprintf "v%vd", $n;
5986     CPAN->debug("n[$n] better[$better]") if $CPAN::DEBUG;
5987     return $better;
5988     }
5989    
5990     package CPAN;
5991    
5992     1;
5993    
5994     __END__
5995    
5996     =head1 NAME
5997    
5998     CPAN - query, download and build perl modules from CPAN sites
5999    
6000     =head1 SYNOPSIS
6001    
6002     Interactive mode:
6003    
6004     perl -MCPAN -e shell;
6005    
6006     Batch mode:
6007    
6008     use CPAN;
6009    
6010     autobundle, clean, install, make, recompile, test
6011    
6012     =head1 STATUS
6013    
6014     This module will eventually be replaced by CPANPLUS. CPANPLUS is kind
6015     of a modern rewrite from ground up with greater extensibility and more
6016     features but no full compatibility. If you're new to CPAN.pm, you
6017     probably should investigate if CPANPLUS is the better choice for you.
6018     If you're already used to CPAN.pm you're welcome to continue using it,
6019     if you accept that its development is mostly (though not completely)
6020     stalled.
6021    
6022     =head1 DESCRIPTION
6023    
6024     The CPAN module is designed to automate the make and install of perl
6025     modules and extensions. It includes some primitive searching capabilities and
6026     knows how to use Net::FTP or LWP (or lynx or an external ftp client)
6027     to fetch the raw data from the net.
6028    
6029     Modules are fetched from one or more of the mirrored CPAN
6030     (Comprehensive Perl Archive Network) sites and unpacked in a dedicated
6031     directory.
6032    
6033     The CPAN module also supports the concept of named and versioned
6034     I<bundles> of modules. Bundles simplify the handling of sets of
6035     related modules. See Bundles below.
6036    
6037     The package contains a session manager and a cache manager. There is
6038     no status retained between sessions. The session manager keeps track
6039     of what has been fetched, built and installed in the current
6040     session. The cache manager keeps track of the disk space occupied by
6041     the make processes and deletes excess space according to a simple FIFO
6042     mechanism.
6043    
6044     For extended searching capabilities there's a plugin for CPAN available,
6045     L<C<CPAN::WAIT>|CPAN::WAIT>. C<CPAN::WAIT> is a full-text search engine
6046     that indexes all documents available in CPAN authors directories. If
6047     C<CPAN::WAIT> is installed on your system, the interactive shell of
6048     CPAN.pm will enable the C<wq>, C<wr>, C<wd>, C<wl>, and C<wh> commands
6049     which send queries to the WAIT server that has been configured for your
6050     installation.
6051    
6052     All other methods provided are accessible in a programmer style and in an
6053     interactive shell style.
6054    
6055     =head2 Interactive Mode
6056    
6057     The interactive mode is entered by running
6058    
6059     perl -MCPAN -e shell
6060    
6061     which puts you into a readline interface. You will have the most fun if
6062     you install Term::ReadKey and Term::ReadLine to enjoy both history and
6063     command completion.
6064    
6065     Once you are on the command line, type 'h' and the rest should be
6066     self-explanatory.
6067    
6068     The function call C<shell> takes two optional arguments, one is the
6069     prompt, the second is the default initial command line (the latter
6070     only works if a real ReadLine interface module is installed).
6071    
6072     The most common uses of the interactive modes are
6073    
6074     =over 2
6075    
6076     =item Searching for authors, bundles, distribution files and modules
6077    
6078     There are corresponding one-letter commands C<a>, C<b>, C<d>, and C<m>
6079     for each of the four categories and another, C<i> for any of the
6080     mentioned four. Each of the four entities is implemented as a class
6081     with slightly differing methods for displaying an object.
6082    
6083     Arguments you pass to these commands are either strings exactly matching
6084     the identification string of an object or regular expressions that are
6085     then matched case-insensitively against various attributes of the
6086     objects. The parser recognizes a regular expression only if you
6087     enclose it between two slashes.
6088    
6089     The principle is that the number of found objects influences how an
6090     item is displayed. If the search finds one item, the result is
6091     displayed with the rather verbose method C<as_string>, but if we find
6092     more than one, we display each object with the terse method
6093     <as_glimpse>.
6094    
6095     =item make, test, install, clean modules or distributions
6096    
6097     These commands take any number of arguments and investigate what is
6098     necessary to perform the action. If the argument is a distribution
6099     file name (recognized by embedded slashes), it is processed. If it is
6100     a module, CPAN determines the distribution file in which this module
6101     is included and processes that, following any dependencies named in
6102     the module's Makefile.PL (this behavior is controlled by
6103     I<prerequisites_policy>.)
6104    
6105     Any C<make> or C<test> are run unconditionally. An
6106    
6107     install <distribution_file>
6108    
6109     also is run unconditionally. But for
6110    
6111     install <module>
6112    
6113     CPAN checks if an install is actually needed for it and prints
6114     I<module up to date> in the case that the distribution file containing
6115     the module doesn't need to be updated.
6116    
6117     CPAN also keeps track of what it has done within the current session
6118     and doesn't try to build a package a second time regardless if it
6119     succeeded or not. The C<force> command takes as a first argument the
6120     method to invoke (currently: C<make>, C<test>, or C<install>) and executes the
6121     command from scratch.
6122    
6123     Example:
6124    
6125     cpan> install OpenGL
6126     OpenGL is up to date.
6127     cpan> force install OpenGL
6128     Running make
6129     OpenGL-0.4/
6130     OpenGL-0.4/COPYRIGHT
6131     [...]
6132    
6133     A C<clean> command results in a
6134    
6135     make clean
6136    
6137     being executed within the distribution file's working directory.
6138    
6139     =item get, readme, look module or distribution
6140    
6141     C<get> downloads a distribution file without further action. C<readme>
6142     displays the README file of the associated distribution. C<Look> gets
6143     and untars (if not yet done) the distribution file, changes to the
6144     appropriate directory and opens a subshell process in that directory.
6145    
6146     =item ls author
6147    
6148     C<ls> lists all distribution files in and below an author's CPAN
6149     directory. Only those files that contain modules are listed and if
6150     there is more than one for any given module, only the most recent one
6151     is listed.
6152    
6153     =item Signals
6154    
6155     CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
6156     in the cpan-shell it is intended that you can press C<^C> anytime and
6157     return to the cpan-shell prompt. A SIGTERM will cause the cpan-shell
6158     to clean up and leave the shell loop. You can emulate the effect of a
6159     SIGTERM by sending two consecutive SIGINTs, which usually means by
6160     pressing C<^C> twice.
6161    
6162     CPAN.pm ignores a SIGPIPE. If the user sets inactivity_timeout, a
6163     SIGALRM is used during the run of the C<perl Makefile.PL> subprocess.
6164    
6165     =back
6166    
6167     =head2 CPAN::Shell
6168    
6169     The commands that are available in the shell interface are methods in
6170     the package CPAN::Shell. If you enter the shell command, all your
6171     input is split by the Text::ParseWords::shellwords() routine which
6172     acts like most shells do. The first word is being interpreted as the
6173     method to be called and the rest of the words are treated as arguments
6174     to this method. Continuation lines are supported if a line ends with a
6175     literal backslash.
6176    
6177     =head2 autobundle
6178    
6179     C<autobundle> writes a bundle file into the
6180     C<$CPAN::Config-E<gt>{cpan_home}/Bundle> directory. The file contains
6181     a list of all modules that are both available from CPAN and currently
6182     installed within @INC. The name of the bundle file is based on the
6183     current date and a counter.
6184    
6185     =head2 recompile
6186    
6187     recompile() is a very special command in that it takes no argument and
6188     runs the make/test/install cycle with brute force over all installed
6189     dynamically loadable extensions (aka XS modules) with 'force' in
6190     effect. The primary purpose of this command is to finish a network
6191     installation. Imagine, you have a common source tree for two different
6192     architectures. You decide to do a completely independent fresh
6193     installation. You start on one architecture with the help of a Bundle
6194     file produced earlier. CPAN installs the whole Bundle for you, but
6195     when you try to repeat the job on the second architecture, CPAN
6196     responds with a C<"Foo up to date"> message for all modules. So you
6197     invoke CPAN's recompile on the second architecture and you're done.
6198    
6199     Another popular use for C<recompile> is to act as a rescue in case your
6200     perl breaks binary compatibility. If one of the modules that CPAN uses
6201     is in turn depending on binary compatibility (so you cannot run CPAN
6202     commands), then you should try the CPAN::Nox module for recovery.
6203    
6204     =head2 The four C<CPAN::*> Classes: Author, Bundle, Module, Distribution
6205    
6206     Although it may be considered internal, the class hierarchy does matter
6207     for both users and programmer. CPAN.pm deals with above mentioned four
6208     classes, and all those classes share a set of methods. A classical
6209     single polymorphism is in effect. A metaclass object registers all
6210     objects of all kinds and indexes them with a string. The strings
6211     referencing objects have a separated namespace (well, not completely
6212     separated):
6213    
6214     Namespace Class
6215    
6216     words containing a "/" (slash) Distribution
6217     words starting with Bundle:: Bundle
6218     everything else Module or Author
6219    
6220     Modules know their associated Distribution objects. They always refer
6221     to the most recent official release. Developers may mark their releases
6222     as unstable development versions (by inserting an underbar into the
6223     module version number which will also be reflected in the distribution
6224     name when you run 'make dist'), so the really hottest and newest
6225     distribution is not always the default. If a module Foo circulates
6226     on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
6227     way to install version 1.23 by saying
6228    
6229     install Foo
6230    
6231     This would install the complete distribution file (say
6232     BAR/Foo-1.23.tar.gz) with all accompanying material. But if you would
6233     like to install version 1.23_90, you need to know where the
6234     distribution file resides on CPAN relative to the authors/id/
6235     directory. If the author is BAR, this might be BAR/Foo-1.23_90.tar.gz;
6236     so you would have to say
6237    
6238     install BAR/Foo-1.23_90.tar.gz
6239    
6240     The first example will be driven by an object of the class
6241     CPAN::Module, the second by an object of class CPAN::Distribution.
6242    
6243     =head2 Programmer's interface
6244    
6245     If you do not enter the shell, the available shell commands are both
6246     available as methods (C<CPAN::Shell-E<gt>install(...)>) and as
6247     functions in the calling package (C<install(...)>).
6248    
6249     There's currently only one class that has a stable interface -
6250     CPAN::Shell. All commands that are available in the CPAN shell are
6251     methods of the class CPAN::Shell. Each of the commands that produce
6252     listings of modules (C<r>, C<autobundle>, C<u>) also return a list of
6253     the IDs of all modules within the list.
6254    
6255     =over 2
6256    
6257     =item expand($type,@things)
6258    
6259     The IDs of all objects available within a program are strings that can
6260     be expanded to the corresponding real objects with the
6261     C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
6262     list of CPAN::Module objects according to the C<@things> arguments
6263     given. In scalar context it only returns the first element of the
6264     list.
6265    
6266     =item expandany(@things)
6267    
6268     Like expand, but returns objects of the appropriate type, i.e.
6269     CPAN::Bundle objects for bundles, CPAN::Module objects for modules and
6270     CPAN::Distribution objects fro distributions.
6271    
6272     =item Programming Examples
6273    
6274     This enables the programmer to do operations that combine
6275     functionalities that are available in the shell.
6276    
6277     # install everything that is outdated on my disk:
6278     perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'
6279    
6280     # install my favorite programs if necessary:
6281     for $mod (qw(Net::FTP Digest::MD5 Data::Dumper)){
6282     my $obj = CPAN::Shell->expand('Module',$mod);
6283     $obj->install;
6284     }
6285    
6286     # list all modules on my disk that have no VERSION number
6287     for $mod (CPAN::Shell->expand("Module","/./")){
6288     next unless $mod->inst_file;
6289     # MakeMaker convention for undefined $VERSION:
6290     next unless $mod->inst_version eq "undef";
6291     print "No VERSION in ", $mod->id, "\n";
6292     }
6293    
6294     # find out which distribution on CPAN contains a module:
6295     print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file
6296    
6297     Or if you want to write a cronjob to watch The CPAN, you could list
6298     all modules that need updating. First a quick and dirty way:
6299    
6300     perl -e 'use CPAN; CPAN::Shell->r;'
6301    
6302     If you don't want to get any output in the case that all modules are
6303     up to date, you can parse the output of above command for the regular
6304     expression //modules are up to date// and decide to mail the output
6305     only if it doesn't match. Ick?
6306    
6307     If you prefer to do it more in a programmer style in one single
6308     process, maybe something like this suits you better:
6309    
6310     # list all modules on my disk that have newer versions on CPAN
6311     for $mod (CPAN::Shell->expand("Module","/./")){
6312     next unless $mod->inst_file;
6313     next if $mod->uptodate;
6314     printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
6315     $mod->id, $mod->inst_version, $mod->cpan_version;
6316     }
6317    
6318     If that gives you too much output every day, you maybe only want to
6319     watch for three modules. You can write
6320    
6321     for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")){
6322    
6323     as the first line instead. Or you can combine some of the above
6324     tricks:
6325    
6326     # watch only for a new mod_perl module
6327     $mod = CPAN::Shell->expand("Module","mod_perl");
6328     exit if $mod->uptodate;
6329     # new mod_perl arrived, let me know all update recommendations
6330     CPAN::Shell->r;
6331    
6332     =back
6333    
6334     =head2 Methods in the other Classes
6335    
6336     The programming interface for the classes CPAN::Module,
6337     CPAN::Distribution, CPAN::Bundle, and CPAN::Author is still considered
6338     beta and partially even alpha. In the following paragraphs only those
6339     methods are documented that have proven useful over a longer time and
6340     thus are unlikely to change.
6341    
6342     =over 4
6343    
6344     =item CPAN::Author::as_glimpse()
6345    
6346     Returns a one-line description of the author
6347    
6348     =item CPAN::Author::as_string()
6349    
6350     Returns a multi-line description of the author
6351    
6352     =item CPAN::Author::email()
6353    
6354     Returns the author's email address
6355    
6356     =item CPAN::Author::fullname()
6357    
6358     Returns the author's name
6359    
6360     =item CPAN::Author::name()
6361    
6362     An alias for fullname
6363    
6364     =item CPAN::Bundle::as_glimpse()
6365    
6366     Returns a one-line description of the bundle
6367    
6368     =item CPAN::Bundle::as_string()
6369    
6370     Returns a multi-line description of the bundle
6371    
6372     =item CPAN::Bundle::clean()
6373    
6374     Recursively runs the C<clean> method on all items contained in the bundle.
6375    
6376     =item CPAN::Bundle::contains()
6377    
6378     Returns a list of objects' IDs contained in a bundle. The associated
6379     objects may be bundles, modules or distributions.
6380    
6381     =item CPAN::Bundle::force($method,@args)
6382    
6383     Forces CPAN to perform a task that normally would have failed. Force
6384     takes as arguments a method name to be called and any number of
6385     additional arguments that should be passed to the called method. The
6386     internals of the object get the needed changes so that CPAN.pm does
6387     not refuse to take the action. The C<force> is passed recursively to
6388     all contained objects.
6389    
6390     =item CPAN::Bundle::get()
6391    
6392     Recursively runs the C<get> method on all items contained in the bundle
6393    
6394     =item CPAN::Bundle::inst_file()
6395    
6396     Returns the highest installed version of the bundle in either @INC or
6397     C<$CPAN::Config->{cpan_home}>. Note that this is different from
6398     CPAN::Module::inst_file.
6399    
6400     =item CPAN::Bundle::inst_version()
6401    
6402     Like CPAN::Bundle::inst_file, but returns the $VERSION
6403    
6404     =item CPAN::Bundle::uptodate()
6405    
6406     Returns 1 if the bundle itself and all its members are uptodate.
6407    
6408     =item CPAN::Bundle::install()
6409    
6410     Recursively runs the C<install> method on all items contained in the bundle
6411    
6412     =item CPAN::Bundle::make()
6413    
6414     Recursively runs the C<make> method on all items contained in the bundle
6415    
6416     =item CPAN::Bundle::readme()
6417    
6418     Recursively runs the C<readme> method on all items contained in the bundle
6419    
6420     =item CPAN::Bundle::test()
6421    
6422     Recursively runs the C<test> method on all items contained in the bundle
6423    
6424     =item CPAN::Distribution::as_glimpse()
6425    
6426     Returns a one-line description of the distribution
6427    
6428     =item CPAN::Distribution::as_string()
6429    
6430     Returns a multi-line description of the distribution
6431    
6432     =item CPAN::Distribution::clean()
6433    
6434     Changes to the directory where the distribution has been unpacked and
6435     runs C<make clean> there.
6436    
6437     =item CPAN::Distribution::containsmods()
6438    
6439     Returns a list of IDs of modules contained in a distribution file.
6440     Only works for distributions listed in the 02packages.details.txt.gz
6441     file. This typically means that only the most recent version of a
6442     distribution is covered.
6443    
6444     =item CPAN::Distribution::cvs_import()
6445    
6446     Changes to the directory where the distribution has been unpacked and
6447     runs something like
6448    
6449     cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version
6450    
6451     there.
6452    
6453     =item CPAN::Distribution::dir()
6454    
6455     Returns the directory into which this distribution has been unpacked.
6456    
6457     =item CPAN::Distribution::force($method,@args)
6458    
6459     Forces CPAN to perform a task that normally would have failed. Force
6460     takes as arguments a method name to be called and any number of
6461     additional arguments that should be passed to the called method. The
6462     internals of the object get the needed changes so that CPAN.pm does
6463     not refuse to take the action.
6464    
6465     =item CPAN::Distribution::get()
6466    
6467     Downloads the distribution from CPAN and unpacks it. Does nothing if
6468     the distribution has already been downloaded and unpacked within the
6469     current session.
6470    
6471     =item CPAN::Distribution::install()
6472    
6473     Changes to the directory where the distribution has been unpacked and
6474     runs the external command C<make install> there. If C<make> has not
6475     yet been run, it will be run first. A C<make test> will be issued in
6476     any case and if this fails, the install will be canceled. The
6477     cancellation can be avoided by letting C<force> run the C<install> for
6478     you.
6479    
6480     =item CPAN::Distribution::isa_perl()
6481    
6482     Returns 1 if this distribution file seems to be a perl distribution.
6483     Normally this is derived from the file name only, but the index from
6484     CPAN can contain a hint to achieve a return value of true for other
6485     filenames too.
6486    
6487     =item CPAN::Distribution::look()
6488    
6489     Changes to the directory where the distribution has been unpacked and
6490     opens a subshell there. Exiting the subshell returns.
6491    
6492     =item CPAN::Distribution::make()
6493    
6494     First runs the C<get> method to make sure the distribution is
6495     downloaded and unpacked. Changes to the directory where the
6496     distribution has been unpacked and runs the external commands C<perl
6497     Makefile.PL> and C<make> there.
6498    
6499     =item CPAN::Distribution::prereq_pm()
6500    
6501     Returns the hash reference that has been announced by a distribution
6502     as the PREREQ_PM hash in the Makefile.PL. Note: works only after an
6503     attempt has been made to C<make> the distribution. Returns undef
6504     otherwise.
6505    
6506     =item CPAN::Distribution::readme()
6507    
6508     Downloads the README file associated with a distribution and runs it
6509     through the pager specified in C<$CPAN::Config->{pager}>.
6510    
6511     =item CPAN::Distribution::test()
6512    
6513     Changes to the directory where the distribution has been unpacked and
6514     runs C<make test> there.
6515    
6516     =item CPAN::Distribution::uptodate()
6517    
6518     Returns 1 if all the modules contained in the distribution are
6519     uptodate. Relies on containsmods.
6520    
6521     =item CPAN::Index::force_reload()
6522    
6523     Forces a reload of all indices.
6524    
6525     =item CPAN::Index::reload()
6526    
6527     Reloads all indices if they have been read more than
6528     C<$CPAN::Config->{index_expire}> days.
6529    
6530     =item CPAN::InfoObj::dump()
6531    
6532     CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
6533     inherit this method. It prints the data structure associated with an
6534     object. Useful for debugging. Note: the data structure is considered
6535     internal and thus subject to change without notice.
6536    
6537     =item CPAN::Module::as_glimpse()
6538    
6539     Returns a one-line description of the module
6540    
6541     =item CPAN::Module::as_string()
6542    
6543     Returns a multi-line description of the module
6544    
6545     =item CPAN::Module::clean()
6546    
6547     Runs a clean on the distribution associated with this module.
6548    
6549     =item CPAN::Module::cpan_file()
6550    
6551     Returns the filename on CPAN that is associated with the module.
6552    
6553     =item CPAN::Module::cpan_version()
6554    
6555     Returns the latest version of this module available on CPAN.
6556    
6557     =item CPAN::Module::cvs_import()
6558    
6559     Runs a cvs_import on the distribution associated with this module.
6560    
6561     =item CPAN::Module::description()
6562    
6563     Returns a 44 character description of this module. Only available for
6564     modules listed in The Module List (CPAN/modules/00modlist.long.html
6565     or 00modlist.long.txt.gz)
6566    
6567     =item CPAN::Module::force($method,@args)
6568    
6569     Forces CPAN to perform a task that normally would have failed. Force
6570     takes as arguments a method name to be called and any number of
6571     additional arguments that should be passed to the called method. The
6572     internals of the object get the needed changes so that CPAN.pm does
6573     not refuse to take the action.
6574    
6575     =item CPAN::Module::get()
6576    
6577     Runs a get on the distribution associated with this module.
6578    
6579     =item CPAN::Module::inst_file()
6580    
6581     Returns the filename of the module found in @INC. The first file found
6582     is reported just like perl itself stops searching @INC when it finds a
6583     module.
6584    
6585     =item CPAN::Module::inst_version()
6586    
6587     Returns the version number of the module in readable format.
6588    
6589     =item CPAN::Module::install()
6590    
6591     Runs an C<install> on the distribution associated with this module.
6592    
6593     =item CPAN::Module::look()
6594    
6595     Changes to the directory where the distribution associated with this
6596     module has been unpacked and opens a subshell there. Exiting the
6597     subshell returns.
6598    
6599     =item CPAN::Module::make()
6600    
6601     Runs a C<make> on the distribution associated with this module.
6602    
6603     =item CPAN::Module::manpage_headline()
6604    
6605     If module is installed, peeks into the module's manpage, reads the
6606     headline and returns it. Moreover, if the module has been downloaded
6607     within this session, does the equivalent on the downloaded module even
6608     if it is not installed.
6609    
6610     =item CPAN::Module::readme()
6611    
6612     Runs a C<readme> on the distribution associated with this module.
6613    
6614     =item CPAN::Module::test()
6615    
6616     Runs a C<test> on the distribution associated with this module.
6617    
6618     =item CPAN::Module::uptodate()
6619    
6620     Returns 1 if the module is installed and up-to-date.
6621    
6622     =item CPAN::Module::userid()
6623    
6624     Returns the author's ID of the module.
6625    
6626     =back
6627    
6628     =head2 Cache Manager
6629    
6630     Currently the cache manager only keeps track of the build directory
6631     ($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
6632     deletes complete directories below C<build_dir> as soon as the size of
6633     all directories there gets bigger than $CPAN::Config->{build_cache}
6634     (in MB). The contents of this cache may be used for later
6635     re-installations that you intend to do manually, but will never be
6636     trusted by CPAN itself. This is due to the fact that the user might
6637     use these directories for building modules on different architectures.
6638    
6639     There is another directory ($CPAN::Config->{keep_source_where}) where
6640     the original distribution files are kept. This directory is not
6641     covered by the cache manager and must be controlled by the user. If
6642     you choose to have the same directory as build_dir and as
6643     keep_source_where directory, then your sources will be deleted with
6644     the same fifo mechanism.
6645    
6646     =head2 Bundles
6647    
6648     A bundle is just a perl module in the namespace Bundle:: that does not
6649     define any functions or methods. It usually only contains documentation.
6650    
6651     It starts like a perl module with a package declaration and a $VERSION
6652     variable. After that the pod section looks like any other pod with the
6653     only difference being that I<one special pod section> exists starting with
6654     (verbatim):
6655    
6656     =head1 CONTENTS
6657    
6658     In this pod section each line obeys the format
6659    
6660     Module_Name [Version_String] [- optional text]
6661    
6662     The only required part is the first field, the name of a module
6663     (e.g. Foo::Bar, ie. I<not> the name of the distribution file). The rest
6664     of the line is optional. The comment part is delimited by a dash just
6665     as in the man page header.
6666    
6667     The distribution of a bundle should follow the same convention as
6668     other distributions.
6669    
6670     Bundles are treated specially in the CPAN package. If you say 'install
6671     Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
6672     the modules in the CONTENTS section of the pod. You can install your
6673     own Bundles locally by placing a conformant Bundle file somewhere into
6674     your @INC path. The autobundle() command which is available in the
6675     shell interface does that for you by including all currently installed
6676     modules in a snapshot bundle file.
6677    
6678     =head2 Prerequisites
6679    
6680     If you have a local mirror of CPAN and can access all files with
6681     "file:" URLs, then you only need a perl better than perl5.003 to run
6682     this module. Otherwise Net::FTP is strongly recommended. LWP may be
6683     required for non-UNIX systems or if your nearest CPAN site is
6684     associated with a URL that is not C<ftp:>.
6685    
6686     If you have neither Net::FTP nor LWP, there is a fallback mechanism
6687     implemented for an external ftp command or for an external lynx
6688     command.
6689    
6690     =head2 Finding packages and VERSION
6691    
6692     This module presumes that all packages on CPAN
6693    
6694     =over 2
6695    
6696     =item *
6697    
6698     declare their $VERSION variable in an easy to parse manner. This
6699     prerequisite can hardly be relaxed because it consumes far too much
6700     memory to load all packages into the running program just to determine
6701     the $VERSION variable. Currently all programs that are dealing with
6702     version use something like this
6703    
6704     perl -MExtUtils::MakeMaker -le \
6705     'print MM->parse_version(shift)' filename
6706    
6707     If you are author of a package and wonder if your $VERSION can be
6708     parsed, please try the above method.
6709    
6710     =item *
6711    
6712     come as compressed or gzipped tarfiles or as zip files and contain a
6713     Makefile.PL (well, we try to handle a bit more, but without much
6714     enthusiasm).
6715    
6716     =back
6717    
6718     =head2 Debugging
6719    
6720     The debugging of this module is a bit complex, because we have
6721     interferences of the software producing the indices on CPAN, of the
6722     mirroring process on CPAN, of packaging, of configuration, of
6723     synchronicity, and of bugs within CPAN.pm.
6724    
6725     For code debugging in interactive mode you can try "o debug" which
6726     will list options for debugging the various parts of the code. You
6727     should know that "o debug" has built-in completion support.
6728    
6729     For data debugging there is the C<dump> command which takes the same
6730     arguments as make/test/install and outputs the object's Data::Dumper
6731     dump.
6732    
6733     =head2 Floppy, Zip, Offline Mode
6734    
6735     CPAN.pm works nicely without network too. If you maintain machines
6736     that are not networked at all, you should consider working with file:
6737     URLs. Of course, you have to collect your modules somewhere first. So
6738     you might use CPAN.pm to put together all you need on a networked
6739     machine. Then copy the $CPAN::Config->{keep_source_where} (but not
6740     $CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
6741     of a personal CPAN. CPAN.pm on the non-networked machines works nicely
6742     with this floppy. See also below the paragraph about CD-ROM support.
6743    
6744     =head1 CONFIGURATION
6745    
6746     When the CPAN module is used for the first time, a configuration
6747     dialog tries to determine a couple of site specific options. The
6748     result of the dialog is stored in a hash reference C< $CPAN::Config >
6749     in a file CPAN/Config.pm.
6750    
6751     The default values defined in the CPAN/Config.pm file can be
6752     overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
6753     best placed in $HOME/.cpan/CPAN/MyConfig.pm, because $HOME/.cpan is
6754     added to the search path of the CPAN module before the use() or
6755     require() statements.
6756    
6757     The configuration dialog can be started any time later again by
6758     issueing the command C< o conf init > in the CPAN shell.
6759    
6760     Currently the following keys in the hash reference $CPAN::Config are
6761     defined:
6762    
6763     build_cache size of cache for directories to build modules
6764     build_dir locally accessible directory to build modules
6765     index_expire after this many days refetch index files
6766     cache_metadata use serializer to cache metadata
6767     cpan_home local directory reserved for this package
6768     dontload_hash anonymous hash: modules in the keys will not be
6769     loaded by the CPAN::has_inst() routine
6770     gzip location of external program gzip
6771     histfile file to maintain history between sessions
6772     histsize maximum number of lines to keep in histfile
6773     inactivity_timeout breaks interactive Makefile.PLs after this
6774     many seconds inactivity. Set to 0 to never break.
6775     inhibit_startup_message
6776     if true, does not print the startup message
6777     keep_source_where directory in which to keep the source (if we do)
6778     make location of external make program
6779     make_arg arguments that should always be passed to 'make'
6780     make_install_arg same as make_arg for 'make install'
6781     makepl_arg arguments passed to 'perl Makefile.PL'
6782     pager location of external program more (or any pager)
6783     prerequisites_policy
6784     what to do if you are missing module prerequisites
6785     ('follow' automatically, 'ask' me, or 'ignore')
6786     proxy_user username for accessing an authenticating proxy
6787     proxy_pass password for accessing an authenticating proxy
6788     scan_cache controls scanning of cache ('atstart' or 'never')
6789     tar location of external program tar
6790     term_is_latin if true internal UTF-8 is translated to ISO-8859-1
6791     (and nonsense for characters outside latin range)
6792     unzip location of external program unzip
6793     urllist arrayref to nearby CPAN sites (or equivalent locations)
6794     wait_list arrayref to a wait server to try (See CPAN::WAIT)
6795     ftp_proxy, } the three usual variables for configuring
6796     http_proxy, } proxy requests. Both as CPAN::Config variables
6797     no_proxy } and as environment variables configurable.
6798    
6799     You can set and query each of these options interactively in the cpan
6800     shell with the command set defined within the C<o conf> command:
6801    
6802     =over 2
6803    
6804     =item C<o conf E<lt>scalar optionE<gt>>
6805    
6806     prints the current value of the I<scalar option>
6807    
6808     =item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>
6809    
6810     Sets the value of the I<scalar option> to I<value>
6811    
6812     =item C<o conf E<lt>list optionE<gt>>
6813    
6814     prints the current value of the I<list option> in MakeMaker's
6815     neatvalue format.
6816    
6817     =item C<o conf E<lt>list optionE<gt> [shift|pop]>
6818    
6819     shifts or pops the array in the I<list option> variable
6820    
6821     =item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>
6822    
6823     works like the corresponding perl commands.
6824    
6825     =back
6826    
6827     =head2 Note on urllist parameter's format
6828    
6829     urllist parameters are URLs according to RFC 1738. We do a little
6830     guessing if your URL is not compliant, but if you have problems with
6831     file URLs, please try the correct format. Either:
6832    
6833     file://localhost/whatever/ftp/pub/CPAN/
6834    
6835     or
6836    
6837     file:///home/ftp/pub/CPAN/
6838    
6839     =head2 urllist parameter has CD-ROM support
6840    
6841     The C<urllist> parameter of the configuration table contains a list of
6842     URLs that are to be used for downloading. If the list contains any
6843     C<file> URLs, CPAN always tries to get files from there first. This
6844     feature is disabled for index files. So the recommendation for the
6845     owner of a CD-ROM with CPAN contents is: include your local, possibly
6846     outdated CD-ROM as a C<file> URL at the end of urllist, e.g.
6847    
6848     o conf urllist push file://localhost/CDROM/CPAN
6849    
6850     CPAN.pm will then fetch the index files from one of the CPAN sites
6851     that come at the beginning of urllist. It will later check for each
6852     module if there is a local copy of the most recent version.
6853    
6854     Another peculiarity of urllist is that the site that we could
6855     successfully fetch the last file from automatically gets a preference
6856     token and is tried as the first site for the next request. So if you
6857     add a new site at runtime it may happen that the previously preferred
6858     site will be tried another time. This means that if you want to disallow
6859     a site for the next transfer, it must be explicitly removed from
6860     urllist.
6861    
6862     =head1 SECURITY
6863    
6864     There's no strong security layer in CPAN.pm. CPAN.pm helps you to
6865     install foreign, unmasked, unsigned code on your machine. We compare
6866     to a checksum that comes from the net just as the distribution file
6867     itself. If somebody has managed to tamper with the distribution file,
6868     they may have as well tampered with the CHECKSUMS file. Future
6869     development will go towards strong authentication.
6870    
6871     =head1 EXPORT
6872    
6873     Most functions in package CPAN are exported per default. The reason
6874     for this is that the primary use is intended for the cpan shell or for
6875     one-liners.
6876    
6877     =head1 POPULATE AN INSTALLATION WITH LOTS OF MODULES
6878    
6879     Populating a freshly installed perl with my favorite modules is pretty
6880     easy if you maintain a private bundle definition file. To get a useful
6881     blueprint of a bundle definition file, the command autobundle can be used
6882     on the CPAN shell command line. This command writes a bundle definition
6883     file for all modules that are installed for the currently running perl
6884     interpreter. It's recommended to run this command only once and from then
6885     on maintain the file manually under a private name, say
6886     Bundle/my_bundle.pm. With a clever bundle file you can then simply say
6887    
6888     cpan> install Bundle::my_bundle
6889    
6890     then answer a few questions and then go out for a coffee.
6891    
6892     Maintaining a bundle definition file means keeping track of two
6893     things: dependencies and interactivity. CPAN.pm sometimes fails on
6894     calculating dependencies because not all modules define all MakeMaker
6895     attributes correctly, so a bundle definition file should specify
6896     prerequisites as early as possible. On the other hand, it's a bit
6897     annoying that many distributions need some interactive configuring. So
6898     what I try to accomplish in my private bundle file is to have the
6899     packages that need to be configured early in the file and the gentle
6900     ones later, so I can go out after a few minutes and leave CPAN.pm
6901     untended.
6902    
6903     =head1 WORKING WITH CPAN.pm BEHIND FIREWALLS
6904    
6905     Thanks to Graham Barr for contributing the following paragraphs about
6906     the interaction between perl, and various firewall configurations. For
6907     further informations on firewalls, it is recommended to consult the
6908     documentation that comes with the ncftp program. If you are unable to
6909     go through the firewall with a simple Perl setup, it is very likely
6910     that you can configure ncftp so that it works for your firewall.
6911    
6912     =head2 Three basic types of firewalls
6913    
6914     Firewalls can be categorized into three basic types.
6915    
6916     =over 4
6917    
6918     =item http firewall
6919    
6920     This is where the firewall machine runs a web server and to access the
6921     outside world you must do it via the web server. If you set environment
6922     variables like http_proxy or ftp_proxy to a values beginning with http://
6923     or in your web browser you have to set proxy information then you know
6924     you are running an http firewall.
6925    
6926     To access servers outside these types of firewalls with perl (even for
6927     ftp) you will need to use LWP.
6928    
6929     =item ftp firewall
6930    
6931     This where the firewall machine runs an ftp server. This kind of
6932     firewall will only let you access ftp servers outside the firewall.
6933     This is usually done by connecting to the firewall with ftp, then
6934     entering a username like "user@outside.host.com"
6935    
6936     To access servers outside these type of firewalls with perl you
6937     will need to use Net::FTP.
6938    
6939     =item One way visibility
6940    
6941     I say one way visibility as these firewalls try to make themselves look
6942     invisible to the users inside the firewall. An FTP data connection is
6943     normally created by sending the remote server your IP address and then
6944     listening for the connection. But the remote server will not be able to
6945     connect to you because of the firewall. So for these types of firewall
6946     FTP connections need to be done in a passive mode.
6947    
6948     There are two that I can think off.
6949    
6950     =over 4
6951    
6952     =item SOCKS
6953    
6954     If you are using a SOCKS firewall you will need to compile perl and link
6955     it with the SOCKS library, this is what is normally called a 'socksified'
6956     perl. With this executable you will be able to connect to servers outside
6957     the firewall as if it is not there.
6958    
6959     =item IP Masquerade
6960    
6961     This is the firewall implemented in the Linux kernel, it allows you to
6962     hide a complete network behind one IP address. With this firewall no
6963     special compiling is needed as you can access hosts directly.
6964    
6965     For accessing ftp servers behind such firewalls you may need to set
6966     the environment variable C<FTP_PASSIVE> to a true value, e.g.
6967    
6968     env FTP_PASSIVE=1 perl -MCPAN -eshell
6969    
6970     or
6971    
6972     perl -MCPAN -e '$ENV{FTP_PASSIVE} = 1; shell'
6973    
6974    
6975     =back
6976    
6977     =back
6978    
6979     =head2 Configuring lynx or ncftp for going through a firewall
6980    
6981     If you can go through your firewall with e.g. lynx, presumably with a
6982     command such as
6983    
6984     /usr/local/bin/lynx -pscott:tiger
6985    
6986     then you would configure CPAN.pm with the command
6987    
6988     o conf lynx "/usr/local/bin/lynx -pscott:tiger"
6989    
6990     That's all. Similarly for ncftp or ftp, you would configure something
6991     like
6992    
6993     o conf ncftp "/usr/bin/ncftp -f /home/scott/ncftplogin.cfg"
6994    
6995     Your mileage may vary...
6996    
6997     =head1 FAQ
6998    
6999     =over 4
7000    
7001     =item 1)
7002    
7003     I installed a new version of module X but CPAN keeps saying,
7004     I have the old version installed
7005    
7006     Most probably you B<do> have the old version installed. This can
7007     happen if a module installs itself into a different directory in the
7008     @INC path than it was previously installed. This is not really a
7009     CPAN.pm problem, you would have the same problem when installing the
7010     module manually. The easiest way to prevent this behaviour is to add
7011     the argument C<UNINST=1> to the C<make install> call, and that is why
7012     many people add this argument permanently by configuring
7013    
7014     o conf make_install_arg UNINST=1
7015    
7016     =item 2)
7017    
7018     So why is UNINST=1 not the default?
7019    
7020     Because there are people who have their precise expectations about who
7021     may install where in the @INC path and who uses which @INC array. In
7022     fine tuned environments C<UNINST=1> can cause damage.
7023    
7024     =item 3)
7025    
7026     I want to clean up my mess, and install a new perl along with
7027     all modules I have. How do I go about it?
7028    
7029     Run the autobundle command for your old perl and optionally rename the
7030     resulting bundle file (e.g. Bundle/mybundle.pm), install the new perl
7031     with the Configure option prefix, e.g.
7032    
7033     ./Configure -Dprefix=/usr/local/perl-5.6.78.9
7034    
7035     Install the bundle file you produced in the first step with something like
7036    
7037     cpan> install Bundle::mybundle
7038    
7039     and you're done.
7040    
7041     =item 4)
7042    
7043     When I install bundles or multiple modules with one command
7044     there is too much output to keep track of.
7045    
7046     You may want to configure something like
7047    
7048     o conf make_arg "| tee -ai /root/.cpan/logs/make.out"
7049     o conf make_install_arg "| tee -ai /root/.cpan/logs/make_install.out"
7050    
7051     so that STDOUT is captured in a file for later inspection.
7052    
7053    
7054     =item 5)
7055    
7056     I am not root, how can I install a module in a personal directory?
7057    
7058     You will most probably like something like this:
7059    
7060     o conf makepl_arg "LIB=~/myperl/lib \
7061     INSTALLMAN1DIR=~/myperl/man/man1 \
7062     INSTALLMAN3DIR=~/myperl/man/man3"
7063     install Sybase::Sybperl
7064    
7065     You can make this setting permanent like all C<o conf> settings with
7066     C<o conf commit>.
7067    
7068     You will have to add ~/myperl/man to the MANPATH environment variable
7069     and also tell your perl programs to look into ~/myperl/lib, e.g. by
7070     including
7071    
7072     use lib "$ENV{HOME}/myperl/lib";
7073    
7074     or setting the PERL5LIB environment variable.
7075    
7076     Another thing you should bear in mind is that the UNINST parameter
7077     should never be set if you are not root.
7078    
7079     =item 6)
7080    
7081     How to get a package, unwrap it, and make a change before building it?
7082    
7083     look Sybase::Sybperl
7084    
7085     =item 7)
7086    
7087     I installed a Bundle and had a couple of fails. When I
7088     retried, everything resolved nicely. Can this be fixed to work
7089     on first try?
7090    
7091     The reason for this is that CPAN does not know the dependencies of all
7092     modules when it starts out. To decide about the additional items to
7093     install, it just uses data found in the generated Makefile. An
7094     undetected missing piece breaks the process. But it may well be that
7095     your Bundle installs some prerequisite later than some depending item
7096     and thus your second try is able to resolve everything. Please note,
7097     CPAN.pm does not know the dependency tree in advance and cannot sort
7098     the queue of things to install in a topologically correct order. It
7099     resolves perfectly well IFF all modules declare the prerequisites
7100     correctly with the PREREQ_PM attribute to MakeMaker. For bundles which
7101     fail and you need to install often, it is recommended sort the Bundle
7102     definition file manually. It is planned to improve the metadata
7103     situation for dependencies on CPAN in general, but this will still
7104     take some time.
7105    
7106     =item 8)
7107    
7108     In our intranet we have many modules for internal use. How
7109     can I integrate these modules with CPAN.pm but without uploading
7110     the modules to CPAN?
7111    
7112     Have a look at the CPAN::Site module.
7113    
7114     =item 9)
7115    
7116     When I run CPAN's shell, I get error msg about line 1 to 4,
7117     setting meta input/output via the /etc/inputrc file.
7118    
7119     Some versions of readline are picky about capitalization in the
7120     /etc/inputrc file and specifically RedHat 6.2 comes with a
7121     /etc/inputrc that contains the word C<on> in lowercase. Change the
7122     occurrences of C<on> to C<On> and the bug should disappear.
7123    
7124     =item 10)
7125    
7126     Some authors have strange characters in their names.
7127    
7128     Internally CPAN.pm uses the UTF-8 charset. If your terminal is
7129     expecting ISO-8859-1 charset, a converter can be activated by setting
7130     term_is_latin to a true value in your config file. One way of doing so
7131     would be
7132    
7133     cpan> ! $CPAN::Config->{term_is_latin}=1
7134    
7135     Extended support for converters will be made available as soon as perl
7136     becomes stable with regard to charset issues.
7137    
7138     =back
7139    
7140     =head1 BUGS
7141    
7142     We should give coverage for B<all> of the CPAN and not just the PAUSE
7143     part, right? In this discussion CPAN and PAUSE have become equal --
7144     but they are not. PAUSE is authors/, modules/ and scripts/. CPAN is
7145     PAUSE plus the clpa/, doc/, misc/, ports/, and src/.
7146    
7147     Future development should be directed towards a better integration of
7148     the other parts.
7149    
7150     If a Makefile.PL requires special customization of libraries, prompts
7151     the user for special input, etc. then you may find CPAN is not able to
7152     build the distribution. In that case, you should attempt the
7153     traditional method of building a Perl module package from a shell.
7154    
7155     =head1 AUTHOR
7156    
7157     Andreas Koenig E<lt>andreas.koenig@anima.deE<gt>
7158    
7159     =head1 TRANSLATIONS
7160    
7161     Kawai,Takanori provides a Japanese translation of this manpage at
7162     http://member.nifty.ne.jp/hippo2000/perltips/CPAN.htm
7163    
7164     =head1 SEE ALSO
7165    
7166     perl(1), CPAN::Nox(3)
7167    
7168     =cut
7169