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