This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
OS2::PrfDB was exploiting a bug in U32 XSUBs
[perl5.git] / lib / CPAN.pm
CommitLineData
5f05dabc 1package CPAN;
c356248b
AK
2use vars qw{$Try_autoload $Revision
3 $META $Signal $Cwd $End
4 $Suppress_readline %Dontload
09d9d230 5 $Frontend $Defaultsite
c356248b 6 };
5f05dabc 7
2e2b7522 8$VERSION = '1.40';
5f05dabc 9
2e2b7522 10# $Id: CPAN.pm,v 1.239 1998/07/24 16:37:04 k Exp $
5f05dabc 11
c356248b
AK
12# only used during development:
13$Revision = "";
2e2b7522 14# $Revision = "[".substr(q$Revision: 1.239 $, 10)."]";
5f05dabc
PP
15
16use Carp ();
17use Config ();
18use Cwd ();
19use DirHandle;
20use Exporter ();
2e2b7522 21use ExtUtils::MakeMaker (); # $SelfLoader::DEBUG=1;
5f05dabc 22use File::Basename ();
10b2abe6 23use File::Copy ();
5f05dabc
PP
24use File::Find;
25use File::Path ();
da199366 26use FileHandle ();
5f05dabc 27use Safe ();
10b2abe6 28use Text::ParseWords ();
05454584 29use Text::Wrap;
5f05dabc 30
5f05dabc
PP
31END { $End++; &cleanup; }
32
2e2b7522 33%CPAN::DEBUG = qw[
5f05dabc
PP
34 CPAN 1
35 Index 2
36 InfoObj 4
37 Author 8
38 Distribution 16
39 Bundle 32
40 Module 64
41 CacheMgr 128
42 Complete 256
43 FTP 512
44 Shell 1024
45 Eval 2048
46 Config 4096
09d9d230 47 Tarzip 8192
2e2b7522 48];
5f05dabc
PP
49
50$CPAN::DEBUG ||= 0;
da199366 51$CPAN::Signal ||= 0;
c356248b 52$CPAN::Frontend ||= "CPAN::Shell";
09d9d230 53$CPAN::Defaultsite ||= "ftp://ftp.perl.org/pub/CPAN";
5f05dabc
PP
54
55package CPAN;
05454584 56use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META $term);
5f05dabc
PP
57use strict qw(vars);
58
2e2b7522 59@CPAN::ISA = qw(CPAN::Debug Exporter);
5f05dabc 60
55e314ee 61@EXPORT = qw(
da199366
AK
62 autobundle bundle expand force get
63 install make readme recompile shell test clean
64 );
5f05dabc 65
55e314ee
AK
66#-> sub CPAN::AUTOLOAD ;
67sub AUTOLOAD {
68 my($l) = $AUTOLOAD;
69 $l =~ s/.*:://;
70 my(%EXPORT);
71 @EXPORT{@EXPORT} = '';
72 if (exists $EXPORT{$l}){
73 CPAN::Shell->$l(@_);
74 } else {
75 my $ok = CPAN::Shell->try_dot_al($AUTOLOAD);
76 if ($ok) {
77 goto &$AUTOLOAD;
c356248b
AK
78# } else {
79# $CPAN::Frontend->mywarn("Could not autoload $AUTOLOAD");
55e314ee 80 }
c356248b
AK
81 $CPAN::Frontend->mywarn(qq{Unknown command "$AUTOLOAD". }.
82 qq{Type ? for help.
83});
55e314ee
AK
84 }
85}
86
87#-> sub CPAN::shell ;
88sub shell {
89 $Suppress_readline ||= ! -t STDIN;
90
91 my $prompt = "cpan> ";
92 local($^W) = 1;
93 unless ($Suppress_readline) {
94 require Term::ReadLine;
95# import Term::ReadLine;
96 $term = Term::ReadLine->new('CPAN Monitor');
97 $readline::rl_completion_function =
98 $readline::rl_completion_function = 'CPAN::Complete::cpl';
99 }
100
101 no strict;
102 $META->checklock();
103 my $getcwd;
104 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
105 my $cwd = CPAN->$getcwd();
106 my $rl_avail = $Suppress_readline ? "suppressed" :
107 ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
108 "available (try ``install Bundle::CPAN'')";
109
c356248b
AK
110 $CPAN::Frontend->myprint(
111 qq{
112cpan shell -- CPAN exploration and modules installation (v$CPAN::VERSION$CPAN::Revision)
113ReadLine support $rl_avail
55e314ee 114
c356248b
AK
115}) unless $CPAN::Config->{'inhibit_startup_message'} ;
116 my($continuation) = "";
55e314ee
AK
117 while () {
118 if ($Suppress_readline) {
119 print $prompt;
120 last unless defined ($_ = <> );
121 chomp;
122 } else {
123 last unless defined ($_ = $term->readline($prompt));
124 }
c356248b 125 $_ = "$continuation$_" if $continuation;
55e314ee
AK
126 s/^\s+//;
127 next if /^$/;
2e2b7522 128 $_ = 'h' if /^\s*\?/;
09d9d230 129 if (/^(?:q(?:uit)?|bye|exit)$/i) {
c356248b
AK
130 last;
131 } elsif (s/\\$//s) {
132 chomp;
133 $continuation = $_;
134 $prompt = " > ";
135 } elsif (/^\!/) {
55e314ee
AK
136 s/^\!//;
137 my($eval) = $_;
138 package CPAN::Eval;
139 use vars qw($import_done);
140 CPAN->import(':DEFAULT') unless $import_done++;
141 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
142 eval($eval);
143 warn $@ if $@;
c356248b
AK
144 $continuation = "";
145 $prompt = "cpan> ";
55e314ee
AK
146 } elsif (/./) {
147 my(@line);
148 if ($] < 5.00322) { # parsewords had a bug until recently
149 @line = split;
150 } else {
151 eval { @line = Text::ParseWords::shellwords($_) };
152 warn($@), next if $@;
153 }
154 $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
155 my $command = shift @line;
156 eval { CPAN::Shell->$command(@line) };
157 warn $@ if $@;
c356248b
AK
158 chdir $cwd;
159 $CPAN::Frontend->myprint("\n");
160 $continuation = "";
161 $prompt = "cpan> ";
55e314ee
AK
162 }
163 } continue {
09d9d230 164 $Signal=0;
55e314ee
AK
165 }
166}
167
168package CPAN::CacheMgr;
c356248b 169@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
55e314ee
AK
170use File::Find;
171
172package CPAN::Config;
173import ExtUtils::MakeMaker 'neatvalue';
174use vars qw(%can $dot_cpan);
175
176%can = (
177 'commit' => "Commit changes to disk",
178 'defaults' => "Reload defaults from disk",
179 'init' => "Interactive setting of all options",
180);
181
182package CPAN::FTP;
c356248b 183use vars qw($Ua $Thesite $Themethod);
55e314ee
AK
184@CPAN::FTP::ISA = qw(CPAN::Debug);
185
186package CPAN::Complete;
187@CPAN::Complete::ISA = qw(CPAN::Debug);
188
189package CPAN::Index;
190use vars qw($last_time $date_of_03);
191@CPAN::Index::ISA = qw(CPAN::Debug);
192$last_time ||= 0;
193$date_of_03 ||= 0;
194
195package CPAN::InfoObj;
196@CPAN::InfoObj::ISA = qw(CPAN::Debug);
197
198package CPAN::Author;
199@CPAN::Author::ISA = qw(CPAN::InfoObj);
200
201package CPAN::Distribution;
202@CPAN::Distribution::ISA = qw(CPAN::InfoObj);
203
204package CPAN::Bundle;
205@CPAN::Bundle::ISA = qw(CPAN::Module);
206
207package CPAN::Module;
208@CPAN::Module::ISA = qw(CPAN::InfoObj);
10b2abe6 209
55e314ee
AK
210package CPAN::Shell;
211use vars qw($AUTOLOAD $redef @ISA);
212@CPAN::Shell::ISA = qw(CPAN::Debug);
213
214#-> sub CPAN::Shell::AUTOLOAD ;
215sub AUTOLOAD {
216 my($autoload) = $AUTOLOAD;
c356248b 217 my $class = shift(@_);
09d9d230 218 # warn "autoload[$autoload] class[$class]";
55e314ee
AK
219 $autoload =~ s/.*:://;
220 if ($autoload =~ /^w/) {
221 if ($CPAN::META->has_inst('CPAN::WAIT')) {
c356248b 222 CPAN::WAIT->$autoload(@_);
55e314ee 223 } else {
c356248b 224 $CPAN::Frontend->mywarn(qq{
55e314ee
AK
225Commands starting with "w" require CPAN::WAIT to be installed.
226Please consider installing CPAN::WAIT to use the fulltext index.
227For this you just need to type
228 install CPAN::WAIT
c356248b 229});
55e314ee
AK
230 }
231 } else {
232 my $ok = CPAN::Shell->try_dot_al($AUTOLOAD);
233 if ($ok) {
234 goto &$AUTOLOAD;
c356248b
AK
235# } else {
236# $CPAN::Frontend->mywarn("Could not autoload $autoload");
55e314ee 237 }
c356248b
AK
238 $CPAN::Frontend->mywarn(qq{Unknown command '$autoload'. }.
239 qq{Type ? for help.
240});
55e314ee
AK
241 }
242}
243
244#-> CPAN::Shell::try_dot_al
245sub try_dot_al {
246 my($class,$autoload) = @_;
247 return unless $CPAN::Try_autoload;
248 # I don't see how to re-use that from the AutoLoader...
249 my($name,$ok);
250 # Braces used to preserve $1 et al.
251 {
252 my ($pkg,$func) = $autoload =~ /(.*)::([^:]+)$/;
253 $pkg =~ s|::|/|g;
254 if (defined($name=$INC{"$pkg.pm"}))
255 {
256 $name =~ s|^(.*)$pkg\.pm$|$1auto/$pkg/$func.al|;
257 $name = undef unless (-r $name);
258 }
259 unless (defined $name)
260 {
261 $name = "auto/$autoload.al";
262 $name =~ s|::|/|g;
263 }
264 }
265 my $save = $@;
266 eval {local $SIG{__DIE__};require $name};
267 if ($@) {
268 if (substr($autoload,-9) eq '::DESTROY') {
269 *$autoload = sub {};
270 $ok = 1;
271 } else {
272 if ($name =~ s/(\w{12,})\.al$/substr($1,0,11).".al"/e){
273 eval {local $SIG{__DIE__};require $name};
274 }
275 if ($@){
276 $@ =~ s/ at .*\n//;
277 Carp::croak $@;
278 } else {
279 $ok = 1;
280 }
281 }
282 } else {
2e2b7522 283
55e314ee 284 $ok = 1;
2e2b7522 285
55e314ee
AK
286 }
287 $@ = $save;
c356248b 288# my $lm = Carp::longmess();
55e314ee
AK
289# warn "ok[$ok] autoload[$autoload] longmess[$lm]"; # debug
290 return $ok;
291}
292
55e314ee
AK
293#### autoloader is experimental
294#### to try it we have to set $Try_autoload and uncomment
295#### the use statement and uncomment the __END__ below
296#### You also need AutoSplit 1.01 available. MakeMaker will
297#### then build CPAN with all the AutoLoad stuff.
298# use AutoLoader;
299# $Try_autoload = 1;
300
301if ($CPAN::Try_autoload) {
c356248b
AK
302 my $p;
303 for $p (qw(
55e314ee
AK
304 CPAN::Author CPAN::Bundle CPAN::CacheMgr CPAN::Complete
305 CPAN::Config CPAN::Debug CPAN::Distribution CPAN::FTP
306 CPAN::FTP::netrc CPAN::Index CPAN::InfoObj CPAN::Module
307 )) {
308 *{"$p\::AUTOLOAD"} = \&AutoLoader::AUTOLOAD;
309 }
310}
311
09d9d230
A
312package CPAN::Tarzip;
313use vars qw($AUTOLOAD @ISA);
314@CPAN::Tarzip::ISA = qw(CPAN::Debug);
315
316package CPAN::Queue;
317# currently only used to determine if we should or shouldn't announce
318# the availability of a new CPAN module
319sub new {
320 my($class,$mod) = @_;
321 # warn "Queue object for mod[$mod]";
322 bless {mod => $mod}, $class;
323}
55e314ee
AK
324
325package CPAN;
326
2e2b7522 327$META ||= CPAN->new; # In case we re-eval ourselves we need the ||
55e314ee
AK
328
329# Do this after you have set up the whole inheritance
330CPAN::Config->load unless defined $CPAN::No_Config_is_ok;
331
3321;
333
334# __END__ # uncomment this and AutoSplit version 1.01 will split it
10b2abe6
CS
335
336#-> sub CPAN::autobundle ;
5f05dabc 337sub autobundle;
10b2abe6 338#-> sub CPAN::bundle ;
5f05dabc 339sub bundle;
10b2abe6 340#-> sub CPAN::expand ;
5f05dabc 341sub expand;
10b2abe6 342#-> sub CPAN::force ;
5f05dabc 343sub force;
10b2abe6 344#-> sub CPAN::install ;
5f05dabc 345sub install;
10b2abe6 346#-> sub CPAN::make ;
5f05dabc 347sub make;
10b2abe6 348#-> sub CPAN::clean ;
5f05dabc 349sub clean;
10b2abe6 350#-> sub CPAN::test ;
5f05dabc
PP
351sub test;
352
10b2abe6 353#-> sub CPAN::all ;
5f05dabc
PP
354sub all {
355 my($mgr,$class) = @_;
356 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
357 CPAN::Index->reload;
358 values %{ $META->{$class} };
359}
360
361# Called by shell, not in batch mode. Not clean XXX
10b2abe6 362#-> sub CPAN::checklock ;
5f05dabc
PP
363sub checklock {
364 my($self) = @_;
c356248b 365 my $lockfile = MM->catfile($CPAN::Config->{cpan_home},".lock");
5f05dabc 366 if (-f $lockfile && -M _ > 0) {
da199366 367 my $fh = FileHandle->new($lockfile);
5f05dabc
PP
368 my $other = <$fh>;
369 $fh->close;
370 if (defined $other && $other) {
371 chomp $other;
372 return if $$==$other; # should never happen
c356248b
AK
373 $CPAN::Frontend->mywarn(
374 qq{
375There seems to be running another CPAN process ($other). Contacting...
376});
5f05dabc 377 if (kill 0, $other) {
c356248b
AK
378 $CPAN::Frontend->mydie(qq{Other job is running.
379You may want to kill it and delete the lockfile, maybe. On UNIX try:
380 kill $other
381 rm $lockfile
382});
5f05dabc 383 } elsif (-w $lockfile) {
e50380aa 384 my($ans) =
5f05dabc 385 ExtUtils::MakeMaker::prompt
05454584
AK
386 (qq{Other job not responding. Shall I overwrite }.
387 qq{the lockfile? (Y/N)},"y");
c356248b
AK
388 $CPAN::Frontend->myexit("Ok, bye\n")
389 unless $ans =~ /^y/i;
5f05dabc
PP
390 } else {
391 Carp::croak(
05454584
AK
392 qq{Lockfile $lockfile not writeable by you. }.
393 qq{Cannot proceed.\n}.
5f05dabc
PP
394 qq{ On UNIX try:\n}.
395 qq{ rm $lockfile\n}.
396 qq{ and then rerun us.\n}
397 );
398 }
399 }
400 }
401 File::Path::mkpath($CPAN::Config->{cpan_home});
402 my $fh;
da199366 403 unless ($fh = FileHandle->new(">$lockfile")) {
5f05dabc
PP
404 if ($! =~ /Permission/) {
405 my $incc = $INC{'CPAN/Config.pm'};
05454584 406 my $myincc = MM->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
c356248b 407 $CPAN::Frontend->myprint(qq{
5f05dabc
PP
408
409Your configuration suggests that CPAN.pm should use a working
410directory of
411 $CPAN::Config->{cpan_home}
412Unfortunately we could not create the lock file
413 $lockfile
414due to permission problems.
415
416Please make sure that the configuration variable
417 \$CPAN::Config->{cpan_home}
418points to a directory where you can write a .lock file. You can set
419this variable in either
420 $incc
421or
422 $myincc
423
c356248b 424});
5f05dabc 425 }
c356248b 426 $CPAN::Frontend->mydie("Could not open >$lockfile: $!");
5f05dabc 427 }
c356248b 428 $fh->print($$, "\n");
5f05dabc
PP
429 $self->{LOCK} = $lockfile;
430 $fh->close;
c356248b 431 $SIG{'TERM'} = sub {
2e2b7522
GS
432 &cleanup;
433 $CPAN::Frontend->mydie("Got SIGTERM, leaving");
c356248b 434 };
da199366 435 $SIG{'INT'} = sub {
09d9d230
A
436 # no blocks!!!
437 &cleanup if $Signal;
438 $CPAN::Frontend->mydie("Got another SIGINT") if $Signal;
439 print "Caught SIGINT\n";
440 $Signal++;
da199366 441 };
5f05dabc 442 $SIG{'__DIE__'} = \&cleanup;
e50380aa 443 $self->debug("Signal handler set.") if $CPAN::DEBUG;
5f05dabc
PP
444}
445
10b2abe6 446#-> sub CPAN::DESTROY ;
5f05dabc
PP
447sub DESTROY {
448 &cleanup; # need an eval?
449}
450
55e314ee
AK
451#-> sub CPAN::cwd ;
452sub cwd {Cwd::cwd();}
453
454#-> sub CPAN::getcwd ;
455sub getcwd {Cwd::getcwd();}
456
10b2abe6 457#-> sub CPAN::exists ;
5f05dabc
PP
458sub exists {
459 my($mgr,$class,$id) = @_;
460 CPAN::Index->reload;
e50380aa 461 ### Carp::croak "exists called without class argument" unless $class;
5f05dabc
PP
462 $id ||= "";
463 exists $META->{$class}{$id};
464}
465
09d9d230
A
466#-> sub CPAN::delete ;
467sub delete {
468 my($mgr,$class,$id) = @_;
469 delete $META->{$class}{$id};
470}
471
55e314ee
AK
472#-> sub CPAN::has_inst
473sub has_inst {
474 my($self,$mod,$message) = @_;
475 Carp::croak("CPAN->has_inst() called without an argument")
476 unless defined $mod;
477 if (defined $message && $message eq "no") {
478 $Dontload{$mod}||=1;
479 return 0;
480 } elsif (exists $Dontload{$mod}) {
481 return 0;
482 }
483 my $file = $mod;
c356248b 484 my $obj;
55e314ee
AK
485 $file =~ s|::|/|g;
486 $file =~ s|/|\\|g if $^O eq 'MSWin32';
487 $file .= ".pm";
c356248b 488 if ($INC{$file}) {
55e314ee
AK
489# warn "$file in %INC"; #debug
490 return 1;
55e314ee 491 } elsif (eval { require $file }) {
c356248b
AK
492 # eval is good: if we haven't yet read the database it's
493 # perfect and if we have installed the module in the meantime,
494 # it tries again. The second require is only a NOOP returning
495 # 1 if we had success, otherwise it's retrying
496 $CPAN::Frontend->myprint("CPAN: $mod loaded ok\n");
497 if ($mod eq "CPAN::WAIT") {
498 push @CPAN::Shell::ISA, CPAN::WAIT;
499 }
55e314ee
AK
500 return 1;
501 } elsif ($mod eq "Net::FTP") {
502 warn qq{
503 Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
504 if you just type
505 install Bundle::libnet
5f05dabc 506
55e314ee
AK
507};
508 sleep 2;
c356248b
AK
509 } elsif ($mod eq "MD5"){
510 $CPAN::Frontend->myprint(qq{
511 CPAN: MD5 security checks disabled because MD5 not installed.
512 Please consider installing the MD5 module.
513
514});
515 sleep 2;
05454584 516 }
55e314ee 517 return 0;
05454584
AK
518}
519
10b2abe6 520#-> sub CPAN::instance ;
5f05dabc
PP
521sub instance {
522 my($mgr,$class,$id) = @_;
523 CPAN::Index->reload;
5f05dabc
PP
524 $id ||= "";
525 $META->{$class}{$id} ||= $class->new(ID => $id );
526}
527
10b2abe6 528#-> sub CPAN::new ;
5f05dabc
PP
529sub new {
530 bless {}, shift;
531}
532
10b2abe6 533#-> sub CPAN::cleanup ;
5f05dabc 534sub cleanup {
2e2b7522
GS
535 # warn "cleanup called with arg[@_] End[$End] Signal[$Signal]";
536 local $SIG{__DIE__} = '';
537 my($message) = @_;
538 my $i = 0;
539 my $ineval = 0;
540 if (
541 0 && # disabled, try reload cpan with it
542 $] > 5.004_60 # thereabouts
543 ) {
544 $ineval = $^S;
545 } else {
546 my($subroutine);
547 while ((undef,undef,undef,$subroutine) = caller(++$i)) {
548 $ineval = 1, last if
549 $subroutine eq '(eval)';
5f05dabc 550 }
2e2b7522
GS
551 }
552 return if $ineval && !$End;
553 return unless defined $META->{'LOCK'};
554 return unless -f $META->{'LOCK'};
555 unlink $META->{'LOCK'};
556 # require Carp;
557 # Carp::cluck("DEBUGGING");
558 $CPAN::Frontend->mywarn("Lockfile removed.\n");
5f05dabc
PP
559}
560
05454584 561package CPAN::CacheMgr;
5f05dabc 562
05454584
AK
563#-> sub CPAN::CacheMgr::as_string ;
564sub as_string {
565 eval { require Data::Dumper };
566 if ($@) {
567 return shift->SUPER::as_string;
5f05dabc 568 } else {
05454584 569 return Data::Dumper::Dumper(shift);
5f05dabc
PP
570 }
571}
572
05454584
AK
573#-> sub CPAN::CacheMgr::cachesize ;
574sub cachesize {
575 shift->{DU};
5f05dabc 576}
5f05dabc 577
09d9d230
A
578sub tidyup {
579 my($self) = @_;
580 return unless -d $self->{ID};
581 while ($self->{DU} > $self->{'MAX'} ) {
582 my($toremove) = shift @{$self->{FIFO}};
583 $CPAN::Frontend->myprint(sprintf(
584 "Deleting from cache".
585 ": $toremove (%.1f>%.1f MB)\n",
586 $self->{DU}, $self->{'MAX'})
587 );
588 return if $CPAN::Signal;
589 $self->force_clean_cache($toremove);
590 return if $CPAN::Signal;
591 }
592}
5f05dabc 593
05454584
AK
594#-> sub CPAN::CacheMgr::dir ;
595sub dir {
596 shift->{ID};
597}
598
599#-> sub CPAN::CacheMgr::entries ;
600sub entries {
601 my($self,$dir) = @_;
55e314ee 602 return unless defined $dir;
e50380aa 603 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
05454584 604 $dir ||= $self->{ID};
e50380aa
AK
605 my $getcwd;
606 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
55e314ee 607 my($cwd) = CPAN->$getcwd();
05454584
AK
608 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
609 my $dh = DirHandle->new(".") or Carp::croak("Couldn't opendir $dir: $!");
610 my(@entries);
611 for ($dh->read) {
612 next if $_ eq "." || $_ eq "..";
613 if (-f $_) {
c356248b 614 push @entries, MM->catfile($dir,$_);
05454584 615 } elsif (-d _) {
c356248b 616 push @entries, MM->catdir($dir,$_);
5f05dabc 617 } else {
c356248b 618 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
5f05dabc 619 }
5f05dabc 620 }
05454584 621 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
e50380aa 622 sort { -M $b <=> -M $a} @entries;
5f05dabc
PP
623}
624
05454584
AK
625#-> sub CPAN::CacheMgr::disk_usage ;
626sub disk_usage {
627 my($self,$dir) = @_;
09d9d230
A
628 return if exists $self->{SIZE}{$dir};
629 return if $CPAN::Signal;
630 my($Du) = 0;
05454584
AK
631 find(
632 sub {
09d9d230 633 $File::Find::prune++ if $CPAN::Signal;
05454584 634 return if -l $_;
e50380aa 635 $Du += -s _;
05454584
AK
636 },
637 $dir
638 );
09d9d230 639 return if $CPAN::Signal;
05454584
AK
640 $self->{SIZE}{$dir} = $Du/1024/1024;
641 push @{$self->{FIFO}}, $dir;
642 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
643 $self->{DU} += $Du/1024/1024;
05454584 644 $self->{DU};
5f05dabc
PP
645}
646
05454584
AK
647#-> sub CPAN::CacheMgr::force_clean_cache ;
648sub force_clean_cache {
649 my($self,$dir) = @_;
09d9d230 650 return unless -e $dir;
05454584
AK
651 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
652 if $CPAN::DEBUG;
653 File::Path::rmtree($dir);
654 $self->{DU} -= $self->{SIZE}{$dir};
655 delete $self->{SIZE}{$dir};
5f05dabc
PP
656}
657
05454584
AK
658#-> sub CPAN::CacheMgr::new ;
659sub new {
660 my $class = shift;
e50380aa
AK
661 my $time = time;
662 my($debug,$t2);
663 $debug = "";
05454584
AK
664 my $self = {
665 ID => $CPAN::Config->{'build_dir'},
666 MAX => $CPAN::Config->{'build_cache'},
667 DU => 0
668 };
669 File::Path::mkpath($self->{ID});
670 my $dh = DirHandle->new($self->{ID});
671 bless $self, $class;
05454584 672 my $e;
09d9d230
A
673 $CPAN::Frontend->myprint(
674 sprintf("Scanning cache %s for sizes\n",
675 $self->{ID}));
676 for $e ($self->entries($self->{ID})) {
05454584 677 next if $e eq ".." || $e eq ".";
05454584 678 $self->disk_usage($e);
09d9d230 679 return if $CPAN::Signal;
5f05dabc 680 }
09d9d230 681 $self->tidyup;
e50380aa
AK
682 $t2 = time;
683 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
684 $time = $t2;
685 CPAN->debug($debug) if $CPAN::DEBUG;
05454584 686 $self;
5f05dabc
PP
687}
688
05454584
AK
689package CPAN::Debug;
690
691#-> sub CPAN::Debug::debug ;
692sub debug {
693 my($self,$arg) = @_;
694 my($caller,$func,$line,@rest) = caller(1); # caller(0) eg
695 # Complete, caller(1)
696 # eg readline
697 ($caller) = caller(0);
698 $caller =~ s/.*:://;
55e314ee 699 $arg = "" unless defined $arg;
c356248b 700 my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest;
05454584 701 if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){
55e314ee 702 if ($arg and ref $arg) {
05454584
AK
703 eval { require Data::Dumper };
704 if ($@) {
c356248b 705 $CPAN::Frontend->myprint($arg->as_string);
05454584 706 } else {
c356248b 707 $CPAN::Frontend->myprint(Data::Dumper::Dumper($arg));
5f05dabc
PP
708 }
709 } else {
c356248b 710 $CPAN::Frontend->myprint("Debug($caller:$func,$line,[$rest]): $arg\n");
5f05dabc 711 }
05454584
AK
712 }
713}
714
715package CPAN::Config;
05454584
AK
716
717#-> sub CPAN::Config::edit ;
718sub edit {
719 my($class,@args) = @_;
720 return unless @args;
721 CPAN->debug("class[$class]args[".join(" | ",@args)."]");
722 my($o,$str,$func,$args,$key_exists);
723 $o = shift @args;
724 if($can{$o}) {
725 $class->$o(@args);
726 return 1;
727 } else {
728 if (ref($CPAN::Config->{$o}) eq ARRAY) {
729 $func = shift @args;
730 $func ||= "";
731 # Let's avoid eval, it's easier to comprehend without.
732 if ($func eq "push") {
733 push @{$CPAN::Config->{$o}}, @args;
734 } elsif ($func eq "pop") {
735 pop @{$CPAN::Config->{$o}};
736 } elsif ($func eq "shift") {
737 shift @{$CPAN::Config->{$o}};
738 } elsif ($func eq "unshift") {
739 unshift @{$CPAN::Config->{$o}}, @args;
740 } elsif ($func eq "splice") {
741 splice @{$CPAN::Config->{$o}}, @args;
742 } elsif (@args) {
743 $CPAN::Config->{$o} = [@args];
744 } else {
c356248b
AK
745 $CPAN::Frontend->myprint(
746 join "",
747 " $o ",
748 ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$o}),
749 "\n"
05454584
AK
750 );
751 }
752 } else {
753 $CPAN::Config->{$o} = $args[0] if defined $args[0];
c356248b
AK
754 $CPAN::Frontend->myprint(" $o " .
755 (defined $CPAN::Config->{$o} ?
756 $CPAN::Config->{$o} : "UNDEFINED"));
5f05dabc 757 }
5f05dabc 758 }
05454584
AK
759}
760
761#-> sub CPAN::Config::commit ;
762sub commit {
763 my($self,$configpm) = @_;
764 unless (defined $configpm){
765 $configpm ||= $INC{"CPAN/MyConfig.pm"};
766 $configpm ||= $INC{"CPAN/Config.pm"};
2e2b7522 767 $configpm || Carp::confess(q{
05454584
AK
768CPAN::Config::commit called without an argument.
769Please specify a filename where to save the configuration or try
770"o conf init" to have an interactive course through configing.
771});
772 }
773 my($mode);
774 if (-f $configpm) {
775 $mode = (stat $configpm)[2];
776 if ($mode && ! -w _) {
777 Carp::confess("$configpm is not writable");
5f05dabc
PP
778 }
779 }
05454584
AK
780
781 my $msg = <<EOF unless $configpm =~ /MyConfig/;
782
09d9d230 783# This is CPAN.pm's systemwide configuration file. This file provides
55e314ee
AK
784# defaults for users, and the values can be changed in a per-user
785# configuration file. The user-config file is being looked for as
786# ~/.cpan/CPAN/MyConfig.pm.
05454584
AK
787
788EOF
789 $msg ||= "\n";
790 my($fh) = FileHandle->new;
791 open $fh, ">$configpm" or warn "Couldn't open >$configpm: $!";
c356248b 792 $fh->print(qq[$msg\$CPAN::Config = \{\n]);
05454584
AK
793 foreach (sort keys %$CPAN::Config) {
794 $fh->print(
795 " '$_' => ",
796 ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$_}),
797 ",\n"
798 );
5f05dabc 799 }
05454584 800
c356248b 801 $fh->print("};\n1;\n__END__\n");
05454584
AK
802 close $fh;
803
804 #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
805 #chmod $mode, $configpm;
e50380aa 806###why was that so? $self->defaults;
c356248b 807 $CPAN::Frontend->myprint("commit: wrote $configpm\n");
05454584 808 1;
5f05dabc
PP
809}
810
05454584
AK
811*default = \&defaults;
812#-> sub CPAN::Config::defaults ;
813sub defaults {
814 my($self) = @_;
815 $self->unload;
816 $self->load;
817 1;
5f05dabc
PP
818}
819
05454584
AK
820sub init {
821 my($self) = @_;
822 undef $CPAN::Config->{'inhibit_startup_message'}; # lazy trick to
823 # have the least
824 # important
825 # variable
826 # undefined
827 $self->load;
828 1;
5f05dabc
PP
829}
830
05454584
AK
831#-> sub CPAN::Config::load ;
832sub load {
e50380aa
AK
833 my($self) = shift;
834 my(@miss);
c356248b
AK
835 eval {require CPAN::Config;}; # We eval because of some
836 # MakeMaker problems
09d9d230
A
837 unless ($dot_cpan++){
838 unshift @INC, MM->catdir($ENV{HOME},".cpan");
839 eval {require CPAN::MyConfig;}; # where you can override
c356248b 840 # system wide settings
09d9d230
A
841 shift @INC;
842 }
e50380aa 843 return unless @miss = $self->not_loaded;
c356248b 844 # XXX better check for arrayrefs too
e50380aa 845 require CPAN::FirstTime;
55e314ee 846 my($configpm,$fh,$redo,$theycalled);
e50380aa 847 $redo ||= "";
55e314ee 848 $theycalled++ if @miss==1 && $miss[0] eq 'inhibit_startup_message';
e50380aa
AK
849 if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
850 $configpm = $INC{"CPAN/Config.pm"};
851 $redo++;
852 } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
853 $configpm = $INC{"CPAN/MyConfig.pm"};
854 $redo++;
855 } else {
856 my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
857 my($configpmdir) = MM->catdir($path_to_cpan,"CPAN");
858 my($configpmtest) = MM->catfile($configpmdir,"Config.pm");
859 if (-d $configpmdir or File::Path::mkpath($configpmdir)) {
860 if (-w $configpmtest) {
861 $configpm = $configpmtest;
862 } elsif (-w $configpmdir) {
863 #_#_# following code dumped core on me with 5.003_11, a.k.
864 unlink "$configpmtest.bak" if -f "$configpmtest.bak";
865 rename $configpmtest, "$configpmtest.bak" if -f $configpmtest;
866 my $fh = FileHandle->new;
867 if ($fh->open(">$configpmtest")) {
868 $fh->print("1;\n");
869 $configpm = $configpmtest;
870 } else {
871 # Should never happen
872 Carp::confess("Cannot open >$configpmtest");
873 }
874 }
875 }
876 unless ($configpm) {
877 $configpmdir = MM->catdir($ENV{HOME},".cpan","CPAN");
878 File::Path::mkpath($configpmdir);
879 $configpmtest = MM->catfile($configpmdir,"MyConfig.pm");
880 if (-w $configpmtest) {
881 $configpm = $configpmtest;
882 } elsif (-w $configpmdir) {
883 #_#_# following code dumped core on me with 5.003_11, a.k.
884 my $fh = FileHandle->new;
885 if ($fh->open(">$configpmtest")) {
886 $fh->print("1;\n");
887 $configpm = $configpmtest;
888 } else {
889 # Should never happen
890 Carp::confess("Cannot open >$configpmtest");
891 }
892 } else {
893 Carp::confess(qq{WARNING: CPAN.pm is unable to }.
894 qq{create a configuration file.});
895 }
896 }
897 }
898 local($") = ", ";
c356248b 899 $CPAN::Frontend->myprint(qq{
e50380aa
AK
900We have to reconfigure CPAN.pm due to following uninitialized parameters:
901
902@miss
c356248b
AK
903}) if $redo && ! $theycalled;
904 $CPAN::Frontend->myprint(qq{
05454584 905$configpm initialized.
c356248b 906});
e50380aa
AK
907 sleep 2;
908 CPAN::FirstTime::init($configpm);
5f05dabc
PP
909}
910
e50380aa
AK
911#-> sub CPAN::Config::not_loaded ;
912sub not_loaded {
913 my(@miss);
05454584
AK
914 for (qw(
915 cpan_home keep_source_where build_dir build_cache index_expire
916 gzip tar unzip make pager makepl_arg make_arg make_install_arg
917 urllist inhibit_startup_message ftp_proxy http_proxy no_proxy
918 )) {
e50380aa 919 push @miss, $_ unless defined $CPAN::Config->{$_};
5f05dabc 920 }
e50380aa 921 return @miss;
5f05dabc
PP
922}
923
05454584
AK
924#-> sub CPAN::Config::unload ;
925sub unload {
926 delete $INC{'CPAN/MyConfig.pm'};
927 delete $INC{'CPAN/Config.pm'};
5f05dabc
PP
928}
929
05454584
AK
930#-> sub CPAN::Config::help ;
931sub help {
2e2b7522 932 $CPAN::Frontend->myprint(q[
05454584
AK
933Known options:
934 defaults reload default config values from disk
935 commit commit session changes to disk
936 init go through a dialog to set all parameters
5f05dabc 937
05454584 938You may edit key values in the follow fashion:
5f05dabc 939
05454584 940 o conf build_cache 15
5f05dabc 941
05454584 942 o conf build_dir "/foo/bar"
5f05dabc 943
05454584 944 o conf urllist shift
5f05dabc 945
05454584 946 o conf urllist unshift ftp://ftp.foo.bar/
5f05dabc 947
2e2b7522 948]);
05454584
AK
949 undef; #don't reprint CPAN::Config
950}
5f05dabc 951
55e314ee
AK
952#-> sub CPAN::Config::cpl ;
953sub cpl {
05454584
AK
954 my($word,$line,$pos) = @_;
955 $word ||= "";
c356248b
AK
956 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
957 my(@words) = split " ", substr($line,0,$pos+1);
958 if (
09d9d230
A
959 defined($words[2])
960 and
961 (
962 $words[2] =~ /list$/ && @words == 3
963 ||
964 $words[2] =~ /list$/ && @words == 4 && length($word)
965 )
c356248b
AK
966 ) {
967 return grep /^\Q$word\E/, qw(splice shift unshift pop push);
968 } elsif (@words >= 4) {
969 return ();
970 }
05454584
AK
971 my(@o_conf) = (keys %CPAN::Config::can, keys %$CPAN::Config);
972 return grep /^\Q$word\E/, @o_conf;
973}
974
975package CPAN::Shell;
5f05dabc 976
05454584
AK
977#-> sub CPAN::Shell::h ;
978sub h {
979 my($class,$about) = @_;
980 if (defined $about) {
c356248b 981 $CPAN::Frontend->myprint("Detailed help not yet implemented\n");
05454584 982 } else {
c356248b 983 $CPAN::Frontend->myprint(q{
05454584
AK
984command arguments description
985a string authors
986b or display bundles
987d /regex/ info distributions
988m or about modules
989i none anything of above
da199366 990
05454584
AK
991r as reinstall recommendations
992u above uninstalled distributions
993See manpage for autobundle, recompile, force, look, etc.
da199366 994
05454584
AK
995make make
996test modules, make test (implies make)
997install dists, bundles, make install (implies test)
998clean "r" or "u" make clean
999readme display the README file
da199366 1000
05454584
AK
1001reload index|cpan load most recent indices/CPAN.pm
1002h or ? display this menu
1003o various set and query options
1004! perl-code eval a perl command
1005q quit the shell subroutine
c356248b 1006});
05454584
AK
1007 }
1008}
da199366 1009
09d9d230
A
1010*help = \&h;
1011
05454584 1012#-> sub CPAN::Shell::a ;
c356248b 1013sub a { $CPAN::Frontend->myprint(shift->format_result('Author',@_));}
05454584
AK
1014#-> sub CPAN::Shell::b ;
1015sub b {
1016 my($self,@which) = @_;
1017 CPAN->debug("which[@which]") if $CPAN::DEBUG;
55e314ee 1018 my($incdir,$bdir,$dh);
05454584 1019 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
c356248b 1020 $bdir = MM->catdir($incdir,"Bundle");
05454584
AK
1021 if ($dh = DirHandle->new($bdir)) { # may fail
1022 my($entry);
1023 for $entry ($dh->read) {
c356248b 1024 next if -d MM->catdir($bdir,$entry);
05454584
AK
1025 next unless $entry =~ s/\.pm$//;
1026 $CPAN::META->instance('CPAN::Bundle',"Bundle::$entry");
1027 }
1028 }
1029 }
c356248b 1030 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
05454584
AK
1031}
1032#-> sub CPAN::Shell::d ;
c356248b 1033sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
05454584 1034#-> sub CPAN::Shell::m ;
c356248b 1035sub m { $CPAN::Frontend->myprint(shift->format_result('Module',@_));}
da199366 1036
05454584
AK
1037#-> sub CPAN::Shell::i ;
1038sub i {
1039 my($self) = shift;
1040 my(@args) = @_;
1041 my(@type,$type,@m);
1042 @type = qw/Author Bundle Distribution Module/;
1043 @args = '/./' unless @args;
1044 my(@result);
1045 for $type (@type) {
1046 push @result, $self->expand($type,@args);
1047 }
e50380aa 1048 my $result = @result == 1 ?
05454584
AK
1049 $result[0]->as_string :
1050 join "", map {$_->as_glimpse} @result;
1051 $result ||= "No objects found of any type for argument @args\n";
c356248b 1052 $CPAN::Frontend->myprint($result);
da199366 1053}
da199366 1054
05454584
AK
1055#-> sub CPAN::Shell::o ;
1056sub o {
1057 my($self,$o_type,@o_what) = @_;
1058 $o_type ||= "";
1059 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
1060 if ($o_type eq 'conf') {
1061 shift @o_what if @o_what && $o_what[0] eq 'help';
1062 if (!@o_what) {
1063 my($k,$v);
09d9d230
A
1064 $CPAN::Frontend->myprint("CPAN::Config options");
1065 if (exists $INC{'CPAN/Config.pm'}) {
1066 $CPAN::Frontend->myprint(" from $INC{'CPAN/Config.pm'}");
1067 }
1068 if (exists $INC{'CPAN/MyConfig.pm'}) {
1069 $CPAN::Frontend->myprint(" and $INC{'CPAN/MyConfig.pm'}");
1070 }
1071 $CPAN::Frontend->myprint(":\n");
05454584
AK
1072 for $k (sort keys %CPAN::Config::can) {
1073 $v = $CPAN::Config::can{$k};
c356248b 1074 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
05454584 1075 }
c356248b 1076 $CPAN::Frontend->myprint("\n");
05454584
AK
1077 for $k (sort keys %$CPAN::Config) {
1078 $v = $CPAN::Config->{$k};
1079 if (ref $v) {
c356248b
AK
1080 $CPAN::Frontend->myprint(
1081 join(
1082 "",
1083 sprintf(
1084 " %-18s\n",
1085 $k
1086 ),
1087 map {"\t$_\n"} @{$v}
1088 )
1089 );
10b2abe6 1090 } else {
c356248b 1091 $CPAN::Frontend->myprint(sprintf " %-18s %s\n", $k, $v);
da199366 1092 }
10b2abe6 1093 }
c356248b 1094 $CPAN::Frontend->myprint("\n");
05454584 1095 } elsif (!CPAN::Config->edit(@o_what)) {
c356248b 1096 $CPAN::Frontend->myprint(qq[Type 'o conf' to view configuration edit options\n\n]);
5f05dabc 1097 }
05454584
AK
1098 } elsif ($o_type eq 'debug') {
1099 my(%valid);
1100 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
1101 if (@o_what) {
1102 while (@o_what) {
1103 my($what) = shift @o_what;
1104 if ( exists $CPAN::DEBUG{$what} ) {
1105 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
1106 } elsif ($what =~ /^\d/) {
1107 $CPAN::DEBUG = $what;
1108 } elsif (lc $what eq 'all') {
1109 my($max) = 0;
1110 for (values %CPAN::DEBUG) {
1111 $max += $_;
10b2abe6 1112 }
05454584 1113 $CPAN::DEBUG = $max;
10b2abe6 1114 } else {
d4fd5c69 1115 my($known) = 0;
05454584
AK
1116 for (keys %CPAN::DEBUG) {
1117 next unless lc($_) eq lc($what);
1118 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
d4fd5c69 1119 $known = 1;
10b2abe6 1120 }
c356248b
AK
1121 $CPAN::Frontend->myprint("unknown argument [$what]\n")
1122 unless $known;
10b2abe6
CS
1123 }
1124 }
05454584 1125 } else {
c356248b
AK
1126 $CPAN::Frontend->myprint("Valid options for debug are ".
1127 join(", ",sort(keys %CPAN::DEBUG), 'all').
05454584 1128 qq{ or a number. Completion works on the options. }.
c356248b 1129 qq{Case is ignored.\n\n});
05454584
AK
1130 }
1131 if ($CPAN::DEBUG) {
c356248b 1132 $CPAN::Frontend->myprint("Options set for debugging:\n");
05454584
AK
1133 my($k,$v);
1134 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
1135 $v = $CPAN::DEBUG{$k};
c356248b 1136 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v) if $v & $CPAN::DEBUG;
05454584
AK
1137 }
1138 } else {
c356248b 1139 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
10b2abe6 1140 }
05454584 1141 } else {
c356248b 1142 $CPAN::Frontend->myprint(qq{
05454584
AK
1143Known options:
1144 conf set or get configuration variables
1145 debug set or get debugging options
c356248b 1146});
5f05dabc 1147 }
5f05dabc
PP
1148}
1149
05454584
AK
1150#-> sub CPAN::Shell::reload ;
1151sub reload {
d4fd5c69
AK
1152 my($self,$command,@arg) = @_;
1153 $command ||= "";
1154 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
1155 if ($command =~ /cpan/i) {
05454584
AK
1156 CPAN->debug("reloading the whole CPAN.pm") if $CPAN::DEBUG;
1157 my $fh = FileHandle->new($INC{'CPAN.pm'});
1158 local($/);
05454584
AK
1159 $redef = 0;
1160 local($SIG{__WARN__})
1161 = sub {
2e2b7522
GS
1162 if ( $_[0] =~ /Subroutine (\w+) redefined/ ) {
1163 my($subr) = $1;
1164 ++$redef;
1165 local($|) = 1;
1166 # $CPAN::Frontend->myprint(".($subr)");
1167 $CPAN::Frontend->myprint(".");
1168 return;
05454584
AK
1169 }
1170 warn @_;
1171 };
1172 eval <$fh>;
1173 warn $@ if $@;
c356248b 1174 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
d4fd5c69 1175 } elsif ($command =~ /index/) {
2e2b7522 1176 CPAN::Index->force_reload;
d4fd5c69 1177 } else {
2e2b7522 1178 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN.pm file
c356248b
AK
1179index re-reads the index files
1180});
05454584
AK
1181 }
1182}
1183
1184#-> sub CPAN::Shell::_binary_extensions ;
1185sub _binary_extensions {
1186 my($self) = shift @_;
1187 my(@result,$module,%seen,%need,$headerdone);
e04b929a 1188 my $isaperl = q{perl5[._-]\\d{3}(_[0-4][0-9])?\\.tar[._-]gz$};
05454584
AK
1189 for $module ($self->expand('Module','/./')) {
1190 my $file = $module->cpan_file;
1191 next if $file eq "N/A";
1192 next if $file =~ /^Contact Author/;
c356248b 1193 next if $file =~ / $isaperl /xo;
05454584
AK
1194 next unless $module->xs_file;
1195 local($|) = 1;
c356248b 1196 $CPAN::Frontend->myprint(".");
05454584
AK
1197 push @result, $module;
1198 }
1199# print join " | ", @result;
c356248b 1200 $CPAN::Frontend->myprint("\n");
05454584
AK
1201 return @result;
1202}
1203
1204#-> sub CPAN::Shell::recompile ;
1205sub recompile {
1206 my($self) = shift @_;
1207 my($module,@module,$cpan_file,%dist);
1208 @module = $self->_binary_extensions();
c356248b
AK
1209 for $module (@module){ # we force now and compile later, so we
1210 # don't do it twice
05454584
AK
1211 $cpan_file = $module->cpan_file;
1212 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1213 $pack->force;
1214 $dist{$cpan_file}++;
1215 }
1216 for $cpan_file (sort keys %dist) {
c356248b 1217 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
05454584
AK
1218 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1219 $pack->install;
1220 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
1221 # stop a package from recompiling,
1222 # e.g. IO-1.12 when we have perl5.003_10
1223 }
1224}
1225
1226#-> sub CPAN::Shell::_u_r_common ;
1227sub _u_r_common {
1228 my($self) = shift @_;
1229 my($what) = shift @_;
1230 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
1231 Carp::croak "Usage: \$obj->_u_r_common($what)" unless defined $what;
1232 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless $what =~ /^[aru]$/;
1233 my(@args) = @_;
1234 @args = '/./' unless @args;
c356248b
AK
1235 my(@result,$module,%seen,%need,$headerdone,
1236 $version_undefs,$version_zeroes);
1237 $version_undefs = $version_zeroes = 0;
05454584
AK
1238 my $sprintf = "%-25s %9s %9s %s\n";
1239 for $module ($self->expand('Module',@args)) {
1240 my $file = $module->cpan_file;
1241 next unless defined $file; # ??
c356248b 1242 my($latest) = $module->cpan_version;
05454584
AK
1243 my($inst_file) = $module->inst_file;
1244 my($have);
09d9d230 1245 return if $CPAN::Signal;
05454584
AK
1246 if ($inst_file){
1247 if ($what eq "a") {
1248 $have = $module->inst_version;
1249 } elsif ($what eq "r") {
1250 $have = $module->inst_version;
1251 local($^W) = 0;
c356248b
AK
1252 if ($have eq "undef"){
1253 $version_undefs++;
1254 } elsif ($have == 0){
1255 $version_zeroes++;
1256 }
05454584 1257 next if $have >= $latest;
c356248b
AK
1258# to be pedantic we should probably say:
1259# && !($have eq "undef" && $latest ne "undef" && $latest gt "");
1260# to catch the case where CPAN has a version 0 and we have a version undef
05454584
AK
1261 } elsif ($what eq "u") {
1262 next;
1263 }
1264 } else {
1265 if ($what eq "a") {
1266 next;
1267 } elsif ($what eq "r") {
1268 next;
1269 } elsif ($what eq "u") {
1270 $have = "-";
1271 }
1272 }
1273 return if $CPAN::Signal; # this is sometimes lengthy
1274 $seen{$file} ||= 0;
1275 if ($what eq "a") {
1276 push @result, sprintf "%s %s\n", $module->id, $have;
1277 } elsif ($what eq "r") {
1278 push @result, $module->id;
1279 next if $seen{$file}++;
1280 } elsif ($what eq "u") {
1281 push @result, $module->id;
1282 next if $seen{$file}++;
1283 next if $file =~ /^Contact/;
1284 }
1285 unless ($headerdone++){
c356248b
AK
1286 $CPAN::Frontend->myprint("\n");
1287 $CPAN::Frontend->myprint(sprintf(
05454584
AK
1288 $sprintf,
1289 "Package namespace",
1290 "installed",
1291 "latest",
1292 "in CPAN file"
c356248b 1293 ));
05454584
AK
1294 }
1295 $latest = substr($latest,0,8) if length($latest) > 8;
1296 $have = substr($have,0,8) if length($have) > 8;
c356248b 1297 $CPAN::Frontend->myprint(sprintf $sprintf, $module->id, $have, $latest, $file);
05454584
AK
1298 $need{$module->id}++;
1299 }
1300 unless (%need) {
1301 if ($what eq "u") {
c356248b 1302 $CPAN::Frontend->myprint("No modules found for @args\n");
05454584 1303 } elsif ($what eq "r") {
c356248b 1304 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
05454584
AK
1305 }
1306 }
c356248b
AK
1307 if ($what eq "r") {
1308 if ($version_zeroes) {
1309 my $s_has = $version_zeroes > 1 ? "s have" : " has";
1310 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
1311 qq{a version number of 0\n});
1312 }
1313 if ($version_undefs) {
1314 my $s_has = $version_undefs > 1 ? "s have" : " has";
1315 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1316 qq{parseable version number\n});
1317 }
05454584
AK
1318 }
1319 @result;
1320}
1321
1322#-> sub CPAN::Shell::r ;
1323sub r {
1324 shift->_u_r_common("r",@_);
1325}
1326
1327#-> sub CPAN::Shell::u ;
1328sub u {
1329 shift->_u_r_common("u",@_);
1330}
1331
1332#-> sub CPAN::Shell::autobundle ;
1333sub autobundle {
1334 my($self) = shift;
1335 my(@bundle) = $self->_u_r_common("a",@_);
c356248b 1336 my($todir) = MM->catdir($CPAN::Config->{'cpan_home'},"Bundle");
05454584
AK
1337 File::Path::mkpath($todir);
1338 unless (-d $todir) {
c356248b 1339 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
05454584
AK
1340 return;
1341 }
1342 my($y,$m,$d) = (localtime)[5,4,3];
1343 $y+=1900;
1344 $m++;
1345 my($c) = 0;
1346 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
c356248b 1347 my($to) = MM->catfile($todir,"$me.pm");
05454584
AK
1348 while (-f $to) {
1349 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
c356248b 1350 $to = MM->catfile($todir,"$me.pm");
05454584
AK
1351 }
1352 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1353 $fh->print(
1354 "package Bundle::$me;\n\n",
1355 "\$VERSION = '0.01';\n\n",
1356 "1;\n\n",
1357 "__END__\n\n",
1358 "=head1 NAME\n\n",
1359 "Bundle::$me - Snapshot of installation on ",
1360 $Config::Config{'myhostname'},
1361 " on ",
1362 scalar(localtime),
1363 "\n\n=head1 SYNOPSIS\n\n",
1364 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1365 "=head1 CONTENTS\n\n",
1366 join("\n", @bundle),
1367 "\n\n=head1 CONFIGURATION\n\n",
1368 Config->myconfig,
1369 "\n\n=head1 AUTHOR\n\n",
1370 "This Bundle has been generated automatically ",
1371 "by the autobundle routine in CPAN.pm.\n",
1372 );
1373 $fh->close;
c356248b
AK
1374 $CPAN::Frontend->myprint("\nWrote bundle file
1375 $to\n\n");
05454584
AK
1376}
1377
1378#-> sub CPAN::Shell::expand ;
1379sub expand {
1380 shift;
1381 my($type,@args) = @_;
1382 my($arg,@m);
1383 for $arg (@args) {
1384 my $regex;
1385 if ($arg =~ m|^/(.*)/$|) {
1386 $regex = $1;
1387 }
1388 my $class = "CPAN::$type";
1389 my $obj;
1390 if (defined $regex) {
1391 for $obj ( sort {$a->id cmp $b->id} $CPAN::META->all($class)) {
1392 push @m, $obj
1393 if
1394 $obj->id =~ /$regex/i
1395 or
1396 (
1397 (
1398 $] < 5.00303 ### provide sort of compatibility with 5.003
1399 ||
1400 $obj->can('name')
1401 )
1402 &&
1403 $obj->name =~ /$regex/i
1404 );
1405 }
1406 } else {
1407 my($xarg) = $arg;
1408 if ( $type eq 'Bundle' ) {
1409 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1410 }
1411 if ($CPAN::META->exists($class,$xarg)) {
1412 $obj = $CPAN::META->instance($class,$xarg);
1413 } elsif ($CPAN::META->exists($class,$arg)) {
1414 $obj = $CPAN::META->instance($class,$arg);
1415 } else {
1416 next;
1417 }
1418 push @m, $obj;
1419 }
1420 }
e50380aa 1421 return wantarray ? @m : $m[0];
05454584
AK
1422}
1423
1424#-> sub CPAN::Shell::format_result ;
1425sub format_result {
1426 my($self) = shift;
1427 my($type,@args) = @_;
1428 @args = '/./' unless @args;
1429 my(@result) = $self->expand($type,@args);
e50380aa 1430 my $result = @result == 1 ?
05454584
AK
1431 $result[0]->as_string :
1432 join "", map {$_->as_glimpse} @result;
1433 $result ||= "No objects of type $type found for argument @args\n";
1434 $result;
1435}
1436
c356248b
AK
1437# The only reason for this method is currently to have a reliable
1438# debugging utility that reveals which output is going through which
1439# channel. No, I don't like the colors ;-)
1440sub print_ornamented {
1441 my($self,$what,$ornament) = @_;
1442 my $longest = 0;
1443 my $ornamenting = 0; # turn the colors on
1444
1445 if ($ornamenting) {
1446 unless (defined &color) {
1447 if ($CPAN::META->has_inst("Term::ANSIColor")) {
1448 import Term::ANSIColor "color";
1449 } else {
1450 *color = sub { return "" };
1451 }
1452 }
09d9d230
A
1453 my $line;
1454 for $line (split /\n/, $what) {
c356248b
AK
1455 $longest = length($line) if length($line) > $longest;
1456 }
1457 my $sprintf = "%-" . $longest . "s";
1458 while ($what){
1459 $what =~ s/(.*\n?)//m;
1460 my $line = $1;
1461 last unless $line;
1462 my($nl) = chomp $line ? "\n" : "";
1463 # print "line[$line]ornament[$ornament]sprintf[$sprintf]\n";
1464 print color($ornament), sprintf($sprintf,$line), color("reset"), $nl;
1465 }
1466 } else {
1467 print $what;
1468 }
1469}
1470
1471sub myprint {
1472 my($self,$what) = @_;
1473 $self->print_ornamented($what, 'bold blue on_yellow');
1474}
1475
1476sub myexit {
1477 my($self,$what) = @_;
1478 $self->myprint($what);
1479 exit;
1480}
1481
1482sub mywarn {
1483 my($self,$what) = @_;
1484 $self->print_ornamented($what, 'bold red on_yellow');
1485}
1486
1487sub myconfess {
1488 my($self,$what) = @_;
1489 $self->print_ornamented($what, 'bold red on_white');
1490 Carp::confess "died";
1491}
1492
1493sub mydie {
1494 my($self,$what) = @_;
1495 $self->print_ornamented($what, 'bold red on_white');
1496 die "\n";
1497}
1498
05454584 1499#-> sub CPAN::Shell::rematein ;
09d9d230 1500# RE-adme||MA-ke||TE-st||IN-stall
05454584
AK
1501sub rematein {
1502 shift;
1503 my($meth,@some) = @_;
1504 my $pragma = "";
1505 if ($meth eq 'force') {
1506 $pragma = $meth;
1507 $meth = shift @some;
1508 }
1509 CPAN->debug("pragma[$pragma]meth[$meth] some[@some]") if $CPAN::DEBUG;
1510 my($s,@s);
1511 foreach $s (@some) {
1512 my $obj;
1513 if (ref $s) {
1514 $obj = $s;
1515 } elsif ($s =~ m|/|) { # looks like a file
1516 $obj = $CPAN::META->instance('CPAN::Distribution',$s);
1517 } elsif ($s =~ m|^Bundle::|) {
09d9d230 1518 $CPAN::META->{'CPAN::Queue'}{$s} ||= CPAN::Queue->new($s);
05454584
AK
1519 $obj = $CPAN::META->instance('CPAN::Bundle',$s);
1520 } else {
09d9d230 1521 $CPAN::META->{'CPAN::Queue'}{$s} ||= CPAN::Queue->new($s);
05454584
AK
1522 $obj = $CPAN::META->instance('CPAN::Module',$s)
1523 if $CPAN::META->exists('CPAN::Module',$s);
1524 }
1525 if (ref $obj) {
1526 CPAN->debug(
1527 qq{pragma[$pragma] meth[$meth] obj[$obj] as_string\[}.
1528 $obj->as_string.
1529 qq{\]}
1530 ) if $CPAN::DEBUG;
1531 $obj->$pragma()
1532 if
1533 $pragma
1534 &&
09d9d230
A
1535 ($] < 5.00303 || $obj->can($pragma)); ###
1536 ### compatibility
1537 ### with
1538 ### 5.003
1539 if ($]>=5.00303 && $obj->can('called_for')) {
1540 $obj->called_for($s);
1541 }
05454584
AK
1542 $obj->$meth();
1543 } elsif ($CPAN::META->exists('CPAN::Author',$s)) {
1544 $obj = $CPAN::META->instance('CPAN::Author',$s);
c356248b
AK
1545 $CPAN::Frontend->myprint(
1546 join "",
1547 "Don't be silly, you can't $meth ",
1548 $obj->fullname,
1549 " ;-)\n"
1550 );
05454584 1551 } else {
c356248b 1552 $CPAN::Frontend->myprint(qq{Warning: Cannot $meth $s, don\'t know what it is.
e50380aa
AK
1553Try the command
1554
1555 i /$s/
1556
1557to find objects with similar identifiers.
c356248b 1558});
05454584
AK
1559 }
1560 }
1561}
1562
1563#-> sub CPAN::Shell::force ;
1564sub force { shift->rematein('force',@_); }
1565#-> sub CPAN::Shell::get ;
1566sub get { shift->rematein('get',@_); }
1567#-> sub CPAN::Shell::readme ;
1568sub readme { shift->rematein('readme',@_); }
1569#-> sub CPAN::Shell::make ;
1570sub make { shift->rematein('make',@_); }
1571#-> sub CPAN::Shell::test ;
1572sub test { shift->rematein('test',@_); }
1573#-> sub CPAN::Shell::install ;
1574sub install { shift->rematein('install',@_); }
1575#-> sub CPAN::Shell::clean ;
1576sub clean { shift->rematein('clean',@_); }
1577#-> sub CPAN::Shell::look ;
1578sub look { shift->rematein('look',@_); }
1579
1580package CPAN::FTP;
05454584
AK
1581
1582#-> sub CPAN::FTP::ftp_get ;
1583sub ftp_get {
2e2b7522
GS
1584 my($class,$host,$dir,$file,$target) = @_;
1585 $class->debug(
1586 qq[Going to fetch file [$file] from dir [$dir]
05454584
AK
1587 on host [$host] as local [$target]\n]
1588 ) if $CPAN::DEBUG;
2e2b7522
GS
1589 my $ftp = Net::FTP->new($host);
1590 return 0 unless defined $ftp;
1591 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
1592 $class->debug(qq[Going to ->login("anonymous","$Config::Config{'cf_email'}")\n]);
1593 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
1594 warn "Couldn't login on $host";
1595 return;
1596 }
1597 unless ( $ftp->cwd($dir) ){
1598 warn "Couldn't cwd $dir";
1599 return;
1600 }
1601 $ftp->binary;
1602 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
1603 unless ( $ftp->get($file,$target) ){
1604 warn "Couldn't fetch $file from $host\n";
1605 return;
1606 }
1607 $ftp->quit; # it's ok if this fails
1608 return 1;
05454584
AK
1609}
1610
09d9d230
A
1611# If more accuracy is wanted/needed, Chris Leach sent me this patch...
1612
1613 # leach,> *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
1614 # leach,> --- /tmp/cp Wed Sep 24 13:26:40 1997
1615 # leach,> ***************
1616 # leach,> *** 1562,1567 ****
1617 # leach,> --- 1562,1580 ----
1618 # leach,> return 1 if substr($url,0,4) eq "file";
1619 # leach,> return 1 unless $url =~ m|://([^/]+)|;
1620 # leach,> my $host = $1;
1621 # leach,> + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
1622 # leach,> + if ($proxy) {
1623 # leach,> + $proxy =~ m|://([^/:]+)|;
1624 # leach,> + $proxy = $1;
1625 # leach,> + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
1626 # leach,> + if ($noproxy) {
1627 # leach,> + if ($host !~ /$noproxy$/) {
1628 # leach,> + $host = $proxy;
1629 # leach,> + }
1630 # leach,> + } else {
1631 # leach,> + $host = $proxy;
1632 # leach,> + }
1633 # leach,> + }
1634 # leach,> require Net::Ping;
1635 # leach,> return 1 unless $Net::Ping::VERSION >= 2;
1636 # leach,> my $p;
1637
1638
1639# this is quite optimistic and returns one on several occasions where
1640# inappropriate. But this does no harm. It would do harm if we were
1641# too pessimistic (as I was before the http_proxy
c356248b
AK
1642sub is_reachable {
1643 my($self,$url) = @_;
1644 return 1; # we can't simply roll our own, firewalls may break ping
1645 return 0 unless $url;
1646 return 1 if substr($url,0,4) eq "file";
09d9d230
A
1647 return 1 unless $url =~ m|^(\w+)://([^/]+)|;
1648 my $proxytype = $1 . "_proxy"; # ftp_proxy or http_proxy
1649 my $host = $2;
1650 return 1 if $CPAN::Config->{$proxytype} || $ENV{$proxytype};
c356248b
AK
1651 require Net::Ping;
1652 return 1 unless $Net::Ping::VERSION >= 2;
1653 my $p;
09d9d230
A
1654 # 1.3101 had it different: only if the first eval raised an
1655 # exception we tried it with TCP. Now we are happy if icmp wins
1656 # the order and return, we don't even check for $@. Thanks to
1657 # thayer@uis.edu for the suggestion.
c356248b 1658 eval {$p = Net::Ping->new("icmp");};
09d9d230
A
1659 return 1 if $p && ref($p) && $p->ping($host, 10);
1660 eval {$p = Net::Ping->new("tcp");};
c356248b 1661 $CPAN::Frontend->mydie($@) if $@;
09d9d230 1662 return $p->ping($host, 10);
c356248b
AK
1663}
1664
05454584 1665#-> sub CPAN::FTP::localize ;
55e314ee
AK
1666# sorry for the ugly code here, I'll clean it up as soon as Net::FTP
1667# is in the core
05454584
AK
1668sub localize {
1669 my($self,$file,$aslocal,$force) = @_;
1670 $force ||= 0;
1671 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])"
1672 unless defined $aslocal;
55e314ee
AK
1673 $self->debug("file[$file] aslocal[$aslocal] force[$force]")
1674 if $CPAN::DEBUG;
05454584 1675
c356248b 1676 return $aslocal if -f $aslocal && -r _ && !($force & 1);
55e314ee
AK
1677 my($restore) = 0;
1678 if (-f $aslocal){
1679 rename $aslocal, "$aslocal.bak";
1680 $restore++;
1681 }
05454584
AK
1682
1683 my($aslocal_dir) = File::Basename::dirname($aslocal);
1684 File::Path::mkpath($aslocal_dir);
c356248b 1685 $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
05454584 1686 qq{directory "$aslocal_dir".
c356248b
AK
1687 I\'ll continue, but if you encounter problems, they may be due
1688 to insufficient permissions.\n}) unless -w $aslocal_dir;
05454584
AK
1689
1690 # Inheritance is not easier to manage than a few if/else branches
55e314ee 1691 if ($CPAN::META->has_inst('LWP')) {
05454584
AK
1692 require LWP::UserAgent;
1693 unless ($Ua) {
55e314ee 1694 $Ua = LWP::UserAgent->new;
05454584
AK
1695 my($var);
1696 $Ua->proxy('ftp', $var)
1697 if $var = $CPAN::Config->{'ftp_proxy'} || $ENV{'ftp_proxy'};
1698 $Ua->proxy('http', $var)
1699 if $var = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
1700 $Ua->no_proxy($var)
1701 if $var = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
1702 }
1703 }
1704
1705 # Try the list of urls for each single object. We keep a record
1706 # where we did get a file from
c356248b 1707 my(@reordered,$last);
09d9d230 1708 $CPAN::Config->{urllist} ||= [];
c356248b
AK
1709 $last = $#{$CPAN::Config->{urllist}};
1710 if ($force & 2) { # local cpans probably out of date, don't reorder
1711 @reordered = (0..$last);
1712 } else {
1713 @reordered =
1714 sort {
1715 (substr($CPAN::Config->{urllist}[$b],0,4) eq "file")
1716 <=>
1717 (substr($CPAN::Config->{urllist}[$a],0,4) eq "file")
1718 or
1719 defined($Thesite)
1720 and
1721 ($b == $Thesite)
1722 <=>
1723 ($a == $Thesite)
1724 } 0..$last;
c356248b
AK
1725 }
1726 my($level,@levels);
1727 if ($Themethod) {
1728 @levels = ($Themethod, grep {$_ ne $Themethod} qw/easy hard hardest/);
1729 } else {
1730 @levels = qw/easy hard hardest/;
1731 }
1732 for $level (@levels) {
1733 my $method = "host$level";
1734 my @host_seq = $level eq "easy" ?
1735 @reordered : 0..$last; # reordered has CDROM up front
09d9d230 1736 @host_seq = (0) unless @host_seq;
c356248b
AK
1737 my $ret = $self->$method(\@host_seq,$file,$aslocal);
1738 if ($ret) {
2e2b7522
GS
1739 $Themethod = $level;
1740 $self->debug("level[$level]") if $CPAN::DEBUG;
1741 return $ret;
1742 } else {
1743 unlink $aslocal;
c356248b
AK
1744 }
1745 }
1746 my(@mess);
1747 push @mess,
1748 qq{Please check, if the URLs I found in your configuration file \(}.
1749 join(", ", @{$CPAN::Config->{urllist}}).
1750 qq{\) are valid. The urllist can be edited.},
1751 qq{E.g. with ``o conf urllist push ftp://myurl/''};
1752 $CPAN::Frontend->myprint(Text::Wrap::wrap("","",@mess). "\n\n");
1753 sleep 2;
1754 $CPAN::Frontend->myprint("Cannot fetch $file\n\n");
1755 if ($restore) {
1756 rename "$aslocal.bak", $aslocal;
1757 $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
1758 $self->ls($aslocal));
1759 return $aslocal;
1760 }
1761 return;
1762}
1763
1764sub hosteasy {
1765 my($self,$host_seq,$file,$aslocal) = @_;
05454584 1766 my($i);
c356248b 1767 HOSTEASY: for $i (@$host_seq) {
09d9d230 1768 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
c356248b
AK
1769 unless ($self->is_reachable($url)) {
1770 $CPAN::Frontend->myprint("Skipping $url (seems to be not reachable)\n");
1771 sleep 2;
1772 next;
1773 }
05454584
AK
1774 $url .= "/" unless substr($url,-1) eq "/";
1775 $url .= $file;
c356248b 1776 $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
05454584
AK
1777 if ($url =~ /^file:/) {
1778 my $l;
55e314ee 1779 if ($CPAN::META->has_inst('LWP')) {
05454584 1780 require URI::URL;
55e314ee 1781 my $u = URI::URL->new($url);
05454584
AK
1782 $l = $u->path;
1783 } else { # works only on Unix, is poorly constructed, but
c356248b
AK
1784 # hopefully better than nothing.
1785 # RFC 1738 says fileurl BNF is
1786 # fileurl = "file://" [ host | "localhost" ] "/" fpath
1787 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
1788 # the code
05454584
AK
1789 ($l = $url) =~ s,^file://[^/]+,,; # discard the host part
1790 $l =~ s/^file://; # assume they meant file://localhost
1791 }
c356248b
AK
1792 if ( -f $l && -r _) {
1793 $Thesite = $i;
1794 return $l;
1795 }
05454584
AK
1796 # Maybe mirror has compressed it?
1797 if (-f "$l.gz") {
d4fd5c69 1798 $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
09d9d230 1799 CPAN::Tarzip->gunzip("$l.gz", $aslocal);
c356248b
AK
1800 if ( -f $aslocal) {
1801 $Thesite = $i;
1802 return $aslocal;
1803 }
05454584
AK
1804 }
1805 }
2e2b7522 1806 if ($CPAN::META->has_inst('LWP')) {
09d9d230 1807 $CPAN::Frontend->myprint("Fetching with LWP:
c356248b
AK
1808 $url
1809");
09d9d230
A
1810 my $res = $Ua->mirror($url, $aslocal);
1811 if ($res->is_success) {
1812 $Thesite = $i;
1813 return $aslocal;
1814 } elsif ($url !~ /\.gz$/) {
1815 my $gzurl = "$url.gz";
1816 $CPAN::Frontend->myprint("Fetching with LWP:
c356248b
AK
1817 $gzurl
1818");
09d9d230
A
1819 $res = $Ua->mirror($gzurl, "$aslocal.gz");
1820 if ($res->is_success &&
1821 CPAN::Tarzip->gunzip("$aslocal.gz",$aslocal)
1822 ) {
1823 $Thesite = $i;
1824 return $aslocal;
c356248b 1825 } else {
09d9d230 1826 # next HOSTEASY ;
05454584 1827 }
09d9d230
A
1828 } else {
1829 # Alan Burlison informed me that in firewall envs Net::FTP
1830 # can still succeed where LWP fails. So we do not skip
1831 # Net::FTP anymore when LWP is available.
1832 # next HOSTEASY ;
1833 }
1834 } else {
1835 $self->debug("LWP not installed") if $CPAN::DEBUG;
05454584
AK
1836 }
1837 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
1838 # that's the nice and easy way thanks to Graham
1839 my($host,$dir,$getfile) = ($1,$2,$3);
55e314ee 1840 if ($CPAN::META->has_inst('Net::FTP')) {
05454584 1841 $dir =~ s|/+|/|g;
c356248b 1842 $CPAN::Frontend->myprint("Fetching with Net::FTP:
09d9d230 1843 $url
c356248b
AK
1844");
1845 $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
1846 "aslocal[$aslocal]") if $CPAN::DEBUG;
1847 if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
1848 $Thesite = $i;
1849 return $aslocal;
1850 }
1851 if ($aslocal !~ /\.gz$/) {
1852 my $gz = "$aslocal.gz";
1853 $CPAN::Frontend->myprint("Fetching with Net::FTP
09d9d230 1854 $url.gz
c356248b 1855");
2e2b7522 1856 if (CPAN::FTP->ftp_get($host,
09d9d230
A
1857 $dir,
1858 "$getfile.gz",
1859 $gz) &&
1860 CPAN::Tarzip->gunzip($gz,$aslocal)
1861 ){
c356248b
AK
1862 $Thesite = $i;
1863 return $aslocal;
1864 }
1865 }
09d9d230 1866 # next HOSTEASY;
05454584
AK
1867 }
1868 }
c356248b
AK
1869 }
1870}
05454584 1871
c356248b 1872sub hosthard {
2e2b7522 1873 my($self,$host_seq,$file,$aslocal) = @_;
05454584 1874
2e2b7522
GS
1875 # Came back if Net::FTP couldn't establish connection (or
1876 # failed otherwise) Maybe they are behind a firewall, but they
1877 # gave us a socksified (or other) ftp program...
c356248b 1878
2e2b7522
GS
1879 my($i);
1880 my($devnull) = $CPAN::Config->{devnull} || "";
1881 # < /dev/null ";
1882 my($aslocal_dir) = File::Basename::dirname($aslocal);
1883 File::Path::mkpath($aslocal_dir);
c356248b 1884 HOSTHARD: for $i (@$host_seq) {
09d9d230 1885 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
c356248b
AK
1886 unless ($self->is_reachable($url)) {
1887 $CPAN::Frontend->myprint("Skipping $url (not reachable)\n");
1888 next;
1889 }
1890 $url .= "/" unless substr($url,-1) eq "/";
1891 $url .= $file;
09d9d230
A
1892 my($proto,$host,$dir,$getfile);
1893
1894 # Courtesy Mark Conty mark_conty@cargill.com change from
1895 # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
1896 # to
1897 if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
1898 # proto not yet used
1899 ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
c356248b
AK
1900 } else {
1901 next HOSTHARD; # who said, we could ftp anything except ftp?
1902 }
1903 $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;
1904 my($f,$funkyftp);
2e2b7522 1905 for $f ('lynx','ncftpget','ncftp') {
c356248b
AK
1906 next unless exists $CPAN::Config->{$f};
1907 $funkyftp = $CPAN::Config->{$f};
05454584 1908 next unless defined $funkyftp;
55e314ee 1909 next if $funkyftp =~ /^\s*$/;
05454584 1910 my($want_compressed);
c356248b
AK
1911 my $aslocal_uncompressed;
1912 ($aslocal_uncompressed = $aslocal) =~ s/\.gz//;
05454584 1913 my($source_switch) = "";
2e2b7522
GS
1914 $source_switch = " -source" if $funkyftp =~ /\blynx$/;
1915 $source_switch = " -c" if $funkyftp =~ /\bncftp$/;
c356248b 1916 $CPAN::Frontend->myprint(
2e2b7522
GS
1917 qq[
1918Trying with "$funkyftp$source_switch" to get
c356248b 1919 $url
2e2b7522
GS
1920]);
1921 my($system) = "$funkyftp$source_switch '$url' $devnull > ".
c356248b 1922 "$aslocal_uncompressed";
55e314ee 1923 $self->debug("system[$system]") if $CPAN::DEBUG;
05454584 1924 my($wstatus);
55e314ee
AK
1925 if (($wstatus = system($system)) == 0
1926 &&
c356248b
AK
1927 -s $aslocal_uncompressed # lynx returns 0 on my
1928 # system even if it fails
55e314ee 1929 ) {
c356248b 1930 if ($aslocal_uncompressed ne $aslocal) {
09d9d230
A
1931 # test gzip integrity
1932 if (
1933 CPAN::Tarzip->gtest($aslocal_uncompressed)
1934 ) {
1935 rename $aslocal_uncompressed, $aslocal;
1936 } else {
1937 CPAN::Tarzip->gzip($aslocal_uncompressed,
1938 "$aslocal_uncompressed.gz");
1939 }
1940 $Thesite = $i;
1941 return $aslocal;
c356248b
AK
1942 }
1943 } elsif ($url !~ /\.gz$/) {
2e2b7522
GS
1944 unlink $aslocal_uncompressed if
1945 -f $aslocal_uncompressed && -s _ == 0;
1946 my $gz = "$aslocal.gz";
1947 my $gzurl = "$url.gz";
1948 $CPAN::Frontend->myprint(
1949 qq[
1950Trying with "$funkyftp$source_switch" to get
c356248b 1951 $url.gz
2e2b7522
GS
1952]);
1953 my($system) = "$funkyftp$source_switch '$url.gz' $devnull > ".
1954 "$aslocal_uncompressed.gz";
1955 $self->debug("system[$system]") if $CPAN::DEBUG;
1956 my($wstatus);
1957 if (($wstatus = system($system)) == 0
1958 &&
1959 -s "$aslocal_uncompressed.gz"
1960 ) {
1961 # test gzip integrity
1962 if (CPAN::Tarzip->gtest("$aslocal_uncompressed.gz")) {
1963 CPAN::Tarzip->gunzip("$aslocal_uncompressed.gz",
1964 $aslocal);
1965 } else {
1966 rename $aslocal_uncompressed, $aslocal;
05454584 1967 }
2e2b7522
GS
1968 $Thesite = $i;
1969 return $aslocal;
1970 } else {
1971 unlink "$aslocal_uncompressed.gz" if
1972 -f "$aslocal_uncompressed.gz";
1973 }
05454584
AK
1974 } else {
1975 my $estatus = $wstatus >> 8;
c356248b
AK
1976 my $size = -f $aslocal ? ", left\n$aslocal with size ".-s _ : "";
1977 $CPAN::Frontend->myprint(qq{
05454584 1978System call "$system"
c356248b
AK
1979returned status $estatus (wstat $wstatus)$size
1980});
05454584
AK
1981 }
1982 }
c356248b
AK
1983 }
1984}
05454584 1985
c356248b
AK
1986sub hosthardest {
1987 my($self,$host_seq,$file,$aslocal) = @_;
1988
1989 my($i);
1990 my($aslocal_dir) = File::Basename::dirname($aslocal);
1991 File::Path::mkpath($aslocal_dir);
1992 HOSTHARDEST: for $i (@$host_seq) {
1993 unless (length $CPAN::Config->{'ftp'}) {
1994 $CPAN::Frontend->myprint("No external ftp command available\n\n");
1995 last HOSTHARDEST;
1996 }
09d9d230 1997 my $url = $CPAN::Config->{urllist}[$i] || $CPAN::Defaultsite;
c356248b
AK
1998 unless ($self->is_reachable($url)) {
1999 $CPAN::Frontend->myprint("Skipping $url (not reachable)\n");
2000 next;
2001 }
2002 $url .= "/" unless substr($url,-1) eq "/";
2003 $url .= $file;
2004 $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
2005 unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
2006 next;
2007 }
2008 my($host,$dir,$getfile) = ($1,$2,$3);
2009 my($netrcfile,$fh);
2010 my $timestamp = 0;
2011 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
2012 $ctime,$blksize,$blocks) = stat($aslocal);
2013 $timestamp = $mtime ||= 0;
2014 my($netrc) = CPAN::FTP::netrc->new;
2015 my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
2016 my $targetfile = File::Basename::basename($aslocal);
2017 my(@dialog);
2018 push(
2019 @dialog,
2020 "lcd $aslocal_dir",
2021 "cd /",
2022 map("cd $_", split "/", $dir), # RFC 1738
2023 "bin",
2024 "get $getfile $targetfile",
2025 "quit"
2026 );
2027 if (! $netrc->netrc) {
2028 CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
2029 } elsif ($netrc->hasdefault || $netrc->contains($host)) {
2030 CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
2031 $netrc->hasdefault,
2032 $netrc->contains($host))) if $CPAN::DEBUG;
2033 if ($netrc->protected) {
2034 $CPAN::Frontend->myprint(qq{
05454584
AK
2035 Trying with external ftp to get
2036 $url
2037 As this requires some features that are not thoroughly tested, we\'re
2038 not sure, that we get it right....
2039
2040}
c356248b
AK
2041 );
2042 $self->talk_ftp("$CPAN::Config->{'ftp'}$verbose $host",
2043 @dialog);
05454584 2044 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
c356248b 2045 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
05454584
AK
2046 $mtime ||= 0;
2047 if ($mtime > $timestamp) {
c356248b
AK
2048 $CPAN::Frontend->myprint("GOT $aslocal\n");
2049 $Thesite = $i;
05454584
AK
2050 return $aslocal;
2051 } else {
c356248b 2052 $CPAN::Frontend->myprint("Hmm... Still failed!\n");
05454584 2053 }
c356248b
AK
2054 } else {
2055 $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
2056 qq{correctly protected.\n});
05454584 2057 }
c356248b
AK
2058 } else {
2059 $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
2060 nor does it have a default entry\n");
05454584 2061 }
c356248b
AK
2062
2063 # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
2064 # then and login manually to host, using e-mail as
2065 # password.
2066 $CPAN::Frontend->myprint(qq{Issuing "$CPAN::Config->{'ftp'}$verbose -n"\n});
2067 unshift(
2068 @dialog,
2069 "open $host",
2070 "user anonymous $Config::Config{'cf_email'}"
2071 );
2072 $self->talk_ftp("$CPAN::Config->{'ftp'}$verbose -n", @dialog);
2073 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2074 $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
2075 $mtime ||= 0;
2076 if ($mtime > $timestamp) {
2077 $CPAN::Frontend->myprint("GOT $aslocal\n");
2078 $Thesite = $i;
2079 return $aslocal;
2080 } else {
2081 $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
05454584 2082 }
c356248b
AK
2083 $CPAN::Frontend->myprint("Can't access URL $url.\n\n");
2084 sleep 2;
e50380aa 2085 }
c356248b
AK
2086}
2087
2088sub talk_ftp {
2089 my($self,$command,@dialog) = @_;
2090 my $fh = FileHandle->new;
2091 $fh->open("|$command") or die "Couldn't open ftp: $!";
2092 foreach (@dialog) { $fh->print("$_\n") }
2093 $fh->close; # Wait for process to complete
2094 my $wstatus = $?;
2095 my $estatus = $wstatus >> 8;
2096 $CPAN::Frontend->myprint(qq{
2097Subprocess "|$command"
2098 returned status $estatus (wstat $wstatus)
2099}) if $wstatus;
2100
05454584
AK
2101}
2102
e50380aa
AK
2103# find2perl needs modularization, too, all the following is stolen
2104# from there
09d9d230 2105# CPAN::FTP::ls
e50380aa
AK
2106sub ls {
2107 my($self,$name) = @_;
2108 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
2109 $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
2110
2111 my($perms,%user,%group);
2112 my $pname = $name;
2113
55e314ee 2114 if ($blocks) {
e50380aa
AK
2115 $blocks = int(($blocks + 1) / 2);
2116 }
2117 else {
2118 $blocks = int(($sizemm + 1023) / 1024);
2119 }
2120
2121 if (-f _) { $perms = '-'; }
2122 elsif (-d _) { $perms = 'd'; }
2123 elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
2124 elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
2125 elsif (-p _) { $perms = 'p'; }
2126 elsif (-S _) { $perms = 's'; }
2127 else { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
2128
2129 my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
2130 my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
2131 my $tmpmode = $mode;
2132 my $tmp = $rwx[$tmpmode & 7];
2133 $tmpmode >>= 3;
2134 $tmp = $rwx[$tmpmode & 7] . $tmp;
2135 $tmpmode >>= 3;
2136 $tmp = $rwx[$tmpmode & 7] . $tmp;
2137 substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
2138 substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
2139 substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
2140 $perms .= $tmp;
2141
2142 my $user = $user{$uid} || $uid; # too lazy to implement lookup
2143 my $group = $group{$gid} || $gid;
2144
2145 my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
2146 my($timeyear);
2147 my($moname) = $moname[$mon];
2148 if (-M _ > 365.25 / 2) {
2149 $timeyear = $year + 1900;
2150 }
2151 else {
2152 $timeyear = sprintf("%02d:%02d", $hour, $min);
2153 }
2154
2155 sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
2156 $ino,
2157 $blocks,
2158 $perms,
2159 $nlink,
2160 $user,
2161 $group,
2162 $sizemm,
2163 $moname,
2164 $mday,
2165 $timeyear,
2166 $pname;
2167}
2168
05454584
AK
2169package CPAN::FTP::netrc;
2170
2171sub new {
2172 my($class) = @_;
2173 my $file = MM->catfile($ENV{HOME},".netrc");
2174
2175 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
2176 $atime,$mtime,$ctime,$blksize,$blocks)
2177 = stat($file);
2178 $mode ||= 0;
2179 my $protected = 0;
2180
42d3b621
AK
2181 my($fh,@machines,$hasdefault);
2182 $hasdefault = 0;
da199366
AK
2183 $fh = FileHandle->new or die "Could not create a filehandle";
2184
2185 if($fh->open($file)){
2186 $protected = ($mode & 077) == 0;
10b2abe6 2187 local($/) = "";
42d3b621 2188 NETRC: while (<$fh>) {
da199366 2189 my(@tokens) = split " ", $_;
42d3b621
AK
2190 TOKEN: while (@tokens) {
2191 my($t) = shift @tokens;
da199366
AK
2192 if ($t eq "default"){
2193 $hasdefault++;
da199366
AK
2194 last NETRC;
2195 }
42d3b621
AK
2196 last TOKEN if $t eq "macdef";
2197 if ($t eq "machine") {
2198 push @machines, shift @tokens;
2199 }
2200 }
10b2abe6
CS
2201 }
2202 } else {
da199366 2203 $file = $hasdefault = $protected = "";
10b2abe6 2204 }
da199366 2205
10b2abe6 2206 bless {
42d3b621
AK
2207 'mach' => [@machines],
2208 'netrc' => $file,
2209 'hasdefault' => $hasdefault,
da199366 2210 'protected' => $protected,
10b2abe6
CS
2211 }, $class;
2212}
2213
42d3b621 2214sub hasdefault { shift->{'hasdefault'} }
da199366
AK
2215sub netrc { shift->{'netrc'} }
2216sub protected { shift->{'protected'} }
10b2abe6
CS
2217sub contains {
2218 my($self,$mach) = @_;
da199366
AK
2219 for ( @{$self->{'mach'}} ) {
2220 return 1 if $_ eq $mach;
2221 }
2222 return 0;
10b2abe6
CS
2223}
2224
5f05dabc 2225package CPAN::Complete;
5f05dabc 2226
55e314ee
AK
2227#-> sub CPAN::Complete::cpl ;
2228sub cpl {
5f05dabc
PP
2229 my($word,$line,$pos) = @_;
2230 $word ||= "";
2231 $line ||= "";
2232 $pos ||= 0;
2233 CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2234 $line =~ s/^\s*//;
da199366
AK
2235 if ($line =~ s/^(force\s*)//) {
2236 $pos -= length($1);
2237 }
5f05dabc
PP
2238 my @return;
2239 if ($pos == 0) {
da199366
AK
2240 @return = grep(
2241 /^$word/,
2242 sort qw(
2243 ! a b d h i m o q r u autobundle clean
2244 make test install force reload look
2245 )
2246 );
2247 } elsif ( $line !~ /^[\!abdhimorutl]/ ) {
5f05dabc
PP
2248 @return = ();
2249 } elsif ($line =~ /^a\s/) {
55e314ee 2250 @return = cplx('CPAN::Author',$word);
5f05dabc 2251 } elsif ($line =~ /^b\s/) {
55e314ee 2252 @return = cplx('CPAN::Bundle',$word);
5f05dabc 2253 } elsif ($line =~ /^d\s/) {
55e314ee 2254 @return = cplx('CPAN::Distribution',$word);
da199366 2255 } elsif ($line =~ /^([mru]|make|clean|test|install|readme|look)\s/ ) {
55e314ee 2256 @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
5f05dabc 2257 } elsif ($line =~ /^i\s/) {
55e314ee 2258 @return = cpl_any($word);
5f05dabc 2259 } elsif ($line =~ /^reload\s/) {
55e314ee 2260 @return = cpl_reload($word,$line,$pos);
5f05dabc 2261 } elsif ($line =~ /^o\s/) {
55e314ee 2262 @return = cpl_option($word,$line,$pos);
5f05dabc
PP
2263 } else {
2264 @return = ();
2265 }
2266 return @return;
2267}
2268
55e314ee
AK
2269#-> sub CPAN::Complete::cplx ;
2270sub cplx {
5f05dabc
PP
2271 my($class, $word) = @_;
2272 grep /^\Q$word\E/, map { $_->id } $CPAN::META->all($class);
2273}
2274
55e314ee
AK
2275#-> sub CPAN::Complete::cpl_any ;
2276sub cpl_any {
5f05dabc
PP
2277 my($word) = shift;
2278 return (
55e314ee
AK
2279 cplx('CPAN::Author',$word),
2280 cplx('CPAN::Bundle',$word),
2281 cplx('CPAN::Distribution',$word),
2282 cplx('CPAN::Module',$word),
5f05dabc
PP
2283 );
2284}
2285
55e314ee
AK
2286#-> sub CPAN::Complete::cpl_reload ;
2287sub cpl_reload {
5f05dabc
PP
2288 my($word,$line,$pos) = @_;
2289 $word ||= "";
2290 my(@words) = split " ", $line;
2291 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2292 my(@ok) = qw(cpan index);
e50380aa
AK
2293 return @ok if @words == 1;
2294 return grep /^\Q$word\E/, @ok if @words == 2 && $word;
5f05dabc
PP
2295}
2296
55e314ee
AK
2297#-> sub CPAN::Complete::cpl_option ;
2298sub cpl_option {
5f05dabc
PP
2299 my($word,$line,$pos) = @_;
2300 $word ||= "";
2301 my(@words) = split " ", $line;
2302 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
2303 my(@ok) = qw(conf debug);
e50380aa 2304 return @ok if @words == 1;
c356248b 2305 return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
5f05dabc
PP
2306 if (0) {
2307 } elsif ($words[1] eq 'index') {
2308 return ();
2309 } elsif ($words[1] eq 'conf') {
55e314ee 2310 return CPAN::Config::cpl(@_);
5f05dabc
PP
2311 } elsif ($words[1] eq 'debug') {
2312 return sort grep /^\Q$word\E/, sort keys %CPAN::DEBUG, 'all';
2313 }
2314}
2315
2316package CPAN::Index;
5f05dabc 2317
10b2abe6 2318#-> sub CPAN::Index::force_reload ;
5f05dabc
PP
2319sub force_reload {
2320 my($class) = @_;
2321 $CPAN::Index::last_time = 0;
2322 $class->reload(1);
2323}
2324
10b2abe6 2325#-> sub CPAN::Index::reload ;
5f05dabc
PP
2326sub reload {
2327 my($cl,$force) = @_;
2328 my $time = time;
2329
c356248b
AK
2330 # XXX check if a newer one is available. (We currently read it
2331 # from time to time)
e50380aa
AK
2332 for ($CPAN::Config->{index_expire}) {
2333 $_ = 0.001 unless $_ > 0.001;
2334 }
c356248b
AK
2335 return if $last_time + $CPAN::Config->{index_expire}*86400 > $time
2336 and ! $force;
e50380aa 2337 my($debug,$t2);
5f05dabc
PP
2338 $last_time = $time;
2339
c356248b
AK
2340 my $needshort = $^O eq "dos";
2341
55e314ee 2342 $cl->rd_authindex($cl->reload_x(
c356248b
AK
2343 "authors/01mailrc.txt.gz",
2344 $needshort ? "01mailrc.gz" : "",
2345 $force));
e50380aa
AK
2346 $t2 = time;
2347 $debug = "timing reading 01[".($t2 - $time)."]";
2348 $time = $t2;
5f05dabc 2349 return if $CPAN::Signal; # this is sometimes lengthy
55e314ee 2350 $cl->rd_modpacks($cl->reload_x(
c356248b
AK
2351 "modules/02packages.details.txt.gz",
2352 $needshort ? "02packag.gz" : "",
2353 $force));
e50380aa
AK
2354 $t2 = time;
2355 $debug .= "02[".($t2 - $time)."]";
2356 $time = $t2;
5f05dabc 2357 return if $CPAN::Signal; # this is sometimes lengthy
55e314ee 2358 $cl->rd_modlist($cl->reload_x(
c356248b
AK
2359 "modules/03modlist.data.gz",
2360 $needshort ? "03mlist.gz" : "",
2361 $force));
e50380aa
AK
2362 $t2 = time;
2363 $debug .= "03[".($t2 - $time)."]";
2364 $time = $t2;
2365 CPAN->debug($debug) if $CPAN::DEBUG;
5f05dabc
PP
2366}
2367
10b2abe6 2368#-> sub CPAN::Index::reload_x ;
5f05dabc
PP
2369sub reload_x {
2370 my($cl,$wanted,$localname,$force) = @_;
c356248b 2371 $force |= 2; # means we're dealing with an index here
55e314ee
AK
2372 CPAN::Config->load; # we should guarantee loading wherever we rely
2373 # on Config XXX
c356248b
AK
2374 $localname ||= $wanted;
2375 my $abs_wanted = MM->catfile($CPAN::Config->{'keep_source_where'},
55e314ee 2376 $localname);
e50380aa
AK
2377 if (
2378 -f $abs_wanted &&
05454584 2379 -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
c356248b 2380 !($force & 1)
e50380aa
AK
2381 ) {
2382 my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
05454584 2383 $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
e50380aa 2384 qq{day$s. I\'ll use that.});
5f05dabc
PP
2385 return $abs_wanted;
2386 } else {
c356248b 2387 $force |= 1; # means we're quite serious about it.
5f05dabc
PP
2388 }
2389 return CPAN::FTP->localize($wanted,$abs_wanted,$force);
2390}
2391
55e314ee
AK
2392#-> sub CPAN::Index::rd_authindex ;
2393sub rd_authindex {
5f05dabc 2394 my($cl,$index_target) = @_;
c356248b 2395 return unless defined $index_target;
c356248b 2396 $CPAN::Frontend->myprint("Going to read $index_target\n");
09d9d230
A
2397# my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
2398# while ($_ = $fh->READLINE) {
2399 # no strict 'refs';
2400 local(*FH);
2401 tie *FH, CPAN::Tarzip, $index_target;
52128c7b 2402 local($/) = "\n";
09d9d230 2403 while (<FH>) {
5f05dabc 2404 chomp;
c356248b
AK
2405 my($userid,$fullname,$email) =
2406 /alias\s+(\S+)\s+\"([^\"\<]+)\s+<([^\>]+)\>\"/;
5f05dabc
PP
2407 next unless $userid && $fullname && $email;
2408
2409 # instantiate an author object
2410 my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
2411 $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
2412 return if $CPAN::Signal;
2413 }
09d9d230
A
2414}
2415
2416sub userid {
2417 my($self,$dist) = @_;
2418 $dist = $self->{'id'} unless defined $dist;
2419 my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
2420 $ret;
5f05dabc
PP
2421}
2422
55e314ee
AK
2423#-> sub CPAN::Index::rd_modpacks ;
2424sub rd_modpacks {
5f05dabc 2425 my($cl,$index_target) = @_;
c356248b 2426 return unless defined $index_target;
c356248b 2427 $CPAN::Frontend->myprint("Going to read $index_target\n");
09d9d230 2428 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
52128c7b 2429 local($/) = "\n";
09d9d230 2430 while ($_ = $fh->READLINE) {
e50380aa
AK
2431 last if /^\s*$/;
2432 }
09d9d230 2433 while ($_ = $fh->READLINE) {
5f05dabc
PP
2434 chomp;
2435 my($mod,$version,$dist) = split;
e50380aa 2436### $version =~ s/^\+//;
5f05dabc 2437
09d9d230 2438 # if it is a bundle, instatiate a bundle object
e50380aa
AK
2439 my($bundle,$id,$userid);
2440
09d9d230
A
2441 if ($mod eq 'CPAN' &&
2442 ! (
2443 $CPAN::META->exists('CPAN::Queue','Bundle::CPAN') ||
2444 $CPAN::META->exists('CPAN::Queue','CPAN')
2445 )
2446 ) {
e50380aa 2447 local($^W)= 0;
5f05dabc 2448 if ($version > $CPAN::VERSION){
c356248b 2449 $CPAN::Frontend->myprint(qq{
e50380aa
AK
2450 There\'s a new CPAN.pm version (v$version) available!
2451 You might want to try
09d9d230 2452 install Bundle::CPAN
5f05dabc 2453 reload cpan
c356248b 2454 without quitting the current session. It should be a seamless upgrade
05454584 2455 while we are running...
c356248b 2456});
05454584 2457 sleep 2;
c356248b 2458 $CPAN::Frontend->myprint(qq{\n});
5f05dabc 2459 }
05454584 2460 last if $CPAN::Signal;
e50380aa
AK
2461 } elsif ($mod =~ /^Bundle::(.*)/) {
2462 $bundle = $1;
5f05dabc 2463 }
05454584 2464
05454584
AK
2465 if ($bundle){
2466 $id = $CPAN::META->instance('CPAN::Bundle',$mod);
2e2b7522 2467 # warn "made mod[$mod]a bundle";
c356248b
AK
2468 # Let's make it a module too, because bundles have so much
2469 # in common with modules
2470 $CPAN::META->instance('CPAN::Module',$mod);
2e2b7522 2471 # warn "made mod[$mod]a module";
c356248b 2472
05454584
AK
2473# This "next" makes us faster but if the job is running long, we ignore
2474# rereads which is bad. So we have to be a bit slower again.
2475# } elsif ($CPAN::META->exists('CPAN::Module',$mod)) {
2476# next;
c356248b
AK
2477
2478 }
2479 else {
05454584
AK
2480 # instantiate a module object
2481 $id = $CPAN::META->instance('CPAN::Module',$mod);
5f05dabc 2482 }
5f05dabc 2483
e50380aa 2484 if ($id->cpan_file ne $dist){
09d9d230 2485 $userid = $cl->userid($dist);
e50380aa
AK
2486 $id->set(
2487 'CPAN_USERID' => $userid,
2488 'CPAN_VERSION' => $version,
2489 'CPAN_FILE' => $dist
2490 );
2491 }
05454584
AK
2492
2493 # instantiate a distribution object
2494 unless ($CPAN::META->exists('CPAN::Distribution',$dist)) {
2495 $CPAN::META->instance(
2496 'CPAN::Distribution' => $dist
2497 )->set(
2498 'CPAN_USERID' => $userid
e50380aa 2499 );
5f05dabc 2500 }
05454584
AK
2501
2502 return if $CPAN::Signal;
5f05dabc 2503 }
09d9d230 2504 undef $fh;
5f05dabc
PP
2505}
2506
55e314ee
AK
2507#-> sub CPAN::Index::rd_modlist ;
2508sub rd_modlist {
05454584 2509 my($cl,$index_target) = @_;
c356248b 2510 return unless defined $index_target;
c356248b 2511 $CPAN::Frontend->myprint("Going to read $index_target\n");
09d9d230
A
2512 my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
2513 my @eval;
52128c7b 2514 local($/) = "\n";
09d9d230 2515 while ($_ = $fh->READLINE) {
e50380aa
AK
2516 if (/^Date:\s+(.*)/){
2517 return if $date_of_03 eq $1;
2518 ($date_of_03) = $1;
2519 }
d4fd5c69 2520 last if /^\s*$/;
05454584 2521 }
09d9d230
A
2522 push @eval, $_ while $_ = $fh->READLINE;
2523 undef $fh;
2524 push @eval, q{CPAN::Modulelist->data;};
05454584
AK
2525 local($^W) = 0;
2526 my($comp) = Safe->new("CPAN::Safe1");
09d9d230 2527 my($eval) = join("", @eval);
05454584
AK
2528 my $ret = $comp->reval($eval);
2529 Carp::confess($@) if $@;
2530 return if $CPAN::Signal;
2531 for (keys %$ret) {
2532 my $obj = $CPAN::META->instance(CPAN::Module,$_);
2533 $obj->set(%{$ret->{$_}});
2534 return if $CPAN::Signal;
2535 }
2536}
5f05dabc 2537
05454584 2538package CPAN::InfoObj;
5f05dabc 2539
05454584
AK
2540#-> sub CPAN::InfoObj::new ;
2541sub new { my $this = bless {}, shift; %$this = @_; $this }
5f05dabc 2542
05454584
AK
2543#-> sub CPAN::InfoObj::set ;
2544sub set {
2545 my($self,%att) = @_;
2546 my(%oldatt) = %$self;
2547 %$self = (%oldatt, %att);
da199366
AK
2548}
2549
05454584
AK
2550#-> sub CPAN::InfoObj::id ;
2551sub id { shift->{'ID'} }
5f05dabc 2552
05454584
AK
2553#-> sub CPAN::InfoObj::as_glimpse ;
2554sub as_glimpse {
5f05dabc 2555 my($self) = @_;
05454584
AK
2556 my(@m);
2557 my $class = ref($self);
2558 $class =~ s/^CPAN:://;
2559 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
2560 join "", @m;
5f05dabc
PP
2561}
2562
05454584
AK
2563#-> sub CPAN::InfoObj::as_string ;
2564sub as_string {
2565 my($self) = @_;
2566 my(@m);
2567 my $class = ref($self);
2568 $class =~ s/^CPAN:://;
2569 push @m, $class, " id = $self->{ID}\n";
2570 for (sort keys %$self) {
2571 next if $_ eq 'ID';
2572 my $extra = "";
09d9d230
A
2573 if ($_ eq "CPAN_USERID") {
2574 $extra .= " (".$self->author;
2575 my $email; # old perls!
2576 if ($email = $CPAN::META->instance(CPAN::Author,
2577 $self->{$_}
2578 )->email) {
2579 $extra .= " <$email>";
2580 } else {
2581 $extra .= " <no email>";
2582 }
2583 $extra .= ")";
2584 }
2585 if (ref($self->{$_}) eq "ARRAY") { # language interface? XXX
05454584 2586 push @m, sprintf " %-12s %s%s\n", $_, "@{$self->{$_}}", $extra;
5f05dabc 2587 } else {
05454584
AK
2588 push @m, sprintf " %-12s %s%s\n", $_, $self->{$_}, $extra;
2589 }
5f05dabc 2590 }
05454584 2591 join "", @m, "\n";
5f05dabc
PP
2592}
2593
05454584
AK
2594#-> sub CPAN::InfoObj::author ;
2595sub author {
2596 my($self) = @_;
2597 $CPAN::META->instance(CPAN::Author,$self->{CPAN_USERID})->fullname;
5f05dabc
PP
2598}
2599
05454584 2600package CPAN::Author;
05454584
AK
2601
2602#-> sub CPAN::Author::as_glimpse ;
2603sub as_glimpse {
5f05dabc 2604 my($self) = @_;
05454584
AK
2605 my(@m);
2606 my $class = ref($self);
2607 $class =~ s/^CPAN:://;
2608 push @m, sprintf "%-15s %s (%s)\n", $class, $self->{ID}, $self->fullname;
2609 join "", @m;
5f05dabc
PP
2610}
2611
05454584
AK
2612# Dead code, I would have liked to have,,, but it was never reached,,,
2613#sub make {
2614# my($self) = @_;
2615# return "Don't be silly, you can't make $self->{FULLNAME} ;-)\n";
2616#}
5f05dabc 2617
05454584
AK
2618#-> sub CPAN::Author::fullname ;
2619sub fullname { shift->{'FULLNAME'} }
2620*name = \&fullname;
2621#-> sub CPAN::Author::email ;
2622sub email { shift->{'EMAIL'} }
5f05dabc 2623
05454584 2624package CPAN::Distribution;
5f05dabc 2625
05454584
AK
2626#-> sub CPAN::Distribution::called_for ;
2627sub called_for {
2628 my($self,$id) = @_;
2629 $self->{'CALLED_FOR'} = $id if defined $id;
2630 return $self->{'CALLED_FOR'};
5f05dabc
PP
2631}
2632
05454584
AK
2633#-> sub CPAN::Distribution::get ;
2634sub get {
5f05dabc 2635 my($self) = @_;
da199366
AK
2636 EXCUSE: {
2637 my @e;
05454584
AK
2638 exists $self->{'build_dir'} and push @e,
2639 "Unwrapped into directory $self->{'build_dir'}";
c356248b 2640 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
da199366 2641 }
05454584
AK
2642 my($local_file);
2643 my($local_wanted) =
c356248b 2644 MM->catfile(
05454584
AK
2645 $CPAN::Config->{keep_source_where},
2646 "authors",
2647 "id",
2648 split("/",$self->{ID})
2649 );
2650
2651 $self->debug("Doing localize") if $CPAN::DEBUG;
c356248b
AK
2652 $local_file =
2653 CPAN::FTP->localize("authors/id/$self->{ID}", $local_wanted)
2654 or $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n");
05454584
AK
2655 $self->{localfile} = $local_file;
2656 my $builddir = $CPAN::META->{cachemgr}->dir;
2657 $self->debug("doing chdir $builddir") if $CPAN::DEBUG;
2658 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
2659 my $packagedir;
2660
2661 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
55e314ee
AK
2662 if ($CPAN::META->has_inst('MD5')) {
2663 $self->debug("MD5 is installed, verifying");
05454584 2664 $self->verifyMD5;
55e314ee
AK
2665 } else {
2666 $self->debug("MD5 is NOT installed");
2667 }
2668 $self->debug("Removing tmp") if $CPAN::DEBUG;
2669 File::Path::rmtree("tmp");
2670 mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!";
2671 chdir "tmp";
2672 $self->debug("Changed directory to tmp") if $CPAN::DEBUG;
c356248b
AK
2673 if (! $local_file) {
2674 Carp::croak "bad download, can't do anything :-(\n";
2675 } elsif ($local_file =~ /(\.tar\.(gz|Z)|\.tgz)$/i){
55e314ee
AK
2676 $self->untar_me($local_file);
2677 } elsif ( $local_file =~ /\.zip$/i ) {
2678 $self->unzip_me($local_file);
2679 } elsif ( $local_file =~ /\.pm\.(gz|Z)$/) {
2680 $self->pm2dir_me($local_file);
2681 } else {
2682 $self->{archived} = "NO";
5f05dabc 2683 }
55e314ee
AK
2684 chdir "..";
2685 if ($self->{archived} ne 'NO') {
05454584 2686 chdir "tmp";
05454584 2687 # Let's check if the package has its own directory.
55e314ee
AK
2688 my $dh = DirHandle->new(".") or Carp::croak("Couldn't opendir .: $!");
2689 my @readdir = grep $_ !~ /^\.\.?$/, $dh->read; ### MAC??
2690 $dh->close;
05454584
AK
2691 my ($distdir,$packagedir);
2692 if (@readdir == 1 && -d $readdir[0]) {
2693 $distdir = $readdir[0];
c356248b
AK
2694 $packagedir = MM->catdir($builddir,$distdir);
2695 -d $packagedir and $CPAN::Frontend->myprint("Removing previously used $packagedir\n");
05454584
AK
2696 File::Path::rmtree($packagedir);
2697 rename($distdir,$packagedir) or Carp::confess("Couldn't rename $distdir to $packagedir: $!");
2698 } else {
2699 my $pragmatic_dir = $self->{'CPAN_USERID'} . '000';
2700 $pragmatic_dir =~ s/\W_//g;
2701 $pragmatic_dir++ while -d "../$pragmatic_dir";
c356248b 2702 $packagedir = MM->catdir($builddir,$pragmatic_dir);
05454584
AK
2703 File::Path::mkpath($packagedir);
2704 my($f);
2705 for $f (@readdir) { # is already without "." and ".."
c356248b 2706 my $to = MM->catdir($packagedir,$f);
05454584
AK
2707 rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!");
2708 }
2709 }
2710 $self->{'build_dir'} = $packagedir;
05454584 2711 chdir "..";
55e314ee 2712
05454584
AK
2713 $self->debug("Changed directory to .. (self is $self [".$self->as_string."])")
2714 if $CPAN::DEBUG;
2715 File::Path::rmtree("tmp");
2716 if ($CPAN::Config->{keep_source_where} =~ /^no/i ){
c356248b 2717 $CPAN::Frontend->myprint("Going to unlink $local_file\n");
05454584
AK
2718 unlink $local_file or Carp::carp "Couldn't unlink $local_file";
2719 }
c356248b 2720 my($makefilepl) = MM->catfile($packagedir,"Makefile.PL");
05454584 2721 unless (-f $makefilepl) {
09d9d230
A
2722 my($configure) = MM->catfile($packagedir,"Configure");
2723 if (-f $configure) {
2724 # do we have anything to do?
2725 $self->{'configure'} = $configure;
2726 } elsif (-f MM->catfile($packagedir,"Makefile")) {
2727 $CPAN::Frontend->myprint(qq{
2728Package comes with a Makefile and without a Makefile.PL.
2729We\'ll try to build it with that Makefile then.
2730});
2731 $self->{writemakefile} = "YES";
2732 sleep 2;
2733 } else {
2734 my $fh = FileHandle->new(">$makefilepl")
2735 or Carp::croak("Could not open >$makefilepl");
2736 my $cf = $self->called_for || "unknown";
2737 $fh->print(
55e314ee
AK
2738qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
2739# because there was no Makefile.PL supplied.
05454584 2740# Autogenerated on: }.scalar localtime().qq{
55e314ee 2741
09d9d230
A
2742use ExtUtils::MakeMaker;
2743WriteMakefile(NAME => q[$cf]);
55e314ee 2744
05454584 2745});
09d9d230
A
2746 $CPAN::Frontend->myprint(qq{Package comes without Makefile.PL.
2747 Writing one on our own (calling it $cf)\n});
05454584
AK
2748 }
2749 }
5f05dabc 2750 }
05454584 2751 return $self;
5f05dabc
PP
2752}
2753
55e314ee
AK
2754sub untar_me {
2755 my($self,$local_file) = @_;
2756 $self->{archived} = "tar";
09d9d230 2757 if (CPAN::Tarzip->untar($local_file)) {
55e314ee
AK
2758 $self->{unwrapped} = "YES";
2759 } else {
2760 $self->{unwrapped} = "NO";
2761 }
2762}
2763
2764sub unzip_me {
2765 my($self,$local_file) = @_;
2766 $self->{archived} = "zip";
2767 my $system = "$CPAN::Config->{unzip} $local_file";
2768 if (system($system) == 0) {
2769 $self->{unwrapped} = "YES";
2770 } else {
2771 $self->{unwrapped} = "NO";
2772 }
2773}
2774
2775sub pm2dir_me {
2776 my($self,$local_file) = @_;
2777 $self->{archived} = "pm";
2778 my $to = File::Basename::basename($local_file);
2779 $to =~ s/\.(gz|Z)$//;
09d9d230 2780 if (CPAN::Tarzip->gunzip($local_file,$to)) {
55e314ee
AK
2781 $self->{unwrapped} = "YES";
2782 } else {
2783 $self->{unwrapped} = "NO";
2784 }
2785}
2786
05454584
AK
2787#-> sub CPAN::Distribution::new ;
2788sub new {
2789 my($class,%att) = @_;
5f05dabc 2790
05454584 2791 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();
5f05dabc 2792
05454584
AK
2793 my $this = { %att };
2794 return bless $this, $class;
5f05dabc
PP
2795}
2796
05454584
AK
2797#-> sub CPAN::Distribution::look ;
2798sub look {
5f05dabc 2799 my($self) = @_;
05454584 2800 if ( $CPAN::Config->{'shell'} ) {
c356248b 2801 $CPAN::Frontend->myprint(qq{
05454584 2802Trying to open a subshell in the build directory...
c356248b 2803});
05454584 2804 } else {
c356248b 2805 $CPAN::Frontend->myprint(qq{
05454584
AK
2806Your configuration does not define a value for subshells.
2807Please define it with "o conf shell <your shell>"
c356248b 2808});
05454584 2809 return;
5f05dabc 2810 }
05454584
AK
2811 my $dist = $self->id;
2812 my $dir = $self->dir or $self->get;
2813 $dir = $self->dir;
e50380aa
AK
2814 my $getcwd;
2815 $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
55e314ee 2816 my $pwd = CPAN->$getcwd();
05454584 2817 chdir($dir);
c356248b
AK
2818 $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
2819 system($CPAN::Config->{'shell'}) == 0
2820 or $CPAN::Frontend->mydie("Subprocess shell error");
05454584 2821 chdir($pwd);
5f05dabc
PP
2822}
2823
05454584
AK
2824#-> sub CPAN::Distribution::readme ;
2825sub readme {
5f05dabc 2826 my($self) = @_;
05454584
AK
2827 my($dist) = $self->id;
2828 my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/;
2829 $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG;
2830 my($local_file);
2831 my($local_wanted) =
c356248b 2832 MM->catfile(
05454584
AK
2833 $CPAN::Config->{keep_source_where},
2834 "authors",
2835 "id",
2836 split("/","$sans.readme"),
2837 );
2838 $self->debug("Doing localize") if $CPAN::DEBUG;
c356248b
AK
2839 $local_file = CPAN::FTP->localize("authors/id/$sans.readme",
2840 $local_wanted)
2841 or $CPAN::Frontend->mydie(qq{No $sans.readme found});;
05454584 2842 my $fh_pager = FileHandle->new;
c356248b 2843 local($SIG{PIPE}) = "IGNORE";
05454584
AK
2844 $fh_pager->open("|$CPAN::Config->{'pager'}")
2845 or die "Could not open pager $CPAN::Config->{'pager'}: $!";
2846 my $fh_readme = FileHandle->new;
c356248b
AK
2847 $fh_readme->open($local_file)
2848 or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!});
2849 $CPAN::Frontend->myprint(qq{
2850Displaying file
2851 $local_file
2852with pager "$CPAN::Config->{'pager'}"
2853});
2854 sleep 2;
05454584 2855 $fh_pager->print(<$fh_readme>);
5f05dabc
PP
2856}
2857
05454584
AK
2858#-> sub CPAN::Distribution::verifyMD5 ;
2859sub verifyMD5 {
5f05dabc 2860 my($self) = @_;
05454584
AK
2861 EXCUSE: {
2862 my @e;
2863 $self->{MD5_STATUS} ||= "";
2864 $self->{MD5_STATUS} eq "OK" and push @e, "MD5 Checksum was ok";
c356248b 2865 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
05454584 2866 }
55e314ee
AK
2867 my($lc_want,$lc_file,@local,$basename);
2868 @local = split("/",$self->{ID});
2869 pop @local;
05454584 2870 push @local, "CHECKSUMS";
55e314ee 2871 $lc_want =
c356248b 2872 MM->catfile($CPAN::Config->{keep_source_where},
55e314ee 2873 "authors", "id", @local);
05454584
AK
2874 local($") = "/";
2875 if (
c356248b 2876 -s $lc_want
05454584 2877 &&
55e314ee 2878 $self->MD5_check_file($lc_want)
05454584
AK
2879 ) {
2880 return $self->{MD5_STATUS} = "OK";
2881 }
55e314ee 2882 $lc_file = CPAN::FTP->localize("authors/id/@local",
c356248b 2883 $lc_want,1);
55e314ee 2884 unless ($lc_file) {
05454584 2885 $local[-1] .= ".gz";
55e314ee 2886 $lc_file = CPAN::FTP->localize("authors/id/@local",
c356248b
AK
2887 "$lc_want.gz",1);
2888 if ($lc_file) {
c356248b 2889 $lc_file =~ s/\.gz$//;
09d9d230 2890 CPAN::Tarzip->gunzip("$lc_file.gz",$lc_file);
c356248b
AK
2891 } else {
2892 return;
2893 }
05454584 2894 }
55e314ee 2895 $self->MD5_check_file($lc_file);
5f05dabc
PP
2896}
2897
05454584
AK
2898#-> sub CPAN::Distribution::MD5_check_file ;
2899sub MD5_check_file {
55e314ee
AK
2900 my($self,$chk_file) = @_;
2901 my($cksum,$file,$basename);
c356248b 2902 $file = $self->{localfile};
55e314ee
AK
2903 $basename = File::Basename::basename($file);
2904 my $fh = FileHandle->new;
55e314ee 2905 if (open $fh, $chk_file){
c356248b 2906 local($/);
05454584
AK
2907 my $eval = <$fh>;
2908 close $fh;
2909 my($comp) = Safe->new();
2910 $cksum = $comp->reval($eval);
55e314ee
AK
2911 if ($@) {
2912 rename $chk_file, "$chk_file.bad";
2913 Carp::confess($@) if $@;
2914 }
2915 } else {
2916 Carp::carp "Could not open $chk_file for reading";
2917 }
09d9d230
A
2918
2919 if (exists $cksum->{$basename}{md5}) {
55e314ee 2920 $self->debug("Found checksum for $basename:" .
09d9d230
A
2921 "$cksum->{$basename}{md5}\n") if $CPAN::DEBUG;
2922
2923 open($fh, $file);
2924 binmode $fh;
2925 my $eq = $self->eq_MD5($fh,$cksum->{$basename}{'md5'});
2926 $fh->close;
2927 $fh = CPAN::Tarzip->TIEHANDLE($file);
2928
2929 unless ($eq) {
2930 # had to inline it, when I tied it, the tiedness got lost on
2931 # the call to eq_MD5. (Jan 1998)
2932 my $md5 = MD5->new;
2933 my($data,$ref);
2934 $ref = \$data;
2935 while ($fh->READ($ref, 4096)){
2936 $md5->add($data);
2937 }
2938 my $hexdigest = $md5->hexdigest;
2939 $eq += $hexdigest eq $cksum->{$basename}{'md5-ungz'};
2940 }
2941
2942 if ($eq) {
2943 $CPAN::Frontend->myprint("Checksum for $file ok\n");
2944 return $self->{MD5_STATUS} = "OK";
05454584 2945 } else {
c356248b
AK
2946 $CPAN::Frontend->myprint(qq{Checksum mismatch for }.
2947 qq{distribution file. }.
2948 qq{Please investigate.\n\n}.
2949 $self->as_string,
2950 $CPAN::META->instance(
2951 'CPAN::Author',
2952 $self->{CPAN_USERID}
2953 )->as_string);
55e314ee 2954 my $wrap = qq{I\'d recommend removing $file. It seems to
09d9d230
A
2955be a bogus file. Maybe you have configured your \`urllist\' with a
2956bad URL. Please check this array with \`o conf urllist\', and
55e314ee 2957retry.};
c356248b
AK
2958 $CPAN::Frontend->myprint(Text::Wrap::wrap("","",$wrap));
2959 $CPAN::Frontend->myprint("\n\n");
55e314ee 2960 sleep 3;
05454584 2961 return;
5f05dabc 2962 }
09d9d230 2963 # close $fh if fileno($fh);
5f05dabc 2964 } else {
55e314ee
AK
2965 $self->{MD5_STATUS} ||= "";
2966 if ($self->{MD5_STATUS} eq "NIL") {
c356248b
AK
2967 $CPAN::Frontend->myprint(qq{
2968No md5 checksum for $basename in local $chk_file.
2969Removing $chk_file
2970});
2971 unlink $chk_file or $CPAN::Frontend->myprint("Could not unlink: $!");
55e314ee
AK
2972 sleep 1;
2973 }
2974 $self->{MD5_STATUS} = "NIL";
2975 return;
5f05dabc
PP
2976 }
2977}
2978
05454584
AK
2979#-> sub CPAN::Distribution::eq_MD5 ;
2980sub eq_MD5 {
2981 my($self,$fh,$expectMD5) = @_;
55e314ee 2982 my $md5 = MD5->new;
09d9d230
A
2983 my($data);
2984 while (read($fh, $data, 4096)){
2985 $md5->add($data);
2986 }
2987 # $md5->addfile($fh);
05454584 2988 my $hexdigest = $md5->hexdigest;
09d9d230 2989 # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]";
05454584
AK
2990 $hexdigest eq $expectMD5;
2991}
5f05dabc 2992
05454584 2993#-> sub CPAN::Distribution::force ;
5f05dabc
PP
2994sub force {
2995 my($self) = @_;
2996 $self->{'force_update'}++;
05454584
AK
2997 delete $self->{'MD5_STATUS'};
2998 delete $self->{'archived'};
2999 delete $self->{'build_dir'};
3000 delete $self->{'localfile'};
3001 delete $self->{'make'};
3002 delete $self->{'install'};
3003 delete $self->{'unwrapped'};
3004 delete $self->{'writemakefile'};
5f05dabc
PP
3005}
3006
09d9d230
A
3007sub isa_perl {
3008 my($self) = @_;
3009 my $file = File::Basename::basename($self->id);
3010 return unless $file =~ m{ ^ perl
3011 (5)
3012 ([._-])
3013 (\d{3}(_[0-4][0-9])?)
3014 \.tar[._-]gz
3015 $
3016 }x;
3017 "$1.$3";
3018}
3019
d4fd5c69
AK
3020#-> sub CPAN::Distribution::perl ;
3021sub perl {
3022 my($self) = @_;
3023 my($perl) = MM->file_name_is_absolute($^X) ? $^X : "";
e50380aa 3024 my $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
55e314ee 3025 my $pwd = CPAN->$getcwd();
c356248b 3026 my $candidate = MM->catfile($pwd,$^X);
e50380aa 3027 $perl ||= $candidate if MM->maybe_command($candidate);
d4fd5c69
AK
3028 unless ($perl) {
3029 my ($component,$perl_name);
3030 DIST_PERLNAME: foreach $perl_name ($^X, 'perl', 'perl5', "perl$]") {
c356248b
AK
3031 PATH_COMPONENT: foreach $component (MM->path(),
3032 $Config::Config{'binexp'}) {
d4fd5c69
AK
3033 next unless defined($component) && $component;
3034 my($abs) = MM->catfile($component,$perl_name);
3035 if (MM->maybe_command($abs)) {
3036 $perl = $abs;
3037 last DIST_PERLNAME;
3038 }
3039 }
3040 }
3041 }
3042 $perl;
3043}
3044
05454584
AK
3045#-> sub CPAN::Distribution::make ;
3046sub make {
3047 my($self) = @_;
c356248b 3048 $CPAN::Frontend->myprint(sprintf "Running make for %s\n", $self->id);
09d9d230
A
3049 # Emergency brake if they said install Pippi and get newest perl
3050 if ($self->isa_perl) {
3051 if (
3052 $self->called_for ne $self->id && ! $self->{'force_update'}
3053 ) {
3054 $CPAN::Frontend->mydie(sprintf qq{
3055The most recent version "%s" of the module "%s"
3056comes with the current version of perl (%s).
3057I\'ll build that only if you ask for something like
3058 force install %s
3059or
3060 install %s
3061},
3062 $CPAN::META->instance(
3063 'CPAN::Module',
3064 $self->called_for
3065 )->cpan_version,
3066 $self->called_for,
3067 $self->isa_perl,
3068 $self->called_for,
3069 $self->id);
3070 }
3071 }
05454584
AK
3072 $self->get;
3073 EXCUSE: {
3074 my @e;
3075 $self->{archived} eq "NO" and push @e,
3076 "Is neither a tar nor a zip archive.";
5f05dabc 3077
d4fd5c69 3078 $self->{unwrapped} eq "NO" and push @e,
05454584
AK
3079 "had problems unarchiving. Please build manually";
3080
3081 exists $self->{writemakefile} &&
3082 $self->{writemakefile} eq "NO" and push @e,
3083 "Had some problem writing Makefile";
3084
3085 defined $self->{'make'} and push @e,
3086 "Has already been processed within this session";
3087
c356248b 3088 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
5f05dabc 3089 }
c356248b 3090 $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n");
05454584
AK
3091 my $builddir = $self->dir;
3092 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
3093 $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;
3094
3095 my $system;
3096 if ($self->{'configure'}) {
09d9d230 3097 $system = $self->{'configure'};
5f05dabc 3098 } else {
d4fd5c69
AK
3099 my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
3100 my $switch = "";
3101# This needs a handler that can be turned on or off:
3102# $switch = "-MExtUtils::MakeMaker ".
3103# "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
3104# if $] > 5.00310;
3105 $system = "$perl $switch Makefile.PL $CPAN::Config->{makepl_arg}";
3106 }
09d9d230 3107 unless (exists $self->{writemakefile}) {
e50380aa
AK
3108 local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
3109 my($ret,$pid);
3110 $@ = "";
3111 if ($CPAN::Config->{inactivity_timeout}) {
3112 eval {
3113 alarm $CPAN::Config->{inactivity_timeout};
3114 local $SIG{CHLD} = sub { wait };
3115 if (defined($pid = fork)) {
3116 if ($pid) { #parent
3117 wait;
3118 } else { #child
09d9d230
A
3119 # note, this exec isn't necessary if
3120 # inactivity_timeout is 0. On the Mac I'd
3121 # suggest, we set it always to 0.
3122 exec $system;
e50380aa
AK
3123 }
3124 } else {
c356248b 3125 $CPAN::Frontend->myprint("Cannot fork: $!");
e50380aa 3126 return;
05454584 3127 }
e50380aa
AK
3128 };
3129 alarm 0;
3130 if ($@){
3131 kill 9, $pid;
3132 waitpid $pid, 0;
c356248b 3133 $CPAN::Frontend->myprint($@);
e50380aa
AK
3134 $self->{writemakefile} = "NO - $@";
3135 $@ = "";
05454584
AK
3136 return;
3137 }
e50380aa 3138 } else {
2e2b7522
GS
3139 $ret = system($system);
3140 if ($ret != 0) {
3141 $self->{writemakefile} = "NO";
3142 return;
09d9d230 3143 }
e50380aa 3144 }
09d9d230 3145 $self->{writemakefile} = "YES";
05454584 3146 }
05454584
AK
3147 return if $CPAN::Signal;
3148 $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg};
e50380aa 3149 if (system($system) == 0) {
c356248b 3150 $CPAN::Frontend->myprint(" $system -- OK\n");
05454584
AK
3151 $self->{'make'} = "YES";
3152 } else {
3153 $self->{writemakefile} = "YES";
3154 $self->{'make'} = "NO";
c356248b 3155 $CPAN::Frontend->myprint(" $system -- NOT OK\n");
5f05dabc 3156 }
5f05dabc
PP
3157}
3158
05454584
AK
3159#-> sub CPAN::Distribution::test ;
3160sub test {
5f05dabc 3161 my($self) = @_;
05454584
AK
3162 $self->make;
3163 return if $CPAN::Signal;
c356248b 3164 $CPAN::Frontend->myprint("Running make test\n");
05454584
AK
3165 EXCUSE: {
3166 my @e;
3167 exists $self->{'make'} or push @e,
3168 "Make had some problems, maybe interrupted? Won't test";
3169
3170 exists $self->{'make'} and
3171 $self->{'make'} eq 'NO' and
3172 push @e, "Oops, make had returned bad status";
3173
3174 exists $self->{'build_dir'} or push @e, "Has no own directory";
c356248b 3175 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
05454584 3176 }
c356248b
AK
3177 chdir $self->{'build_dir'} or
3178 Carp::croak("Couldn't chdir to $self->{'build_dir'}");
3179 $self->debug("Changed directory to $self->{'build_dir'}")
3180 if $CPAN::DEBUG;
05454584 3181 my $system = join " ", $CPAN::Config->{'make'}, "test";
e50380aa 3182 if (system($system) == 0) {
c356248b 3183 $CPAN::Frontend->myprint(" $system -- OK\n");
05454584
AK
3184 $self->{'make_test'} = "YES";
3185 } else {
3186 $self->{'make_test'} = "NO";
c356248b 3187 $CPAN::Frontend->myprint(" $system -- NOT OK\n");
5f05dabc
PP
3188 }
3189}
3190
05454584
AK
3191#-> sub CPAN::Distribution::clean ;
3192sub clean {
5f05dabc 3193 my($self) = @_;
c356248b 3194 $CPAN::Frontend->myprint("Running make clean\n");
05454584
AK
3195 EXCUSE: {
3196 my @e;
3197 exists $self->{'build_dir'} or push @e, "Has no own directory";
c356248b 3198 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
05454584 3199 }
c356248b
AK
3200 chdir $self->{'build_dir'} or
3201 Carp::croak("Couldn't chdir to $self->{'build_dir'}");
05454584
AK
3202 $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG;
3203 my $system = join " ", $CPAN::Config->{'make'}, "clean";
e50380aa 3204 if (system($system) == 0) {
c356248b 3205 $CPAN::Frontend->myprint(" $system -- OK\n");
05454584
AK
3206 $self->force;
3207 } else {
3208 # Hmmm, what to do if make clean failed?
5f05dabc
PP
3209 }
3210}
3211
05454584
AK
3212#-> sub CPAN::Distribution::install ;
3213sub install {
5f05dabc 3214 my($self) = @_;
05454584
AK
3215 $self->test;
3216 return if $CPAN::Signal;
c356248b 3217 $CPAN::Frontend->myprint("Running make install\n");
05454584
AK
3218 EXCUSE: {
3219 my @e;
3220 exists $self->{'build_dir'} or push @e, "Has no own directory";
5f05dabc 3221
05454584
AK
3222 exists $self->{'make'} or push @e,
3223 "Make had some problems, maybe interrupted? Won't install";
5f05dabc 3224
05454584
AK
3225 exists $self->{'make'} and
3226 $self->{'make'} eq 'NO' and
3227 push @e, "Oops, make had returned bad status";
3228
c356248b
AK
3229 push @e, "make test had returned bad status, ".
3230 "won't install without force"
d4fd5c69
AK
3231 if exists $self->{'make_test'} and
3232 $self->{'make_test'} eq 'NO' and
3233 ! $self->{'force_update'};
3234
05454584
AK
3235 exists $self->{'install'} and push @e,
3236 $self->{'install'} eq "YES" ?
3237 "Already done" : "Already tried without success";
3238
c356248b 3239 $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
05454584 3240 }
c356248b
AK
3241 chdir $self->{'build_dir'} or
3242 Carp::croak("Couldn't chdir to $self->{'build_dir'}");
3243 $self->debug("Changed directory to $self->{'build_dir'}")
3244 if $CPAN::DEBUG;
3245 my $system = join(" ", $CPAN::Config->{'make'},
3246 "install", $CPAN::Config->{make_install_arg});
05454584
AK
3247 my($pipe) = FileHandle->new("$system 2>&1 |");
3248 my($makeout) = "";
3249 while (<$pipe>){
c356248b 3250 $CPAN::Frontend->myprint($_);
05454584
AK
3251 $makeout .= $_;
3252 }
3253 $pipe->close;
3254 if ($?==0) {
c356248b 3255 $CPAN::Frontend->myprint(" $system -- OK\n");
05454584 3256 $self->{'install'} = "YES";
5f05dabc 3257 } else {
05454584 3258 $self->{'install'} = "NO";
c356248b 3259 $CPAN::Frontend->myprint(" $system -- NOT OK\n");
05454584 3260 if ($makeout =~ /permission/s && $> > 0) {
c356248b
AK
3261 $CPAN::Frontend->myprint(qq{ You may have to su }.
3262 qq{to root to install the package\n});
05454584 3263 }
5f05dabc
PP
3264 }
3265}
3266
05454584
AK
3267#-> sub CPAN::Distribution::dir ;
3268sub dir {
3269 shift->{'build_dir'};
5f05dabc
PP
3270}
3271
05454584 3272package CPAN::Bundle;
5f05dabc 3273
05454584
AK
3274#-> sub CPAN::Bundle::as_string ;
3275sub as_string {
3276 my($self) = @_;
3277 $self->contains;
3278 $self->{INST_VERSION} = $self->inst_version;
3279 return $self->SUPER::as_string;
3280}
3281
3282#-> sub CPAN::Bundle::contains ;
3283sub contains {
2e2b7522
GS
3284 my($self) = @_;
3285 my($parsefile) = $self->inst_file;
3286 my($id) = $self->id;
3287 $self->debug("parsefile[$parsefile]id[$id]") if $CPAN::DEBUG;
3288 unless ($parsefile) {
3289 # Try to get at it in the cpan directory
3290 $self->debug("no parsefile") if $CPAN::DEBUG;
3291 Carp::confess "I don't know a $id" unless $self->{CPAN_FILE};
3292 my $dist = $CPAN::META->instance('CPAN::Distribution',
3293 $self->{CPAN_FILE});
3294 $dist->get;
3295 $self->debug($dist->as_string) if $CPAN::DEBUG;
3296 my($todir) = $CPAN::Config->{'cpan_home'};
3297 my(@me,$from,$to,$me);
3298 @me = split /::/, $self->id;
3299 $me[-1] .= ".pm";
3300 $me = MM->catfile(@me);
3301 $from = $self->find_bundle_file($dist->{'build_dir'},$me);
3302 $to = MM->catfile($todir,$me);
3303 File::Path::mkpath(File::Basename::dirname($to));
3304 File::Copy::copy($from, $to)
3305 or Carp::confess("Couldn't copy $from to $to: $!");
3306 $parsefile = $to;
3307 }
3308 my @result;
3309 my $fh = FileHandle->new;
3310 local $/ = "\n";
3311 open($fh,$parsefile) or die "Could not open '$parsefile': $!";
3312 my $inpod = 0;
3313 $self->debug("parsefile[$parsefile]") if $CPAN::DEBUG;
3314 while (<$fh>) {
3315 $inpod = m/^=(?!head1\s+CONTENTS)/ ? 0 :
3316 m/^=head1\s+CONTENTS/ ? 1 : $inpod;
3317 next unless $inpod;
3318 next if /^=/;
3319 next if /^\s+$/;
3320 chomp;
3321 push @result, (split " ", $_, 2)[0];
3322 }
3323 close $fh;
3324 delete $self->{STATUS};
3325 $self->{CONTAINS} = join ", ", @result;
3326 $self->debug("CONTAINS[@result]") if $CPAN::DEBUG;
3327 unless (@result) {
3328 $CPAN::Frontend->mywarn(qq{
3329The bundle file "$parsefile" may be a broken
3330bundlefile. It seems not to contain any bundle definition.
3331Please check the file and if it is bogus, please delete it.
3332Sorry for the inconvenience.
3333});
3334 }
3335 @result;
5f05dabc
PP
3336}
3337
e50380aa
AK
3338#-> sub CPAN::Bundle::find_bundle_file
3339sub find_bundle_file {
3340 my($self,$where,$what) = @_;
c356248b 3341 $self->debug("where[$where]what[$what]") if $CPAN::DEBUG;
2e2b7522
GS
3342### The following two lines let CPAN.pm become Bundle/CPAN.pm :-(
3343### my $bu = MM->catfile($where,$what);
3344### return $bu if -f $bu;
3345 my $bu;
c356248b 3346 my $manifest = MM->catfile($where,"MANIFEST");
e50380aa
AK
3347 unless (-f $manifest) {
3348 require ExtUtils::Manifest;
3349 my $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
55e314ee 3350 my $cwd = CPAN->$getcwd();
e50380aa
AK
3351 chdir $where;
3352 ExtUtils::Manifest::mkmanifest();
3353 chdir $cwd;
3354 }
c356248b
AK
3355 my $fh = FileHandle->new($manifest)
3356 or Carp::croak("Couldn't open $manifest: $!");
e50380aa
AK
3357 local($/) = "\n";
3358 while (<$fh>) {
3359 next if /^\s*\#/;
3360 my($file) = /(\S+)/;
c356248b 3361 if ($file =~ m|\Q$what\E$|) {
e50380aa 3362 $bu = $file;
c356248b
AK
3363 return MM->catfile($where,$bu);
3364 } elsif ($what =~ s|Bundle/||) { # retry if she managed to
3365 # have no Bundle directory
3366 if ($file =~ m|\Q$what\E$|) {
3367 $bu = $file;
3368 return MM->catfile($where,$bu);
3369 }
e50380aa
AK
3370 }
3371 }
c356248b 3372 Carp::croak("Couldn't find a Bundle file in $where");
e50380aa
AK
3373}
3374
05454584
AK
3375#-> sub CPAN::Bundle::inst_file ;
3376sub inst_file {
3377 my($self) = @_;
3378 my($me,$inst_file);
3379 ($me = $self->id) =~ s/.*://;
c356248b
AK
3380## my(@me,$inst_file);
3381## @me = split /::/, $self->id;
3382## $me[-1] .= ".pm";
3383 $inst_file = MM->catfile($CPAN::Config->{'cpan_home'},
3384 "Bundle", "$me.pm");
3385## "Bundle", @me);
05454584 3386 return $self->{'INST_FILE'} = $inst_file if -f $inst_file;
55e314ee 3387# $inst_file =
d4fd5c69
AK
3388 $self->SUPER::inst_file;
3389# return $self->{'INST_FILE'} = $inst_file if -f $inst_file;
3390# return $self->{'INST_FILE'}; # even if undefined?
5f05dabc
PP
3391}
3392
05454584
AK
3393#-> sub CPAN::Bundle::rematein ;
3394sub rematein {
3395 my($self,$meth) = @_;
3396 $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG;
c356248b
AK
3397 my($id) = $self->id;
3398 Carp::croak "Can't $meth $id, don't have an associated bundle file. :-(\n"
3399 unless $self->inst_file || $self->{CPAN_FILE};
05454584
AK
3400 my($s);
3401 for $s ($self->contains) {
3402 my($type) = $s =~ m|/| ? 'CPAN::Distribution' :
3403 $s =~ m|^Bundle::| ? 'CPAN::Bundle' : 'CPAN::Module';
3404 if ($type eq 'CPAN::Distribution') {
c356248b 3405 $CPAN::Frontend->mywarn(qq{
05454584
AK
3406The Bundle }.$self->id.qq{ contains
3407explicitly a file $s.
c356248b 3408});
05454584 3409 sleep 3;
5f05dabc 3410 }
05454584 3411 $CPAN::META->instance($type,$s)->$meth();
5f05dabc 3412 }
5f05dabc
PP
3413}
3414
e50380aa
AK
3415#sub CPAN::Bundle::xs_file
3416sub xs_file {
3417 # If a bundle contains another that contains an xs_file we have
3418 # here, we just don't bother I suppose
3419 return 0;
3420}
3421
05454584
AK
3422#-> sub CPAN::Bundle::force ;
3423sub force { shift->rematein('force',@_); }
3424#-> sub CPAN::Bundle::get ;
3425sub get { shift->rematein('get',@_); }
3426#-> sub CPAN::Bundle::make ;
3427sub make { shift->rematein('make',@_); }
3428#-> sub CPAN::Bundle::test ;
3429sub test { shift->rematein('test',@_); }
3430#-> sub CPAN::Bundle::install ;
09d9d230
A
3431sub install {
3432 my $self = shift;
3433 $self->rematein('install',@_);
3434 $CPAN::META->delete('CPAN::Queue',$self->id);
3435}
05454584
AK
3436#-> sub CPAN::Bundle::clean ;
3437sub clean { shift->rematein('clean',@_); }
5f05dabc 3438
05454584
AK
3439#-> sub CPAN::Bundle::readme ;
3440sub readme {
3441 my($self) = @_;
c356248b
AK
3442 my($file) = $self->cpan_file or $CPAN::Frontend->myprint(qq{
3443No File found for bundle } . $self->id . qq{\n}), return;
05454584
AK
3444 $self->debug("self[$self] file[$file]") if $CPAN::DEBUG;
3445 $CPAN::META->instance('CPAN::Distribution',$file)->readme;
5f05dabc
PP
3446}
3447
05454584 3448package CPAN::Module;
5f05dabc 3449
05454584
AK
3450#-> sub CPAN::Module::as_glimpse ;
3451sub as_glimpse {
3452 my($self) = @_;
3453 my(@m);
3454 my $class = ref($self);
3455 $class =~ s/^CPAN:://;
c356248b
AK
3456 push @m, sprintf("%-15s %-15s (%s)\n", $class, $self->{ID},
3457 $self->cpan_file);
05454584
AK
3458 join "", @m;
3459}
5f05dabc 3460
05454584
AK
3461#-> sub CPAN::Module::as_string ;
3462sub as_string {
3463 my($self) = @_;
3464 my(@m);
3465 CPAN->debug($self) if $CPAN::DEBUG;
3466 my $class = ref($self);
3467 $class =~ s/^CPAN:://;
3468 local($^W) = 0;
3469 push @m, $class, " id = $self->{ID}\n";
3470 my $sprintf = " %-12s %s\n";
c356248b
AK
3471 push @m, sprintf($sprintf, 'DESCRIPTION', $self->{description})
3472 if $self->{description};
05454584
AK
3473 my $sprintf2 = " %-12s %s (%s)\n";
3474 my($userid);
3475 if ($userid = $self->{'CPAN_USERID'} || $self->{'userid'}){
c356248b
AK
3476 my $author;
3477 if ($author = CPAN::Shell->expand('Author',$userid)) {
09d9d230
A
3478 my $email = "";
3479 my $m; # old perls
3480 if ($m = $author->email) {
3481 $email = " <$m>";
3482 }
3483 push @m, sprintf(
3484 $sprintf2,
3485 'CPAN_USERID',
3486 $userid,
3487 $author->fullname . $email
3488 );
c356248b
AK
3489 }
3490 }
3491 push @m, sprintf($sprintf, 'CPAN_VERSION', $self->{CPAN_VERSION})
3492 if $self->{CPAN_VERSION};
3493 push @m, sprintf($sprintf, 'CPAN_FILE', $self->{CPAN_FILE})
3494 if $self->{CPAN_FILE};
05454584
AK
3495 my $sprintf3 = " %-12s %1s%1s%1s%1s (%s,%s,%s,%s)\n";
3496 my(%statd,%stats,%statl,%stati);
c356248b
AK
3497 @statd{qw,? i c a b R M S,} = qw,unknown idea
3498 pre-alpha alpha beta released mature standard,;
3499 @stats{qw,? m d u n,} = qw,unknown mailing-list
3500 developer comp.lang.perl.* none,;
2e2b7522
GS
3501 @statl{qw,? p c + o h,} = qw,unknown perl C C++ other hybrid,;
3502 @stati{qw,? f r O h,} = qw,unknown functions
3503 references+ties object-oriented hybrid,;
05454584
AK
3504 $statd{' '} = 'unknown';
3505 $stats{' '} = 'unknown';
3506 $statl{' '} = 'unknown';
3507 $stati{' '} = 'unknown';
3508 push @m, sprintf(
3509 $sprintf3,
3510 'DSLI_STATUS',
3511 $self->{statd},
3512 $self->{stats},
3513 $self->{statl},
3514 $self->{stati},
3515 $statd{$self->{statd}},
3516 $stats{$self->{stats}},
3517 $statl{$self->{statl}},
3518 $stati{$self->{stati}}
3519 ) if $self->{statd};
3520 my $local_file = $self->inst_file;
09d9d230
A
3521 if ($local_file) {
3522 $self->{MANPAGE} ||= $self->manpage_headline($local_file);
5f05dabc 3523 }
d4fd5c69
AK
3524 my($item);
3525 for $item (qw/MANPAGE CONTAINS/) {
c356248b
AK
3526 push @m, sprintf($sprintf, $item, $self->{$item})
3527 if exists $self->{$item};
d4fd5c69 3528 }
c356248b
AK
3529 push @m, sprintf($sprintf, 'INST_FILE',
3530 $local_file || "(not installed)");
3531 push @m, sprintf($sprintf, 'INST_VERSION',
3532 $self->inst_version) if $local_file;
05454584 3533 join "", @m, "\n";
5f05dabc
PP
3534}
3535
09d9d230
A
3536sub manpage_headline {
3537 my($self,$local_file) = @_;
3538 my(@local_file) = $local_file;
3539 $local_file =~ s/\.pm$/.pod/;
3540 push @local_file, $local_file;
3541 my(@result,$locf);
3542 for $locf (@local_file) {
3543 next unless -f $locf;
3544 my $fh = FileHandle->new($locf)
3545 or $Carp::Frontend->mydie("Couldn't open $locf: $!");
3546 my $inpod = 0;
3547 local $/ = "\n";
3548 while (<$fh>) {
2e2b7522
GS
3549 $inpod = m/^=(?!head1\s+NAME)/ ? 0 :
3550 m/^=head1\s+NAME/ ? 1 : $inpod;
09d9d230
A
3551 next unless $inpod;
3552 next if /^=/;
3553 next if /^\s+$/;
3554 chomp;
3555 push @result, $_;
3556 }
3557 close $fh;
3558 last if @result;
3559 }
3560 join " ", @result;
3561}
3562
05454584
AK
3563#-> sub CPAN::Module::cpan_file ;
3564sub cpan_file {
3565 my $self = shift;
3566 CPAN->debug($self->id) if $CPAN::DEBUG;
3567 unless (defined $self->{'CPAN_FILE'}) {
3568 CPAN::Index->reload;
3569 }
c356248b 3570 if (exists $self->{'CPAN_FILE'} && defined $self->{'CPAN_FILE'}){
05454584 3571 return $self->{'CPAN_FILE'};
c356248b
AK
3572 } elsif (exists $self->{'userid'} && defined $self->{'userid'}) {
3573 my $fullname = $CPAN::META->instance(CPAN::Author,
3574 $self->{'userid'})->fullname;
09d9d230
A
3575 my $email = $CPAN::META->instance(CPAN::Author,
3576 $self->{'userid'})->email;
3577 unless (defined $fullname && defined $email) {
3578 return "Contact Author $self->{userid} (Try ``a $self->{userid}'')";
c356248b 3579 }
09d9d230 3580 return "Contact Author $fullname <$email>";
10b2abe6 3581 } else {
05454584 3582 return "N/A";
5f05dabc
PP
3583 }
3584}
3585
05454584 3586*name = \&cpan_file;
5f05dabc 3587
05454584 3588#-> sub CPAN::Module::cpan_version ;
c356248b
AK
3589sub cpan_version {
3590 my $self = shift;
3591 $self->{'CPAN_VERSION'} = 'undef'
3592 unless defined $self->{'CPAN_VERSION'}; # I believe this is
3593 # always a bug in the
3594 # index and should be
3595 # reported as such,
3596 # but usually I find
3597 # out such an error
3598 # and do not want to
3599 # provoke too many
3600 # bugreports
3601 $self->{'CPAN_VERSION'};
3602}
5f05dabc 3603
05454584
AK
3604#-> sub CPAN::Module::force ;
3605sub force {
3606 my($self) = @_;
3607 $self->{'force_update'}++;
5f05dabc
PP
3608}
3609
05454584
AK
3610#-> sub CPAN::Module::rematein ;
3611sub rematein {
3612 my($self,$meth) = @_;
3613 $self->debug($self->id) if $CPAN::DEBUG;
3614 my $cpan_file = $self->cpan_file;
09d9d230
A
3615 if ($cpan_file eq "N/A" || $cpan_file =~ /^Contact Author/){
3616 $CPAN::Frontend->mywarn(sprintf qq{
3617 The module %s isn\'t available on CPAN.
3618
3619 Either the module has not yet been uploaded to CPAN, or it is
3620 temporary unavailable. Please contact the author to find out
3621 more about the status. Try ``i %s''.
3622},
3623 $self->id,
3624 $self->id,
3625 );
3626 return;
3627 }
05454584
AK
3628 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
3629 $pack->called_for($self->id);
3630 $pack->force if exists $self->{'force_update'};
3631 $pack->$meth();
3632 delete $self->{'force_update'};
5f05dabc
PP
3633}
3634
05454584
AK
3635#-> sub CPAN::Module::readme ;
3636sub readme { shift->rematein('readme') }
3637#-> sub CPAN::Module::look ;
3638sub look { shift->rematein('look') }
3639#-> sub CPAN::Module::get ;
3640sub get { shift->rematein('get',@_); }
3641#-> sub CPAN::Module::make ;
3642sub make { shift->rematein('make') }
3643#-> sub CPAN::Module::test ;
3644sub test { shift->rematein('test') }
3645#-> sub CPAN::Module::install ;
3646sub install {
5f05dabc 3647 my($self) = @_;
05454584
AK
3648 my($doit) = 0;
3649 my($latest) = $self->cpan_version;
3650 $latest ||= 0;
3651 my($inst_file) = $self->inst_file;
3652 my($have) = 0;
3653 if (defined $inst_file) {
3654 $have = $self->inst_version;
3655 }
e50380aa
AK
3656 if (1){ # A block for scoping $^W, the if is just for the visual
3657 # appeal
3658 local($^W)=0;
c356248b
AK
3659 if ($inst_file
3660 &&
3661 $have >= $latest
3662 &&
3663 not exists $self->{'force_update'}
3664 ) {
3665 $CPAN::Frontend->myprint( $self->id. " is up to date.\n");
e50380aa
AK
3666 } else {
3667 $doit = 1;
3668 }
5f05dabc 3669 }
05454584 3670 $self->rematein('install') if $doit;
09d9d230 3671 $CPAN::META->delete('CPAN::Queue',$self->id);
5f05dabc 3672}
05454584
AK
3673#-> sub CPAN::Module::clean ;
3674sub clean { shift->rematein('clean') }
5f05dabc 3675
05454584
AK
3676#-> sub CPAN::Module::inst_file ;
3677sub inst_file {
3678 my($self) = @_;
3679 my($dir,@packpath);
3680 @packpath = split /::/, $self->{ID};
3681 $packpath[-1] .= ".pm";
3682 foreach $dir (@INC) {
c356248b 3683 my $pmfile = MM->catfile($dir,@packpath);
05454584
AK
3684 if (-f $pmfile){
3685 return $pmfile;
da199366 3686 }
5f05dabc 3687 }
d4fd5c69 3688 return;
5f05dabc
PP
3689}
3690
05454584
AK
3691#-> sub CPAN::Module::xs_file ;
3692sub xs_file {
3693 my($self) = @_;
3694 my($dir,@packpath);
3695 @packpath = split /::/, $self->{ID};
3696 push @packpath, $packpath[-1];
3697 $packpath[-1] .= "." . $Config::Config{'dlext'};
3698 foreach $dir (@INC) {
c356248b 3699 my $xsfile = MM->catfile($dir,'auto',@packpath);
05454584
AK
3700 if (-f $xsfile){
3701 return $xsfile;
3702 }
3703 }
d4fd5c69 3704 return;
5f05dabc
PP
3705}
3706
05454584
AK
3707#-> sub CPAN::Module::inst_version ;
3708sub inst_version {
3709 my($self) = @_;
c356248b 3710 my $parsefile = $self->inst_file or return;
05454584 3711 local($^W) = 0 if $] < 5.00303 && $ExtUtils::MakeMaker::VERSION < 5.38;
2e2b7522 3712 # warn "HERE";
c356248b 3713 my $have = MM->parse_version($parsefile) || "undef";
05454584 3714 $have =~ s/\s+//g;
05454584 3715 $have;
5f05dabc
PP
3716}
3717
09d9d230
A
3718package CPAN::Tarzip;
3719