source: for-distributions/trunk/bin/windows/perl/lib/CPAN.pm@ 14489

Last change on this file since 14489 was 14489, checked in by oranfry, 17 years ago

upgrading to perl 5.8

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