This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: perldoc, temp files, async pagers
[perl5.git] / lib / CPAN.pm
CommitLineData
5f05dabc 1package CPAN;
2use vars qw{$META $Signal $Cwd $End $Suppress_readline};
3
42d3b621 4$VERSION = '1.09';
5f05dabc 5
42d3b621 6# $Id: CPAN.pm,v 1.94 1996/12/24 00:41:14 k Exp $
5f05dabc 7
42d3b621 8# my $version = substr q$Revision: 1.94 $, 10; # only used during development
5f05dabc 9
10BEGIN {require 5.003;}
11require UNIVERSAL if $] == 5.003;
12
13use Carp ();
14use Config ();
15use Cwd ();
16use DirHandle;
17use Exporter ();
18use ExtUtils::MakeMaker ();
19use File::Basename ();
10b2abe6 20use File::Copy ();
5f05dabc 21use File::Find;
22use File::Path ();
23use IO::File ();
24use Safe ();
10b2abe6 25use Text::ParseWords ();
5f05dabc 26
27$Cwd = Cwd::cwd();
28
29END { $End++; &cleanup; }
30
31%CPAN::DEBUG = qw(
32 CPAN 1
33 Index 2
34 InfoObj 4
35 Author 8
36 Distribution 16
37 Bundle 32
38 Module 64
39 CacheMgr 128
40 Complete 256
41 FTP 512
42 Shell 1024
43 Eval 2048
44 Config 4096
45 );
46
47$CPAN::DEBUG ||= 0;
48
49package CPAN;
10b2abe6 50use vars qw($VERSION @EXPORT $AUTOLOAD $DEBUG $META);
5f05dabc 51use strict qw(vars);
52
10b2abe6
CS
53@CPAN::ISA = qw(CPAN::Debug Exporter MY); # the MY class from
54 # MakeMaker, gives us
55 # catfile and catdir
5f05dabc 56
10b2abe6
CS
57$META ||= new CPAN; # In case we reeval ourselves we
58 # need a ||
5f05dabc 59
60CPAN::Config->load;
61
62@EXPORT = qw(autobundle bundle expand force install make recompile shell test clean);
63
10b2abe6
CS
64
65
66#-> sub CPAN::autobundle ;
5f05dabc 67sub autobundle;
10b2abe6 68#-> sub CPAN::bundle ;
5f05dabc 69sub bundle;
10b2abe6 70#-> sub CPAN::expand ;
5f05dabc 71sub expand;
10b2abe6 72#-> sub CPAN::force ;
5f05dabc 73sub force;
10b2abe6 74#-> sub CPAN::install ;
5f05dabc 75sub install;
10b2abe6 76#-> sub CPAN::make ;
5f05dabc 77sub make;
10b2abe6 78#-> sub CPAN::shell ;
5f05dabc 79sub shell;
10b2abe6 80#-> sub CPAN::clean ;
5f05dabc 81sub clean;
10b2abe6 82#-> sub CPAN::test ;
5f05dabc 83sub test;
84
10b2abe6 85#-> sub CPAN::AUTOLOAD ;
5f05dabc 86sub AUTOLOAD {
87 my($l) = $AUTOLOAD;
88 $l =~ s/.*:://;
89 my(%EXPORT);
90 @EXPORT{@EXPORT} = '';
91 if (exists $EXPORT{$l}){
92 CPAN::Shell->$l(@_);
93 } else {
94 warn "CPAN doesn't know how to autoload $AUTOLOAD :-(
95Nothing Done.
96";
97 CPAN::Shell->h;
98 }
99}
100
10b2abe6 101#-> sub CPAN::all ;
5f05dabc 102sub all {
103 my($mgr,$class) = @_;
104 CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
105 CPAN::Index->reload;
106 values %{ $META->{$class} };
107}
108
109# Called by shell, not in batch mode. Not clean XXX
10b2abe6 110#-> sub CPAN::checklock ;
5f05dabc 111sub checklock {
112 my($self) = @_;
113 my $lockfile = CPAN->catfile($CPAN::Config->{cpan_home},".lock");
114 if (-f $lockfile && -M _ > 0) {
115 my $fh = IO::File->new($lockfile);
116 my $other = <$fh>;
117 $fh->close;
118 if (defined $other && $other) {
119 chomp $other;
120 return if $$==$other; # should never happen
121 print qq{There seems to be running another CPAN process ($other). Trying to contact...\n};
122 if (kill 0, $other) {
123 Carp::croak qq{Other job is running.\n}.
124 qq{You may want to kill it and delete the lockfile, maybe. On UNIX try:\n}.
125 qq{ kill $other\n}.
126 qq{ rm $lockfile\n};
127 } elsif (-w $lockfile) {
128 my($ans)=
129 ExtUtils::MakeMaker::prompt
130 (qq{Other job not responding. Shall I overwrite the lockfile? (Y/N)},"y");
131 print("Ok, bye\n"), exit unless $ans =~ /^y/i;
132 } else {
133 Carp::croak(
134 qq{Lockfile $lockfile not writeable by you. Cannot proceed.\n}.
135 qq{ On UNIX try:\n}.
136 qq{ rm $lockfile\n}.
137 qq{ and then rerun us.\n}
138 );
139 }
140 }
141 }
142 File::Path::mkpath($CPAN::Config->{cpan_home});
143 my $fh;
144 unless ($fh = IO::File->new(">$lockfile")) {
145 if ($! =~ /Permission/) {
146 my $incc = $INC{'CPAN/Config.pm'};
147 my $myincc = MY->catfile($ENV{HOME},'.cpan','CPAN','MyConfig.pm');
148 print qq{
149
150Your configuration suggests that CPAN.pm should use a working
151directory of
152 $CPAN::Config->{cpan_home}
153Unfortunately we could not create the lock file
154 $lockfile
155due to permission problems.
156
157Please make sure that the configuration variable
158 \$CPAN::Config->{cpan_home}
159points to a directory where you can write a .lock file. You can set
160this variable in either
161 $incc
162or
163 $myincc
164
165};
166 }
167 Carp::croak "Could not open >$lockfile: $!";
168 }
169 print $fh $$, "\n";
170 $self->{LOCK} = $lockfile;
171 $fh->close;
172 $SIG{'TERM'} = sub { &cleanup; die "Got SIGTERM, leaving"; };
173 $SIG{'INT'} = sub { &cleanup, die "Got a second SIGINT" if $Signal; $Signal = 1; };
174 $SIG{'__DIE__'} = \&cleanup;
175 print STDERR "Signal handler set.\n" unless $CPAN::Config->{'inhibit_startup_message'};
176}
177
10b2abe6 178#-> sub CPAN::DESTROY ;
5f05dabc 179sub DESTROY {
180 &cleanup; # need an eval?
181}
182
10b2abe6 183#-> sub CPAN::exists ;
5f05dabc 184sub exists {
185 my($mgr,$class,$id) = @_;
186 CPAN::Index->reload;
187 Carp::croak "exists called without class argument" unless $class;
188 $id ||= "";
189 exists $META->{$class}{$id};
190}
191
10b2abe6 192#-> sub CPAN::hasFTP ;
5f05dabc 193sub hasFTP {
194 my($self,$arg) = @_;
195 if (defined $arg) {
196 return $self->{'hasFTP'} = $arg;
197 } elsif (not defined $self->{'hasFTP'}) {
198 eval {require Net::FTP;};
199 $self->{'hasFTP'} = $@ ? 0 : 1;
200 }
201 return $self->{'hasFTP'};
202}
203
10b2abe6 204#-> sub CPAN::hasLWP ;
5f05dabc 205sub hasLWP {
206 my($self,$arg) = @_;
207 if (defined $arg) {
208 return $self->{'hasLWP'} = $arg;
209 } elsif (not defined $self->{'hasLWP'}) {
210 eval {require LWP;};
211 $LWP::VERSION ||= 0;
212 $self->{'hasLWP'} = $LWP::VERSION >= 4.98;
213 }
214 return $self->{'hasLWP'};
215}
216
10b2abe6 217#-> sub CPAN::hasMD5 ;
5f05dabc 218sub hasMD5 {
219 my($self,$arg) = @_;
220 if (defined $arg) {
221 $self->{'hasMD5'} = $arg;
222 } elsif (not defined $self->{'hasMD5'}) {
223 eval {require MD5;};
224 if ($@) {
225 print "MD5 security checks disabled because MD5 not installed. Please consider installing MD5\n";
226 $self->{'hasMD5'} = 0;
227 } else {
228 $self->{'hasMD5'}++;
229 }
230 }
231 return $self->{'hasMD5'};
232}
233
10b2abe6 234#-> sub CPAN::instance ;
5f05dabc 235sub instance {
236 my($mgr,$class,$id) = @_;
237 CPAN::Index->reload;
238 Carp::croak "instance called without class argument" unless $class;
239 $id ||= "";
240 $META->{$class}{$id} ||= $class->new(ID => $id );
241}
242
10b2abe6 243#-> sub CPAN::new ;
5f05dabc 244sub new {
245 bless {}, shift;
246}
247
10b2abe6 248#-> sub CPAN::cleanup ;
5f05dabc 249sub cleanup {
250 local $SIG{__DIE__} = '';
251 my $i = 0; my $ineval = 0; my $sub;
252 while ((undef,undef,undef,$sub) = caller(++$i)) {
253 $ineval = 1, last if $sub eq '(eval)';
254 }
255 return if $ineval && !$End;
256 return unless defined $META->{'LOCK'};
257 return unless -f $META->{'LOCK'};
258 unlink $META->{'LOCK'};
259 print STDERR "Lockfile removed.\n";
260# my $mess = Carp::longmess(@_);
261# die @_;
262}
263
10b2abe6 264#-> sub CPAN::shell ;
5f05dabc 265sub shell {
266 $Suppress_readline ||= ! -t STDIN;
267
268 my $prompt = "cpan> ";
269 local($^W) = 1;
270 my $term;
271 unless ($Suppress_readline) {
272 require Term::ReadLine;
273 import Term::ReadLine;
274 $term = new Term::ReadLine 'CPAN Monitor';
275 $readline::rl_completion_function =
276 $readline::rl_completion_function = 'CPAN::Complete::complete';
277 }
278
279 no strict;
280 $META->checklock();
281 my $cwd = Cwd::cwd();
282 # How should we determine if we have more than stub ReadLine enabled?
283 my $rl_avail = $Suppress_readline ? "suppressed" :
284 defined &Term::ReadLine::Perl::readline ? "enabled" :
10b2abe6 285 "available (get Term::ReadKey and Term::ReadLine)";
5f05dabc 286
287 print qq{
288cpan shell -- CPAN exploration and modules installation (v$CPAN::VERSION)
289Readline support $rl_avail
290
291} unless $CPAN::Config->{'inhibit_startup_message'} ;
292 while () {
293 if ($Suppress_readline) {
294 print $prompt;
295 last unless defined (chomp($_ = <>));
296 } else {
297 last unless defined ($_ = $term->readline($prompt));
298 }
299 s/^\s//;
300 next if /^$/;
301 $_ = 'h' if $_ eq '?';
302 if (/^\!/) {
303 s/^\!//;
304 my($eval) = $_;
305 package CPAN::Eval;
306 use vars qw($import_done);
307 CPAN->import(':DEFAULT') unless $import_done++;
308 CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
309 eval($eval);
310 warn $@ if $@;
311 } elsif (/^q(?:uit)?$/i) {
312 last;
313 } elsif (/./) {
10b2abe6
CS
314 my(@line);
315 eval { @line = Text::ParseWords::shellwords($_) };
316 warn($@), next if $@;
317 $CPAN::META->debug("line[".join(":",@line)."]") if $CPAN::DEBUG;
5f05dabc 318 my $command = shift @line;
319 eval { CPAN::Shell->$command(@line) };
320 warn $@ if $@;
321 }
322 } continue {
323 &cleanup, die if $Signal;
324 chdir $cwd;
325 print "\n";
326 }
327}
328
329package CPAN::Shell;
10b2abe6
CS
330use vars qw($AUTOLOAD);
331@CPAN::Shell::ISA = qw(CPAN::Debug);
5f05dabc 332
333# private function ro re-eval this module (handy during development)
10b2abe6 334#-> sub CPAN::Shell::AUTOLOAD ;
5f05dabc 335sub AUTOLOAD {
336 warn "CPAN::Shell doesn't know how to autoload $AUTOLOAD :-(
337Nothing Done.
338";
339 CPAN::Shell->h;
340}
341
10b2abe6 342#-> sub CPAN::Shell::h ;
5f05dabc 343sub h {
344 my($class,$about) = @_;
345 if (defined $about) {
346 print "Detailed help not yet implemented\n";
347 } else {
348 print q{
349command arguments description
350a string authors
351b or display bundles
352d /regex/ info distributions
353m or about modules
354i none anything of above
355
356r as reinstall recommendations
357u above uninstalled distributions
10b2abe6 358See manpage for autobundle, recompile, force, etc.
5f05dabc 359
360make modules, make
361test dists, bundles, make test (implies make)
362install "r" or "u" make install (implies test)
363clean make clean
364
365reload index|cpan load most recent indices/CPAN.pm
366h or ? display this menu
367o various set and query options
368! perl-code eval a perl command
369q quit the shell subroutine
370};
371 }
372}
373
10b2abe6 374#-> sub CPAN::Shell::a ;
5f05dabc 375sub a { print shift->format_result('Author',@_);}
10b2abe6 376#-> sub CPAN::Shell::b ;
5f05dabc 377sub b {
378 my($self,@which) = @_;
10b2abe6
CS
379 my($incdir,$bdir,$dh);
380 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
381 $bdir = $CPAN::META->catdir($incdir,"Bundle");
382 if ($dh = DirHandle->new($bdir)) { # may fail
383 my($entry);
384 for $entry ($dh->read) {
385 next if -d $CPAN::META->catdir($bdir,$entry);
386 next unless $entry =~ s/\.pm$//;
387 $CPAN::META->instance('CPAN::Bundle',"Bundle::$entry");
388 }
389 }
5f05dabc 390 }
391 print $self->format_result('Bundle',@which);
392}
10b2abe6 393#-> sub CPAN::Shell::d ;
5f05dabc 394sub d { print shift->format_result('Distribution',@_);}
10b2abe6 395#-> sub CPAN::Shell::m ;
5f05dabc 396sub m { print shift->format_result('Module',@_);}
397
10b2abe6 398#-> sub CPAN::Shell::i ;
5f05dabc 399sub i {
400 my($self) = shift;
401 my(@args) = @_;
402 my(@type,$type,@m);
403 @type = qw/Author Bundle Distribution Module/;
404 @args = '/./' unless @args;
405 my(@result);
406 for $type (@type) {
407 push @result, $self->expand($type,@args);
408 }
409 my $result = @result==1 ? $result[0]->as_string : join "", map {$_->as_glimpse} @result;
410 $result ||= "No objects found of any type for argument @args\n";
411 print $result;
412}
413
10b2abe6 414#-> sub CPAN::Shell::o ;
5f05dabc 415sub o {
416 my($self,$o_type,@o_what) = @_;
417 $o_type ||= "";
10b2abe6 418 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
5f05dabc 419 if ($o_type eq 'conf') {
420 shift @o_what if @o_what && $o_what[0] eq 'help';
421 if (!@o_what) {
422 my($k,$v);
423 print "CPAN::Config options:\n";
424 for $k (sort keys %CPAN::Config::can) {
425 $v = $CPAN::Config::can{$k};
426 printf " %-18s %s\n", $k, $v;
427 }
428 print "\n";
429 for $k (sort keys %$CPAN::Config) {
430 $v = $CPAN::Config->{$k};
431 if (ref $v) {
432 printf " %-18s\n", $k;
433 print map {"\t$_\n"} @{$v};
434 } else {
435 printf " %-18s %s\n", $k, $v;
436 }
437 }
438 print "\n";
439 } elsif (!CPAN::Config->edit(@o_what)) {
440 print qq[Type 'o conf' to view configuration edit options\n\n];
441 }
442 } elsif ($o_type eq 'debug') {
443 my(%valid);
444 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
445 if (@o_what) {
446 while (@o_what) {
447 my($what) = shift @o_what;
448 if ( exists $CPAN::DEBUG{$what} ) {
449 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
450 } elsif ($what =~ /^\d/) {
451 $CPAN::DEBUG = $what;
452 } elsif (lc $what eq 'all') {
453 my($max) = 0;
454 for (values %CPAN::DEBUG) {
455 $max += $_;
456 }
457 $CPAN::DEBUG = $max;
458 } else {
459 for (keys %CPAN::DEBUG) {
460 next unless lc($_) eq lc($what);
461 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
462 }
463 print "unknown argument $what\n";
464 }
465 }
466 } else {
467 print "Valid options for debug are ".join(", ",sort(keys %CPAN::DEBUG), 'all').
468 " or a number. Completion works on the options. Case is ignored.\n\n";
469 }
470 if ($CPAN::DEBUG) {
471 print "Options set for debugging:\n";
472 my($k,$v);
473 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
474 $v = $CPAN::DEBUG{$k};
475 printf " %-14s(%s)\n", $k, $v if $v & $CPAN::DEBUG;
476 }
477 } else {
478 print "Debugging turned off completely.\n";
479 }
480 } else {
481 print qq{
482Known options:
483 conf set or get configuration variables
484 debug set or get debugging options
485};
486 }
487}
488
10b2abe6 489#-> sub CPAN::Shell::reload ;
5f05dabc 490sub reload {
491 if ($_[1] =~ /cpan/i) {
492 CPAN->debug("reloading the whole CPAN.pm") if $CPAN::DEBUG;
493 my $fh = IO::File->new($INC{'CPAN.pm'});
494 local $/;
495 undef $/;
496 eval <$fh>;
497 warn $@ if $@;
498 } elsif ($_[1] =~ /index/) {
499 CPAN::Index->force_reload;
500 }
501}
502
10b2abe6 503#-> sub CPAN::Shell::_binary_extensions ;
5f05dabc 504sub _binary_extensions {
505 my($self) = shift @_;
506 my(@result,$module,%seen,%need,$headerdone);
507 for $module ($self->expand('Module','/./')) {
508 my $file = $module->cpan_file;
509 next if $file eq "N/A";
510 next if $file =~ /^Contact Author/;
511 next if $file =~ /perl5[._-]\d{3}(?:[\d_]+)?\.tar[._-]gz$/;
512 next unless $module->xs_file;
513 push @result, $module;
514 }
515# print join " | ", @result;
516# print "\n";
517 return @result;
518}
519
10b2abe6 520#-> sub CPAN::Shell::recompile ;
5f05dabc 521sub recompile {
522 my($self) = shift @_;
523 my($module,@module,$cpan_file,%dist);
524 @module = $self->_binary_extensions();
525 for $module (@module){ # we force now and compile later, so we don't do it twice
526 $cpan_file = $module->cpan_file;
527 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
528 $pack->force;
529 $dist{$cpan_file}++;
530 }
531 for $cpan_file (sort keys %dist) {
532 print " CPAN: Recompiling $cpan_file\n\n";
533 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
534 $pack->install;
535 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
536 # stop a package from recompiling,
537 # e.g. IO-1.12 when we have perl5.003_10
538 }
539}
540
10b2abe6 541#-> sub CPAN::Shell::_u_r_common ;
5f05dabc 542sub _u_r_common {
543 my($self) = shift @_;
544 my($what) = shift @_;
545 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
546 Carp::croak "Usage: \$obj->_u_r_common($what)" unless defined $what;
547 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless $what =~ /^[aru]$/;
548 my(@args) = @_;
549 @args = '/./' unless @args;
550 my(@result,$module,%seen,%need,$headerdone,$version_zeroes);
551 $version_zeroes = 0;
552 my $sprintf = "%-25s %9s %9s %s\n";
553 for $module ($self->expand('Module',@args)) {
554 my $file = $module->cpan_file;
555 next unless defined $file; # ??
556 my($latest) = $module->cpan_version || 0;
557 my($inst_file) = $module->inst_file;
558 my($have);
559 if ($inst_file){
560 if ($what eq "a") {
561 $have = $module->inst_version;
562 } elsif ($what eq "r") {
563 $have = $module->inst_version;
564 local($^W) = 0;
565 $version_zeroes++ unless $have;
566 next if $have >= $latest;
567 } elsif ($what eq "u") {
568 next;
569 }
570 } else {
571 if ($what eq "a") {
572 next;
573 } elsif ($what eq "r") {
574 next;
575 } elsif ($what eq "u") {
576 $have = "-";
577 }
578 }
579 $seen{$file} ||= 0;
580 if ($what eq "a") {
581 push @result, sprintf "%s %s\n", $module->id, $have;
582 } elsif ($what eq "r") {
583 push @result, $module->id;
584 next if $seen{$file}++;
585 } elsif ($what eq "u") {
586 push @result, $module->id;
587 next if $seen{$file}++;
588 next if $file =~ /^Contact/;
589 }
590 unless ($headerdone++){
591 print "\n";
592 printf $sprintf, "Package namespace", "installed", "latest", "in CPAN file";
593 }
594 $latest = substr($latest,0,8) if length($latest) > 8;
595 $have = substr($have,0,8) if length($have) > 8;
596 printf $sprintf, $module->id, $have, $latest, $file;
597 $need{$module->id}++;
598 return if $CPAN::Signal; # this is sometimes lengthy
599 }
600 unless (%need) {
601 if ($what eq "u") {
602 print "No modules found for @args\n";
603 } elsif ($what eq "r") {
604 print "All modules are up to date for @args\n";
605 }
606 }
607 if ($what eq "r" && $version_zeroes) {
608 my $s = $version_zeroes>1 ? "s have" : " has";
609 print qq{$version_zeroes installed module$s no version number to compare\n};
610 }
611 @result;
612}
613
10b2abe6 614#-> sub CPAN::Shell::r ;
5f05dabc 615sub r {
616 shift->_u_r_common("r",@_);
617}
618
10b2abe6 619#-> sub CPAN::Shell::u ;
5f05dabc 620sub u {
621 shift->_u_r_common("u",@_);
622}
623
10b2abe6 624#-> sub CPAN::Shell::autobundle ;
5f05dabc 625sub autobundle {
626 my($self) = shift;
627 my(@bundle) = $self->_u_r_common("a",@_);
628 my($todir) = $CPAN::META->catdir($CPAN::Config->{'cpan_home'},"Bundle");
629 File::Path::mkpath($todir);
630 unless (-d $todir) {
631 print "Couldn't mkdir $todir for some reason\n";
632 return;
633 }
634 my($y,$m,$d) = (localtime)[5,4,3];
635 $y+=1900;
636 $m++;
637 my($c) = 0;
638 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
639 my($to) = $CPAN::META->catfile($todir,"$me.pm");
640 while (-f $to) {
641 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
642 $to = $CPAN::META->catfile($todir,"$me.pm");
643 }
644 my($fh) = IO::File->new(">$to") or Carp::croak "Can't open >$to: $!";
645 $fh->print(
646 "package Bundle::$me;\n\n",
647 "\$VERSION = '0.01';\n\n",
648 "1;\n\n",
649 "__END__\n\n",
650 "=head1 NAME\n\n",
651 "Bundle::$me - Snapshot of installation on ",
652 $Config::Config{'myhostname'},
653 " on ",
654 scalar(localtime),
655 "\n\n=head1 SYNOPSIS\n\n",
656 "perl -MCPAN -e 'install Bundle::$me'\n\n",
657 "=head1 CONTENTS\n\n",
658 join("\n", @bundle),
659 "\n\n=head1 CONFIGURATION\n\n",
660 Config->myconfig,
661 "\n\n=head1 AUTHOR\n\n",
662 "This Bundle has been generated automatically by the autobundle routine in CPAN.pm.\n",
663 );
664 $fh->close;
665 print "\nWrote bundle file
666 $to\n\n";
667}
668
10b2abe6 669#-> sub CPAN::Shell::expand ;
5f05dabc 670sub expand {
671 shift;
672 my($type,@args) = @_;
673 my($arg,@m);
674 for $arg (@args) {
675 my $regex;
676 if ($arg =~ m|^/(.*)/$|) {
677 $regex = $1;
678 }
679 my $class = "CPAN::$type";
680 my $obj;
681 if (defined $regex) {
682 for $obj ( sort {$a->id cmp $b->id} $CPAN::META->all($class)) {
683 push @m, $obj if $obj->id =~ /$regex/i or $obj->can('name') && $obj->name =~ /$regex/i;
684 }
685 } else {
686 my($xarg) = $arg;
687 if ( $type eq 'Bundle' ) {
688 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
689 }
690 if ($CPAN::META->exists($class,$xarg)) {
691 $obj = $CPAN::META->instance($class,$xarg);
692 } elsif ($obj = $CPAN::META->exists($class,$arg)) {
693 $obj = $CPAN::META->instance($class,$arg);
694 } else {
695 next;
696 }
697 push @m, $obj;
698 }
699 }
700 return @m;
701}
702
10b2abe6 703#-> sub CPAN::Shell::format_result ;
5f05dabc 704sub format_result {
705 my($self) = shift;
706 my($type,@args) = @_;
707 @args = '/./' unless @args;
708 my(@result) = $self->expand($type,@args);
709 my $result = @result==1 ? $result[0]->as_string : join "", map {$_->as_glimpse} @result;
710 $result ||= "No objects of type $type found for argument @args\n";
711 $result;
712}
713
10b2abe6 714#-> sub CPAN::Shell::rematein ;
5f05dabc 715sub rematein {
716 shift;
717 my($meth,@some) = @_;
718 my $pragma = "";
719 if ($meth eq 'force') {
720 $pragma = $meth;
721 $meth = shift @some;
722 }
723 CPAN->debug("pragma[$pragma]meth[$meth] some[@some]") if $CPAN::DEBUG;
724 my($s,@s);
725 foreach $s (@some) {
726 my $obj;
727 if (ref $s) {
728 $obj = $s;
729 } elsif ($s =~ m|/|) { # looks like a file
730 $obj = $CPAN::META->instance('CPAN::Distribution',$s);
731 } elsif ($s =~ m|^Bundle::|) {
732 $obj = $CPAN::META->instance('CPAN::Bundle',$s);
733 } else {
734 $obj = $CPAN::META->instance('CPAN::Module',$s) if $CPAN::META->exists('CPAN::Module',$s);
735 }
736 if (ref $obj) {
737 CPAN->debug(qq{pragma[$pragma] meth[$meth] obj[$obj] as_string\[}.$obj->as_string.qq{\]}) if $CPAN::DEBUG;
738 $obj->$pragma() if $pragma && $obj->can($pragma);
739 $obj->$meth();
740 } else {
741 print "Warning: Cannot $meth $s, don't know what it is\n";
742 }
743 }
744}
745
10b2abe6 746#-> sub CPAN::Shell::force ;
5f05dabc 747sub force { shift->rematein('force',@_); }
10b2abe6 748#-> sub CPAN::Shell::readme ;
5f05dabc 749sub readme { shift->rematein('readme',@_); }
10b2abe6 750#-> sub CPAN::Shell::make ;
5f05dabc 751sub make { shift->rematein('make',@_); }
10b2abe6 752#-> sub CPAN::Shell::clean ;
5f05dabc 753sub clean { shift->rematein('clean',@_); }
10b2abe6 754#-> sub CPAN::Shell::test ;
5f05dabc 755sub test { shift->rematein('test',@_); }
10b2abe6 756#-> sub CPAN::Shell::install ;
5f05dabc 757sub install { shift->rematein('install',@_); }
758
759package CPAN::FTP;
10b2abe6
CS
760use vars qw($Ua);
761@CPAN::FTP::ISA = qw(CPAN::Debug);
5f05dabc 762
10b2abe6 763#-> sub CPAN::FTP::ftp_get ;
5f05dabc 764sub ftp_get {
765 my($class,$host,$dir,$file,$target) = @_;
766 $class->debug(
767 qq[Going to fetch file [$file] from dir [$dir]
768 on host [$host] as local [$target]\n]
769 ) if $CPAN::DEBUG;
770 my $ftp = Net::FTP->new($host);
771 $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
772 $class->debug(qq[Going to ->login("anonymous","$Config::Config{'cf_email'}")\n]);
773 unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
774 warn "Couldn't login on $host";
775 return;
776 }
777 # print qq[Going to ->cwd("$dir")\n];
778 unless ( $ftp->cwd($dir) ){
779 warn "Couldn't cwd $dir";
780 return;
781 }
782 $ftp->binary;
10b2abe6 783 $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
5f05dabc 784 unless ( $ftp->get($file,$target) ){
785 warn "Couldn't fetch $file from $host";
786 return;
787 }
788 $ftp->quit;
789}
790
10b2abe6 791#-> sub CPAN::FTP::localize ;
5f05dabc 792sub localize {
793 my($self,$file,$aslocal,$force) = @_;
794 $force ||= 0;
795 Carp::croak "Usage: ->localize(cpan_file,as_local_file[,$force])" unless defined $aslocal;
796 $self->debug("file [$file] aslocal [$aslocal]") if $CPAN::DEBUG;
797
798 return $aslocal if -f $aslocal && -r _ && ! $force;
799
800 my($aslocal_dir) = File::Basename::dirname($aslocal);
801 File::Path::mkpath($aslocal_dir);
802 print STDERR qq{Warning: You are not allowed to write into directory "$aslocal_dir".
803 I\'ll continue, but if you face any problems, they may be due
804 to insufficient permissions.\n} unless -w $aslocal_dir;
805
806 # Inheritance is not easier to manage than a few if/else branches
807 if ($CPAN::META->hasLWP) {
808 require LWP::UserAgent;
809 unless ($Ua) {
810 $Ua = new LWP::UserAgent;
811 $Ua->proxy('ftp', $ENV{'ftp_proxy'}) if defined $ENV{'ftp_proxy'};
812 $Ua->proxy('http', $ENV{'http_proxy'}) if defined $ENV{'http_proxy'};
813 $Ua->no_proxy($ENV{'no_proxy'}) if defined $ENV{'no_proxy'};
814 }
815 }
816
817 # Try the list of urls for each single object. We keep a record
818 # where we did get a file from
819 for (0..$#{$CPAN::Config->{urllist}}) {
820 my $url = $CPAN::Config->{urllist}[$_];
821 $url .= "/" unless substr($url,-1) eq "/";
822 $url .= $file;
823 $self->debug("localizing[$url]") if $CPAN::DEBUG;
824 if ($url =~ /^file:/) {
825 my $l;
826 if ($CPAN::META->hasLWP) {
827 require URI::URL;
828 my $u = new URI::URL $url;
829 $l = $u->path;
10b2abe6
CS
830 } else { # works only on Unix, is poorly constructed, but
831 # hopefully better than nothing.
832 # RFC 1738 says fileurl BNF is
833 # fileurl = "file://" [ host | "localhost" ] "/" fpath
834 # Thanks to "Mark D. Baushke" <mdb@cisco.com> for the code
835 ($l = $url) =~ s,^file://[^/]+,,; # discard the host part
836 $l =~ s/^file://; # assume they meant file://localhost
5f05dabc 837 }
838 return $l if -f $l && -r _;
839 }
840
841 if ($CPAN::META->hasLWP) {
842 print "Fetching $url\n";
843 my $res = $Ua->mirror($url, $aslocal);
844 if ($res->is_success) {
845 return $aslocal;
846 }
10b2abe6
CS
847 }
848 if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
5f05dabc 849 my($host,$dir,$getfile) = ($1,$2,$3);
10b2abe6
CS
850 if ($CPAN::META->hasFTP) {
851 $dir =~ s|/+|/|g;
852 $self->debug("Going to fetch file [$getfile]
853 from dir [$dir]
854 on host [$host]
855 as local [$aslocal]") if $CPAN::DEBUG;
856 CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal) && return $aslocal;
857 } elsif (-x $CPAN::Config->{'ftp'}) {
858 my($netrc) = CPAN::FTP::netrc->new;
42d3b621 859 if ($netrc->hasdefault() || $netrc->contains($host)) {
10b2abe6
CS
860 print(
861 qq{
862 Trying with external ftp to get $url
863 As this requires some features that are not thoroughly tested, we\'re
864 not sure, that we get it right. Please, install Net::FTP as soon
865 as possible. Just type "install Net::FTP". Thank you.
866
867}
868 );
42d3b621 869 my($fh) = IO::File->new;
10b2abe6
CS
870 my($cwd) = Cwd::cwd();
871 chdir $aslocal_dir;
872 my($targetfile) = File::Basename::basename($aslocal);
873 my(@dialog);
874 push @dialog, map {"cd $_\n"} split "/", $dir;
875 push @dialog, "get $getfile $targetfile\n";
876 push @dialog, "quit\n";
42d3b621
A
877 open($fh, "|$CPAN::Config->{'ftp'} $host") or die "Couldn't open ftp: $!";
878 # pilot is blind now
879 foreach (@dialog) {
880 $fh->print($_);
10b2abe6 881 }
10b2abe6
CS
882 chdir($cwd);
883 return $aslocal;
884 } else {
42d3b621
A
885 my($netrcfile) = $netrc->netrc();
886 if ($netrcfile){
10b2abe6 887 print qq{ Your $netrcfile does not contain host $host.\n}
42d3b621
A
888 } else {
889 print qq{ I could not find or open your .netrc file.\n}
10b2abe6
CS
890 }
891 print qq{ If you want to use external ftp,
42d3b621
A
892 please enter the host $host (or a default entry)
893 into your .netrc file and retry.
10b2abe6
CS
894
895 The format of a proper entry in your .netrc file would be:
42d3b621
A
896 machine $host
897 login ftp
898 password $Config::Config{cf_email}
5f05dabc 899
42d3b621
A
900 A typical default entry would be:
901 default login ftp password $Config::Config{cf_email}
10b2abe6 902
42d3b621
A
903 Please make also sure, your .netrc will not be readable by others.
904 You don\'t have to leave and restart CPAN.pm, I\'ll look again next
905 time I come around here.\n\n};
906 }
10b2abe6 907 }
42d3b621 908 sleep 2;
5f05dabc 909 }
10b2abe6
CS
910 if (-x $CPAN::Config->{'lynx'}) {
911## $self->debug("Trying with lynx for [$url]") if $CPAN::DEBUG;
912 my($want_compressed);
913 print(
914 qq{
915 Trying with lynx to get $url
916 As lynx has so many options and versions, we\'re not sure, that we
917 get it right. It is recommended that you install Net::FTP as soon
918 as possible. Just type "install Net::FTP". Thank you.
919
920}
921 );
922 $want_compressed = $aslocal =~ s/\.gz//;
923 my($system) = "$CPAN::Config->{'lynx'} -source '$url' > $aslocal";
924 if (system($system)==0) {
925 if ($want_compressed) {
926 $system = "$CPAN::Config->{'gzip'} -dt $aslocal";
927 if (system($system)==0) {
928 rename $aslocal, "$aslocal.gz";
929 } else {
930 $system = "$CPAN::Config->{'gzip'} $aslocal";
931 system($system);
932 }
933 return "$aslocal.gz";
934 } else {
935 $system = "$CPAN::Config->{'gzip'} -dt $aslocal";
936 if (system($system)==0) {
937 $system = "$CPAN::Config->{'gzip'} -d $aslocal";
938 system($system);
939 } else {
940 # should be fine, eh?
941 }
942 return $aslocal;
943 }
944 }
945 }
946 warn "Can't access URL $url.
947 Either get LWP or Net::FTP
948 or an external lynx or ftp";
5f05dabc 949 }
950 Carp::croak("Cannot fetch $file from anywhere");
951}
952
10b2abe6
CS
953package CPAN::FTP::external;
954
955package CPAN::FTP::netrc;
956
957sub new {
958 my($class) = @_;
959 my $file = MY->catfile($ENV{HOME},".netrc");
42d3b621
A
960 my($fh,@machines,$hasdefault);
961 $hasdefault = 0;
10b2abe6
CS
962 if($fh = IO::File->new($file,"r")){
963 local($/) = "";
42d3b621
A
964 NETRC: while (<$fh>) {
965 my(@tokens) = split ' ', $_;
966 TOKEN: while (@tokens) {
967 my($t) = shift @tokens;
968 $hasdefault++, last NETRC if $t eq "default"; # we will most
969 # probably be
970 # able to anonftp
971 last TOKEN if $t eq "macdef";
972 if ($t eq "machine") {
973 push @machines, shift @tokens;
974 }
975 }
10b2abe6
CS
976 }
977 } else {
978 $file = "";
979 }
980 bless {
42d3b621
A
981 'mach' => [@machines],
982 'netrc' => $file,
983 'hasdefault' => $hasdefault,
10b2abe6
CS
984 }, $class;
985}
986
42d3b621
A
987sub hasdefault { shift->{'hasdefault'} }
988sub netrc { shift->{'netrc'} }
10b2abe6
CS
989sub contains {
990 my($self,$mach) = @_;
42d3b621 991 scalar grep {$_ eq $mach} @{$self->{'mach'}};
10b2abe6
CS
992}
993
5f05dabc 994package CPAN::Complete;
10b2abe6 995@CPAN::Complete::ISA = qw(CPAN::Debug);
5f05dabc 996
10b2abe6 997#-> sub CPAN::Complete::complete ;
5f05dabc 998sub complete {
999 my($word,$line,$pos) = @_;
1000 $word ||= "";
1001 $line ||= "";
1002 $pos ||= 0;
1003 CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1004 $line =~ s/^\s*//;
1005 my @return;
1006 if ($pos == 0) {
1007 @return = grep(/^$word/, sort qw(! a b d h i m o q r u autobundle clean make test install reload));
1008 } elsif ( $line !~ /^[\!abdhimorut]/ ) {
1009 @return = ();
1010 } elsif ($line =~ /^a\s/) {
1011 @return = completex('CPAN::Author',$word);
1012 } elsif ($line =~ /^b\s/) {
1013 @return = completex('CPAN::Bundle',$word);
1014 } elsif ($line =~ /^d\s/) {
1015 @return = completex('CPAN::Distribution',$word);
1016 } elsif ($line =~ /^([mru]\s|(make|clean|test|install)\s)/ ) {
1017 @return = (completex('CPAN::Module',$word),completex('CPAN::Bundle',$word));
1018 } elsif ($line =~ /^i\s/) {
1019 @return = complete_any($word);
1020 } elsif ($line =~ /^reload\s/) {
1021 @return = complete_reload($word,$line,$pos);
1022 } elsif ($line =~ /^o\s/) {
1023 @return = complete_option($word,$line,$pos);
1024 } else {
1025 @return = ();
1026 }
1027 return @return;
1028}
1029
10b2abe6 1030#-> sub CPAN::Complete::completex ;
5f05dabc 1031sub completex {
1032 my($class, $word) = @_;
1033 grep /^\Q$word\E/, map { $_->id } $CPAN::META->all($class);
1034}
1035
10b2abe6 1036#-> sub CPAN::Complete::complete_any ;
5f05dabc 1037sub complete_any {
1038 my($word) = shift;
1039 return (
1040 completex('CPAN::Author',$word),
1041 completex('CPAN::Bundle',$word),
1042 completex('CPAN::Distribution',$word),
1043 completex('CPAN::Module',$word),
1044 );
1045}
1046
10b2abe6 1047#-> sub CPAN::Complete::complete_reload ;
5f05dabc 1048sub complete_reload {
1049 my($word,$line,$pos) = @_;
1050 $word ||= "";
1051 my(@words) = split " ", $line;
1052 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1053 my(@ok) = qw(cpan index);
1054 return @ok if @words==1;
1055 return grep /^\Q$word\E/, @ok if @words==2 && $word;
1056}
1057
10b2abe6 1058#-> sub CPAN::Complete::complete_option ;
5f05dabc 1059sub complete_option {
1060 my($word,$line,$pos) = @_;
1061 $word ||= "";
1062 my(@words) = split " ", $line;
1063 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
1064 my(@ok) = qw(conf debug);
1065 return @ok if @words==1;
1066 return grep /^\Q$word\E/, @ok if @words==2 && $word;
1067 if (0) {
1068 } elsif ($words[1] eq 'index') {
1069 return ();
1070 } elsif ($words[1] eq 'conf') {
1071 return CPAN::Config::complete(@_);
1072 } elsif ($words[1] eq 'debug') {
1073 return sort grep /^\Q$word\E/, sort keys %CPAN::DEBUG, 'all';
1074 }
1075}
1076
1077package CPAN::Index;
10b2abe6
CS
1078use vars qw($last_time);
1079@CPAN::Index::ISA = qw(CPAN::Debug);
5f05dabc 1080$last_time ||= 0;
1081
10b2abe6 1082#-> sub CPAN::Index::force_reload ;
5f05dabc 1083sub force_reload {
1084 my($class) = @_;
1085 $CPAN::Index::last_time = 0;
1086 $class->reload(1);
1087}
1088
10b2abe6 1089#-> sub CPAN::Index::reload ;
5f05dabc 1090sub reload {
1091 my($cl,$force) = @_;
1092 my $time = time;
1093
1094 # XXX check if a newer one is available. (We currently read it from time to time)
1095 return if $last_time + $CPAN::Config->{index_expire}*86400 > $time;
1096 $last_time = $time;
1097
1098 $cl->read_authindex($cl->reload_x("authors/01mailrc.txt.gz","01mailrc.gz",$force));
1099 return if $CPAN::Signal; # this is sometimes lengthy
1100 $cl->read_modpacks($cl->reload_x("modules/02packages.details.txt.gz","02packag.gz",$force));
1101 return if $CPAN::Signal; # this is sometimes lengthy
1102 $cl->read_modlist($cl->reload_x("modules/03modlist.data.gz","03mlist.gz",$force));
1103}
1104
10b2abe6 1105#-> sub CPAN::Index::reload_x ;
5f05dabc 1106sub reload_x {
1107 my($cl,$wanted,$localname,$force) = @_;
1108 $force ||= 0;
1109 my $abs_wanted = CPAN->catfile($CPAN::Config->{'keep_source_where'},$localname);
1110 if (-f $abs_wanted && -M $abs_wanted < $CPAN::Config->{'index_expire'} && !$force) {
1111 my($s) = $CPAN::Config->{'index_expire'} != 1;
1112 $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} day$s. I\'ll use that.\n});
1113 return $abs_wanted;
1114 } else {
1115 $force ||= 1;
1116 }
1117 return CPAN::FTP->localize($wanted,$abs_wanted,$force);
1118}
1119
10b2abe6 1120#-> sub CPAN::Index::read_authindex ;
5f05dabc 1121sub read_authindex {
1122 my($cl,$index_target) = @_;
1123 my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target";
1124 warn "Going to read $index_target\n";
1125 my $fh = IO::File->new("$pipe|");
1126 while (<$fh>) {
1127 chomp;
1128 my($userid,$fullname,$email) = /alias\s+(\S+)\s+\"([^\"\<]+)\s+<([^\>]+)\>\"/;
1129 next unless $userid && $fullname && $email;
1130
1131 # instantiate an author object
1132 my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
1133 $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
1134 return if $CPAN::Signal;
1135 }
1136 $fh->close;
1137 $? and Carp::croak "FAILED $pipe: exit status [$?]";
1138}
1139
10b2abe6 1140#-> sub CPAN::Index::read_modpacks ;
5f05dabc 1141sub read_modpacks {
1142 my($cl,$index_target) = @_;
1143 my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target";
1144 warn "Going to read $index_target\n";
1145 my $fh = IO::File->new("$pipe|");
1146 while (<$fh>) {
1147 next if 1../^\s*$/;
1148 chomp;
1149 my($mod,$version,$dist) = split;
1150 $version =~ s/^\+//;
1151
1152 # if it as a bundle, instatiate a bundle object
10b2abe6
CS
1153 my($bundle);
1154 if ($mod =~ /^Bundle::(.*)/) {
1155 $bundle = $1;
1156 }
5f05dabc 1157
1158 if ($mod eq 'CPAN') {
1159 local($^W)=0;
1160 if ($version > $CPAN::VERSION){
1161 print qq{
1162 Hey, you know what? There\'s a new CPAN.pm version (v$version)
1163 available! I\'d suggest--provided you have time--you try
1164 install CPAN
1165 reload cpan
1166 without quitting the current session. It should be a seemless upgrade
1167 while we are running...
1168};
1169 sleep 2;
1170 print qq{\n};
1171 }
1172 }
1173
1174 my($id);
1175 if ($bundle){
1176 $id = $CPAN::META->instance('CPAN::Bundle',$mod);
1177 $id->set('CPAN_VERSION' => $version, 'CPAN_FILE' => $dist);
1178# This "next" makes us faster but if the job is running long, we ignore
1179# rereads which is bad. So we have to be a bit slower again.
1180# } elsif ($CPAN::META->exists('CPAN::Module',$mod)) {
1181# next;
1182 } else {
1183 # instantiate a module object
1184 $id = $CPAN::META->instance('CPAN::Module',$mod);
1185 $id->set('CPAN_VERSION' => $version, 'CPAN_FILE' => $dist);
1186 }
1187
1188 # determine the author
1189 my($userid) = $dist =~ /([^\/]+)/;
1190 $id->set('CPAN_USERID' => $userid) if $userid =~ /\w/;
1191
1192 # instantiate a distribution object
1193 unless ($CPAN::META->exists('CPAN::Distribution',$dist)) {
1194 $CPAN::META->instance(
1195 'CPAN::Distribution' => $dist
1196 )->set(
1197 'CPAN_USERID' => $userid
1198 )
1199 if $userid =~ /\w/;
1200 }
1201
1202 return if $CPAN::Signal;
1203 }
1204 $fh->close;
1205 $? and Carp::croak "FAILED $pipe: exit status [$?]";
1206}
1207
10b2abe6 1208#-> sub CPAN::Index::read_modlist ;
5f05dabc 1209sub read_modlist {
1210 my($cl,$index_target) = @_;
1211 my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $index_target";
1212 warn "Going to read $index_target\n";
1213 my $fh = IO::File->new("$pipe|");
1214 my $eval = "";
1215 while (<$fh>) {
1216 next if 1../^\s*$/;
1217 next if /use vars/; # will go away in 03...
1218 $eval .= $_;
1219 return if $CPAN::Signal;
1220 }
1221 $eval .= q{CPAN::Modulelist->data;};
1222 local($^W) = 0;
1223 my($comp) = Safe->new("CPAN::Safe1");
1224 my $ret = $comp->reval($eval);
1225 Carp::confess($@) if $@;
1226 return if $CPAN::Signal;
1227 for (keys %$ret) {
1228 my $obj = $CPAN::META->instance(CPAN::Module,$_);
1229 $obj->set(%{$ret->{$_}});
1230 return if $CPAN::Signal;
1231 }
1232}
1233
1234package CPAN::InfoObj;
10b2abe6 1235@CPAN::InfoObj::ISA = qw(CPAN::Debug);
5f05dabc 1236
10b2abe6 1237#-> sub CPAN::InfoObj::new ;
5f05dabc 1238sub new { my $this = bless {}, shift; %$this = @_; $this }
1239
10b2abe6 1240#-> sub CPAN::InfoObj::set ;
5f05dabc 1241sub set {
1242 my($self,%att) = @_;
1243 my(%oldatt) = %$self;
1244 %$self = (%oldatt, %att);
1245}
1246
10b2abe6 1247#-> sub CPAN::InfoObj::id ;
5f05dabc 1248sub id { shift->{'ID'} }
1249
10b2abe6 1250#-> sub CPAN::InfoObj::as_glimpse ;
5f05dabc 1251sub as_glimpse {
1252 my($self) = @_;
1253 my(@m);
1254 my $class = ref($self);
1255 $class =~ s/^CPAN:://;
1256 push @m, sprintf "%-15s %s\n", $class, $self->{ID};
1257 join "", @m;
1258}
1259
10b2abe6 1260#-> sub CPAN::InfoObj::as_string ;
5f05dabc 1261sub as_string {
1262 my($self) = @_;
1263 my(@m);
1264 my $class = ref($self);
1265 $class =~ s/^CPAN:://;
1266 push @m, $class, " id = $self->{ID}\n";
1267 for (sort keys %$self) {
1268 next if $_ eq 'ID';
1269 my $extra = "";
1270 $_ eq "CPAN_USERID" and $extra = " (".$self->author.")";
1271 if (ref $self->{$_}) { # Should we setup a language interface? XXX
1272 push @m, sprintf " %-12s %s%s\n", $_, "@{$self->{$_}}", $extra;
1273 } else {
1274 push @m, sprintf " %-12s %s%s\n", $_, $self->{$_}, $extra;
1275 }
1276 }
1277 join "", @m, "\n";
1278}
1279
10b2abe6 1280#-> sub CPAN::InfoObj::author ;
5f05dabc 1281sub author {
1282 my($self) = @_;
1283 $CPAN::META->instance(CPAN::Author,$self->{CPAN_USERID})->fullname;
1284}
1285
1286package CPAN::Author;
10b2abe6 1287@CPAN::Author::ISA = qw(CPAN::Debug CPAN::InfoObj);
5f05dabc 1288
10b2abe6 1289#-> sub CPAN::Author::as_glimpse ;
5f05dabc 1290sub as_glimpse {
1291 my($self) = @_;
1292 my(@m);
1293 my $class = ref($self);
1294 $class =~ s/^CPAN:://;
1295 push @m, sprintf "%-15s %s (%s)\n", $class, $self->{ID}, $self->fullname;
1296 join "", @m;
1297}
1298
10b2abe6
CS
1299# Dead code, I would have liked to have,,, but it was never reached,,,
1300#sub make {
1301# my($self) = @_;
1302# return "Don't be silly, you can't make $self->{FULLNAME} ;-)\n";
1303#}
1304
1305#-> sub CPAN::Author::fullname ;
5f05dabc 1306sub fullname { shift->{'FULLNAME'} }
1307*name = \&fullname;
10b2abe6 1308#-> sub CPAN::Author::email ;
5f05dabc 1309sub email { shift->{'EMAIL'} }
1310
1311package CPAN::Distribution;
10b2abe6 1312@CPAN::Distribution::ISA = qw(CPAN::Debug CPAN::InfoObj);
5f05dabc 1313
10b2abe6 1314#-> sub CPAN::Distribution::called_for ;
5f05dabc 1315sub called_for {
1316 my($self,$id) = @_;
1317 $self->{'CALLED_FOR'} = $id if defined $id;
1318 return $self->{'CALLED_FOR'};
1319}
1320
10b2abe6 1321#-> sub CPAN::Distribution::get ;
5f05dabc 1322sub get {
1323 my($self) = @_;
1324 EXCUSE: {
1325 my @e;
1326 exists $self->{'build_dir'} and push @e, "Unwrapped into directory $self->{'build_dir'}";
1327 print join "", map {" $_\n"} @e and return if @e;
1328 }
1329 my($local_file);
1330 my($local_wanted) =
1331 CPAN->catfile(
1332 $CPAN::Config->{keep_source_where},
1333 "authors",
1334 "id",
1335 split("/",$self->{ID})
1336 );
1337
1338 $self->debug("Doing localize") if $CPAN::DEBUG;
1339 $local_file = CPAN::FTP->localize("authors/id/$self->{ID}", $local_wanted);
1340 $self->{localfile} = $local_file;
1341 my $builddir = $CPAN::META->{cachemgr}->dir;
1342 $self->debug("doing chdir $builddir") if $CPAN::DEBUG;
1343 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
1344 my $packagedir;
1345
1346 $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
1347 if ($local_file =~ /(\.tar\.(gz|Z)|\.tgz|\.zip)$/i){
1348 $self->debug("Removing tmp") if $CPAN::DEBUG;
1349 File::Path::rmtree("tmp");
1350 mkdir "tmp", 0777 or Carp::croak "Couldn't mkdir tmp: $!";
1351 chdir "tmp";
1352 $self->debug("Changed directory to tmp") if $CPAN::DEBUG;
1353 if ($local_file =~ /z$/i){
1354 $self->{archived} = "tar";
1355 if (system("$CPAN::Config->{gzip} --decompress --stdout $local_file | $CPAN::Config->{tar} xvf -")==0) {
1356 $self->{unwrapped} = "YES";
1357 } else {
1358 $self->{unwrapped} = "NO";
1359 }
1360 } elsif ($local_file =~ /zip$/i) {
1361 $self->{archived} = "zip";
1362 if (system("$CPAN::Config->{unzip} $local_file")==0) {
1363 $self->{unwrapped} = "YES";
1364 } else {
1365 $self->{unwrapped} = "NO";
1366 }
1367 }
1368 # Let's check if the package has its own directory.
1369 opendir DIR, "." or Carp::croak("Weird: couldn't opendir .: $!");
1370 my @readdir = grep $_ !~ /^\.\.?$/, readdir DIR; ### MAC??
1371 closedir DIR;
1372 my ($distdir,$packagedir);
1373 if (@readdir == 1 && -d $readdir[0]) {
1374 $distdir = $readdir[0];
1375 $packagedir = $CPAN::META->catdir($builddir,$distdir);
1376 -d $packagedir and print "Removing previously used $packagedir\n";
1377 File::Path::rmtree($packagedir);
10b2abe6 1378 rename($distdir,$packagedir) or Carp::confess("Couldn't rename $distdir to $packagedir: $!");
5f05dabc 1379 } else {
1380 my $pragmatic_dir = $self->{'CPAN_USERID'} . '000';
1381 $pragmatic_dir =~ s/\W_//g;
1382 $pragmatic_dir++ while -d "../$pragmatic_dir";
1383 $packagedir = $CPAN::META->catdir($builddir,$pragmatic_dir);
1384 File::Path::mkpath($packagedir);
1385 my($f);
1386 for $f (@readdir) { # is already without "." and ".."
1387 my $to = $CPAN::META->catdir($packagedir,$f);
10b2abe6 1388 rename($f,$to) or Carp::confess("Couldn't rename $f to $to: $!");
5f05dabc 1389 }
1390 }
1391 $self->{'build_dir'} = $packagedir;
1392
1393 chdir "..";
1394 $self->debug("Changed directory to .. (self is $self [".$self->as_string."])") if $CPAN::DEBUG;
1395 File::Path::rmtree("tmp");
1396 if ($CPAN::Config->{keep_source_where} =~ /^no/i ){
1397 print "Going to unlink $local_file\n";
1398 unlink $local_file or Carp::carp "Couldn't unlink $local_file";
1399 }
1400 my($makefilepl) = $CPAN::META->catfile($packagedir,"Makefile.PL");
1401 unless (-f $makefilepl) {
1402 my($configure) = $CPAN::META->catfile($packagedir,"Configure");
1403 if (-f $configure) {
1404 # do we have anything to do?
1405 $self->{'configure'} = $configure;
1406 } else {
1407 my $fh = IO::File->new(">$makefilepl") or Carp::croak("Could not open >$makefilepl");
1408 my $cf = $self->called_for || "unknown";
1409 $fh->print(qq{
1410# This Makefile.PL has been autogenerated by the module CPAN.pm
1411# Autogenerated on: }.scalar localtime().qq{
1412 use ExtUtils::MakeMaker;
1413 WriteMakefile(NAME => q[$cf]);
1414});
1415 print qq{Package comes without Makefile.PL.\n}.
1416 qq{ Writing one on our own (calling it $cf)\n};
1417 }
1418 }
1419 } else {
1420 $self->{archived} = "NO";
1421 }
1422 return $self;
1423}
1424
10b2abe6 1425#-> sub CPAN::Distribution::new ;
5f05dabc 1426sub new {
1427 my($class,%att) = @_;
1428
1429 $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();
1430
1431 my $this = { %att };
1432 return bless $this, $class;
1433}
1434
10b2abe6 1435#-> sub CPAN::Distribution::readme ;
5f05dabc 1436sub readme {
1437 my($self) = @_;
1438 print "Readme not yet implemented (says ".$self->id.")\n";
1439}
1440
10b2abe6 1441#-> sub CPAN::Distribution::verifyMD5 ;
5f05dabc 1442sub verifyMD5 {
1443 my($self) = @_;
1444 EXCUSE: {
1445 my @e;
1446 $self->{MD5_STATUS} and push @e, "MD5 Checksum was ok";
1447 print join "", map {" $_\n"} @e and return if @e;
1448 }
1449 my($local_file);
1450 my(@local) = split("/",$self->{ID});
1451 my($basename) = pop @local;
1452 push @local, "CHECKSUMS";
1453 my($local_wanted) =
1454 CPAN->catfile(
1455 $CPAN::Config->{keep_source_where},
1456 "authors",
1457 "id",
1458 @local
1459 );
1460 local($") = "/";
1461 if (
1462 -f $local_wanted
1463 &&
1464 $self->MD5_check_file($local_wanted,$basename)
1465 ) {
1466 return $self->{MD5_STATUS}="OK";
1467 }
1468 $local_file = CPAN::FTP->localize("authors/id/@local", $local_wanted, 'force>:-{');
1469 my($checksum_pipe);
1470 if ($local_file) {
1471 # fine
1472 } else {
1473 $local[-1] .= ".gz";
1474 $local_file = CPAN::FTP->localize(
1475 "authors/id/@local",
1476 "$local_wanted.gz",
1477 'force>:-{'
1478 );
1479 my $system = "$CPAN::Config->{gzip} --decompress $local_file";
1480 system($system)==0 or die "Could not uncompress $local_file";
1481 $local_file =~ s/\.gz$//;
1482 }
1483 $self->MD5_check_file($local_file,$basename);
1484}
1485
10b2abe6 1486#-> sub CPAN::Distribution::MD5_check_file ;
5f05dabc 1487sub MD5_check_file {
1488 my($self,$lfile,$basename) = @_;
1489 my($cksum);
1490 my $fh = new IO::File;
1491 local($/)=undef;
1492 if (open $fh, $lfile){
1493 my $eval = <$fh>;
1494 close $fh;
1495 my($comp) = Safe->new();
1496 $cksum = $comp->reval($eval);
1497 Carp::confess($@) if $@;
1498 if ($cksum->{$basename}->{md5}) {
1499 $self->debug("Found checksum for $basename: $cksum->{$basename}->{md5}\n") if $CPAN::DEBUG;
1500 my $file = $self->{localfile};
1501 my $pipe = "$CPAN::Config->{gzip} --decompress --stdout $self->{localfile}|";
1502 if (
1503 open($fh, $file) && $self->eq_MD5($fh,$cksum->{$basename}->{md5})
1504 or
1505 open($fh, $pipe) && $self->eq_MD5($fh,$cksum->{$basename}->{'md5-ungz'})
1506 ){
1507 print "Checksum for $file ok\n";
1508 return $self->{MD5_STATUS}="OK";
1509 } else {
1510 die join(
1511 "",
1512 "\nChecksum mismatch for distribution file. Please investigate.\n\n",
1513 $self->as_string,
1514 $CPAN::META->instance('CPAN::Author',$self->{CPAN_USERID})->as_string,
1515 "Please contact the author or your CPAN site admin"
1516 );
1517 }
1518 close $fh if fileno($fh);
1519 } else {
1520 print "No md5 checksum for $basename in local $lfile\n";
1521 return;
1522 }
1523 } else {
1524 Carp::carp "Could not open $lfile for reading";
1525 }
1526}
1527
10b2abe6 1528#-> sub CPAN::Distribution::eq_MD5 ;
5f05dabc 1529sub eq_MD5 {
1530 my($self,$fh,$expectMD5) = @_;
1531 my $md5 = new MD5;
1532 $md5->addfile($fh);
1533 my $hexdigest = $md5->hexdigest;
1534 $hexdigest eq $expectMD5;
1535}
1536
10b2abe6 1537#-> sub CPAN::Distribution::force ;
5f05dabc 1538sub force {
1539 my($self) = @_;
1540 $self->{'force_update'}++;
1541 delete $self->{'MD5_STATUS'};
1542 delete $self->{'archived'};
1543 delete $self->{'build_dir'};
1544 delete $self->{'localfile'};
1545 delete $self->{'make'};
1546 delete $self->{'install'};
1547 delete $self->{'unwrapped'};
1548 delete $self->{'writemakefile'};
1549}
1550
10b2abe6 1551#-> sub CPAN::Distribution::make ;
5f05dabc 1552sub make {
1553 my($self) = @_;
1554 $self->debug($self->id) if $CPAN::DEBUG;
1555 print "Running make\n";
1556 $self->get;
1557 if ($CPAN::META->hasMD5) {
1558 $self->verifyMD5;
1559 }
1560 EXCUSE: {
1561 my @e;
1562 $self->{archived} eq "NO" and push @e, "Is neither a tar nor a zip archive.";
1563 $self->{unwrapped} eq "NO" and push @e, "had problems unarchiving. Please build manually";
1564 exists $self->{writemakefile} && $self->{writemakefile} eq "NO" and push @e, "Had some problem writing Makefile";
1565 defined $self->{'make'} and push @e, "Has already been processed within this session";
1566 print join "", map {" $_\n"} @e and return if @e;
1567 }
1568 print "\n CPAN: Going to build ".$self->id."\n\n";
1569 my $builddir = $self->dir;
1570 chdir $builddir or Carp::croak("Couldn't chdir $builddir: $!");
1571 $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;
1572
1573 my $system;
1574 if ($self->{'configure'}) {
1575 $system = $self->{'configure'};
1576 } else {
1577 my($perl) = $^X =~ /^\.\// ? "$CPAN::Cwd/$^X" : $^X; # XXX subclassing folks, forgive me!
1578 $system = "$perl Makefile.PL $CPAN::Config->{makepl_arg}";
1579 }
10b2abe6
CS
1580 $SIG{ALRM} = sub { die "inactivity_timeout reached\n" };
1581 my($ret,$pid);
1582 $@ = "";
1583 if ($CPAN::Config->{inactivity_timeout}) {
1584 eval {
1585 alarm $CPAN::Config->{inactivity_timeout};
1586 #$SIG{CHLD} = \&REAPER;
1587 if (defined($pid=fork)) {
1588 if ($pid) { #parent
1589 wait;
1590 } else { #child
1591 exec $system;
1592 }
1593 } else {
1594 print "Cannot fork: $!";
1595 return;
1596 }
1597 $ret = system($system);
1598 };
1599 alarm 0;
1600 } else {
1601 $ret = system($system);
1602 }
1603 if ($@){
1604 kill 9, $pid;
1605 waitpid $pid, 0;
1606 print $@;
1607 $self->{writemakefile} = "NO - $@";
1608 $@ = "";
1609 return;
1610 } elsif ($ret != 0) {
5f05dabc 1611 $self->{writemakefile} = "NO";
1612 return;
1613 }
1614 $self->{writemakefile} = "YES";
1615 return if $CPAN::Signal;
1616 $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg};
1617 if (system($system)==0) {
1618 print " $system -- OK\n";
1619 $self->{'make'} = "YES";
1620 } else {
1621 $self->{writemakefile} = "YES";
1622 $self->{'make'} = "NO";
1623 print " $system -- NOT OK\n";
1624 }
1625}
1626
10b2abe6 1627#-> sub CPAN::Distribution::test ;
5f05dabc 1628sub test {
1629 my($self) = @_;
1630 $self->make;
1631 return if $CPAN::Signal;
1632 print "Running make test\n";
1633 EXCUSE: {
1634 my @e;
1635 exists $self->{'make'} or push @e, "Make had some problems, maybe interrupted? Won't test";
1636 exists $self->{'make'} and $self->{'make'} eq 'NO' and push @e, "Oops, make had returned bad status";
1637 exists $self->{'build_dir'} or push @e, "Has no own directory";
1638 print join "", map {" $_\n"} @e and return if @e;
1639 }
1640 chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}");
1641 $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG;
1642 my $system = join " ", $CPAN::Config->{'make'}, "test";
1643 if (system($system)==0) {
1644 print " $system -- OK\n";
1645 $self->{'make_test'} = "YES";
1646 } else {
1647 $self->{'make_test'} = "NO";
1648 print " $system -- NOT OK\n";
1649 }
1650}
1651
10b2abe6 1652#-> sub CPAN::Distribution::clean ;
5f05dabc 1653sub clean {
1654 my($self) = @_;
1655 print "Running make clean\n";
1656 EXCUSE: {
1657 my @e;
1658 exists $self->{'build_dir'} or push @e, "Has no own directory";
1659 print join "", map {" $_\n"} @e and return if @e;
1660 }
1661 chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}");
1662 $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG;
1663 my $system = join " ", $CPAN::Config->{'make'}, "clean";
1664 if (system($system)==0) {
1665 print " $system -- OK\n";
1666 $self->force;
1667 } else {
1668 # Hmmm, what to do if make clean failed?
1669 }
1670}
1671
10b2abe6 1672#-> sub CPAN::Distribution::install ;
5f05dabc 1673sub install {
1674 my($self) = @_;
1675 $self->test;
1676 return if $CPAN::Signal;
1677 print "Running make install\n";
1678 EXCUSE: {
1679 my @e;
1680 exists $self->{'build_dir'} or push @e, "Has no own directory";
1681 exists $self->{'make'} or push @e, "Make had some problems, maybe interrupted? Won't install";
1682 exists $self->{'make'} and $self->{'make'} eq 'NO' and push @e, "Oops, make had returned bad status";
1683 exists $self->{'install'} and push @e, $self->{'install'} eq "YES" ? "Already done" : "Already tried without success";
1684 print join "", map {" $_\n"} @e and return if @e;
1685 }
1686 chdir $self->{'build_dir'} or Carp::croak("Couldn't chdir to $self->{'build_dir'}");
1687 $self->debug("Changed directory to $self->{'build_dir'}") if $CPAN::DEBUG;
1688 my $system = join " ", $CPAN::Config->{'make'}, "install", $CPAN::Config->{make_install_arg};
1689 my($pipe) = IO::File->new("$system 2>&1 |");
1690 my($makeout) = "";
10b2abe6
CS
1691
1692 # #If I were to try this, I'd do something like:
1693 # #
1694 # # $SIG{ALRM} = sub { die "alarm\n" };
1695 # #
1696 # # open(PROC,"make somesuch|");
1697 # # eval {
1698 # # alarm 30;
1699 # # while(<PROC>) {
1700 # # alarm 30;
1701 # # }
1702 # # }
1703 # # close(PROC);
1704 # # alarm 0;
1705 # #
1706 # #I'm really not sure how reliable this would is, though.
1707 # #
1708 # #--
1709 # #Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
1710 # #
1711 # #
1712 # #
1713 # #
1714 while (<$pipe>){
5f05dabc 1715 print;
1716 $makeout .= $_;
1717 }
1718 $pipe->close;
1719 if ($?==0) {
1720 print " $system -- OK\n";
1721 $self->{'install'} = "YES";
1722 } else {
1723 $self->{'install'} = "NO";
1724 print " $system -- NOT OK\n";
1725 if ($makeout =~ /permission/s && $> > 0) {
1726 print " You may have to su to root to install the package\n";
1727 }
1728 }
1729}
1730
10b2abe6 1731#-> sub CPAN::Distribution::dir ;
5f05dabc 1732sub dir {
1733 shift->{'build_dir'};
1734}
1735
1736package CPAN::Bundle;
10b2abe6 1737@CPAN::Bundle::ISA = qw(CPAN::Debug CPAN::InfoObj CPAN::Module);
5f05dabc 1738
10b2abe6 1739#-> sub CPAN::Bundle::as_string ;
5f05dabc 1740sub as_string {
1741 my($self) = @_;
1742 $self->contains;
1743 return $self->SUPER::as_string;
1744}
1745
10b2abe6 1746#-> sub CPAN::Bundle::contains ;
5f05dabc 1747sub contains {
1748 my($self) = @_;
1749 my($parsefile) = $self->inst_file;
1750 unless ($parsefile) {
1751 # Try to get at it in the cpan directory
1752 $self->debug("no parsefile") if $CPAN::DEBUG;
1753 my $dist = $CPAN::META->instance('CPAN::Distribution',$self->{'CPAN_FILE'});
1754 $self->debug($dist->as_string) if $CPAN::DEBUG;
1755 $dist->get;
1756 $self->debug($dist->as_string) if $CPAN::DEBUG;
1757 my($todir) = $CPAN::META->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1758 File::Path::mkpath($todir);
1759 my($me,$from,$to);
1760 ($me = $self->id) =~ s/.*://;
1761 $from = $CPAN::META->catfile($dist->{'build_dir'},"$me.pm");
1762 $to = $CPAN::META->catfile($todir,"$me.pm");
10b2abe6 1763 File::Copy::copy($from, $to) or Carp::confess("Couldn't copy $from to $to: $!");
5f05dabc 1764 $parsefile = $to;
1765 }
1766 my @result;
1767 my $fh = new IO::File;
1768 local $/ = "\n";
1769 open($fh,$parsefile) or die "Could not open '$parsefile': $!";
1770 my $inpod = 0;
1771 while (<$fh>) {
1772 $inpod = /^=(?!head1\s+CONTENTS)/ ? 0 : /^=head1\s+CONTENTS/ ? 1 : $inpod;
1773 next unless $inpod;
1774 next if /^=/;
1775 next if /^\s+$/;
1776 chomp;
1777 push @result, (split " ", $_, 2)[0];
1778 }
1779 close $fh;
1780 delete $self->{STATUS};
1781 $self->{CONTAINS} = [@result];
1782 @result;
1783}
1784
10b2abe6 1785#-> sub CPAN::Bundle::inst_file ;
5f05dabc 1786sub inst_file {
1787 my($self) = @_;
1788 my($me,$inst_file);
1789 ($me = $self->id) =~ s/.*://;
1790 $inst_file = $CPAN::META->catfile($CPAN::Config->{'cpan_home'},"Bundle", "$me.pm");
1791 return $self->{'INST_FILE'} = $inst_file if -f $inst_file;
1792 $inst_file = $self->SUPER::inst_file;
1793 return $self->{'INST_FILE'} = $inst_file if -f $inst_file;
1794 return $self->{'INST_FILE'}; # even if undefined?
1795}
1796
10b2abe6 1797#-> sub CPAN::Bundle::rematein ;
5f05dabc 1798sub rematein {
1799 my($self,$meth) = @_;
1800 $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG;
1801 my($s);
1802 for $s ($self->contains) {
1803 $CPAN::META->instance('CPAN::Module',$s)->$meth();
1804 }
1805}
1806
10b2abe6
CS
1807#-> sub CPAN::Bundle::force ;
1808sub force { shift->rematein('force',@_); }
1809#-> sub CPAN::Bundle::install ;
5f05dabc 1810sub install { shift->rematein('install',@_); }
10b2abe6 1811#-> sub CPAN::Bundle::clean ;
5f05dabc 1812sub clean { shift->rematein('clean',@_); }
10b2abe6 1813#-> sub CPAN::Bundle::test ;
5f05dabc 1814sub test { shift->rematein('test',@_); }
10b2abe6 1815#-> sub CPAN::Bundle::make ;
5f05dabc 1816sub make { shift->rematein('make',@_); }
1817
1818# XXX not yet implemented!
10b2abe6 1819#-> sub CPAN::Bundle::readme ;
5f05dabc 1820sub readme {
1821 my($self) = @_;
1822 my($file) = $self->cpan_file or print("No File found for bundle ", $self->id, "\n"), return;
1823 $self->debug("self[$self] file[$file]") if $CPAN::DEBUG;
1824 $CPAN::META->instance('CPAN::Distribution',$file)->readme;
1825# CPAN::FTP->localize("authors/id/$file",$index_wanted); # XXX
1826}
1827
1828package CPAN::Module;
10b2abe6 1829@CPAN::Module::ISA = qw(CPAN::Debug CPAN::InfoObj);
5f05dabc 1830
10b2abe6 1831#-> sub CPAN::Module::as_glimpse ;
5f05dabc 1832sub as_glimpse {
1833 my($self) = @_;
1834 my(@m);
1835 my $class = ref($self);
1836 $class =~ s/^CPAN:://;
1837 push @m, sprintf "%-15s %-15s (%s)\n", $class, $self->{ID}, $self->cpan_file;
1838 join "", @m;
1839}
1840
10b2abe6 1841#-> sub CPAN::Module::as_string ;
5f05dabc 1842sub as_string {
1843 my($self) = @_;
1844 my(@m);
1845 CPAN->debug($self) if $CPAN::DEBUG;
1846 my $class = ref($self);
1847 $class =~ s/^CPAN:://;
1848 local($^W) = 0;
1849 push @m, $class, " id = $self->{ID}\n";
1850 my $sprintf = " %-12s %s\n";
1851 push @m, sprintf $sprintf, 'DESCRIPTION', $self->{description} if $self->{description};
1852 my $sprintf2 = " %-12s %s (%s)\n";
1853 my($userid);
1854 if ($userid = $self->{'CPAN_USERID'} || $self->{'userid'}){
1855 push @m, sprintf(
1856 $sprintf2,
1857 'CPAN_USERID',
1858 $userid,
1859 $CPAN::META->instance(CPAN::Author,$userid)->fullname
1860 )
1861 }
1862 push @m, sprintf $sprintf, 'CPAN_VERSION', $self->{CPAN_VERSION} if $self->{CPAN_VERSION};
1863 push @m, sprintf $sprintf, 'CPAN_FILE', $self->{CPAN_FILE} if $self->{CPAN_FILE};
1864 my $sprintf3 = " %-12s %1s%1s%1s%1s (%s,%s,%s,%s)\n";
1865 my(%statd,%stats,%statl,%stati);
1866 @statd{qw,? i c a b R M S,} = qw,unknown idea pre-alpha alpha beta released mature standard,;
1867 @stats{qw,? m d u n,} = qw,unknown mailing-list developer comp.lang.perl.* none,;
1868 @statl{qw,? p c + o,} = qw,unknown perl C C++ other,;
1869 @stati{qw,? f r O,} = qw,unknown functions references+ties object-oriented,;
1870 $statd{' '} = 'unknown';
1871 $stats{' '} = 'unknown';
1872 $statl{' '} = 'unknown';
1873 $stati{' '} = 'unknown';
1874 push @m, sprintf(
1875 $sprintf3,
1876 'DSLI_STATUS',
1877 $self->{statd},
1878 $self->{stats},
1879 $self->{statl},
1880 $self->{stati},
1881 $statd{$self->{statd}},
1882 $stats{$self->{stats}},
1883 $statl{$self->{statl}},
1884 $stati{$self->{stati}}
1885 ) if $self->{statd};
1886 my $local_file = $self->inst_file;
1887 if ($local_file && ! exists $self->{MANPAGE}) {
1888 my $fh = IO::File->new($local_file) or Carp::croak("Couldn't open $local_file: $!");
1889 my $inpod = 0;
1890 my(@result);
1891 local $/ = "\n";
1892 while (<$fh>) {
1893 $inpod = /^=(?!head1\s+NAME)/ ? 0 : /^=head1\s+NAME/ ? 1 : $inpod;
1894 next unless $inpod;
1895 next if /^=/;
1896 next if /^\s+$/;
1897 chomp;
1898 push @result, $_;
1899 }
1900 close $fh;
1901 $self->{MANPAGE} = join " ", @result;
1902 }
1903 push @m, sprintf $sprintf, 'MANPAGE', $self->{MANPAGE} if $self->{MANPAGE};
1904 push @m, sprintf $sprintf, 'INST_FILE', $local_file || "(not installed)";
1905 push @m, sprintf $sprintf, 'INST_VERSION', $self->inst_version if $local_file;
1906 join "", @m, "\n";
1907}
1908
10b2abe6 1909#-> sub CPAN::Module::cpan_file ;
5f05dabc 1910sub cpan_file {
1911 my $self = shift;
1912 CPAN->debug($self->id) if $CPAN::DEBUG;
1913 unless (defined $self->{'CPAN_FILE'}) {
1914 CPAN::Index->reload;
1915 }
1916 if (defined $self->{'CPAN_FILE'}){
1917 return $self->{'CPAN_FILE'};
1918 } elsif (defined $self->{'userid'}) {
1919 return "Contact Author ".$self->{'userid'}."=".$CPAN::META->instance(CPAN::Author,$self->{'userid'})->fullname
1920 } else {
1921 return "N/A";
1922 }
1923}
1924
1925*name = \&cpan_file;
1926
10b2abe6 1927#-> sub CPAN::Module::cpan_version ;
5f05dabc 1928sub cpan_version { shift->{'CPAN_VERSION'} }
1929
10b2abe6 1930#-> sub CPAN::Module::force ;
5f05dabc 1931sub force {
1932 my($self) = @_;
1933 $self->{'force_update'}++;
1934}
1935
10b2abe6 1936#-> sub CPAN::Module::rematein ;
5f05dabc 1937sub rematein {
1938 my($self,$meth) = @_;
1939 $self->debug($self->id) if $CPAN::DEBUG;
1940 my $cpan_file = $self->cpan_file;
1941 return if $cpan_file eq "N/A";
1942 return if $cpan_file =~ /^Contact Author/;
1943 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
1944 $pack->called_for($self->id);
1945 $pack->force if exists $self->{'force_update'};
1946 $pack->$meth();
1947 delete $self->{'force_update'};
1948}
1949
10b2abe6 1950#-> sub CPAN::Module::readme ;
5f05dabc 1951sub readme { shift->rematein('readme') }
10b2abe6 1952#-> sub CPAN::Module::make ;
5f05dabc 1953sub make { shift->rematein('make') }
10b2abe6 1954#-> sub CPAN::Module::clean ;
5f05dabc 1955sub clean { shift->rematein('clean') }
10b2abe6 1956#-> sub CPAN::Module::test ;
5f05dabc 1957sub test { shift->rematein('test') }
10b2abe6 1958#-> sub CPAN::Module::install ;
5f05dabc 1959sub install {
1960 my($self) = @_;
1961 my($doit) = 0;
1962 my($latest) = $self->cpan_version;
1963 $latest ||= 0;
1964 my($inst_file) = $self->inst_file;
1965 my($have) = 0;
1966 if (defined $inst_file) {
1967 $have = $self->inst_version;
1968 }
1969 if ($inst_file && $have >= $latest && not exists $self->{'force_update'}) {
1970 print $self->id, " is up to date.\n";
1971 } else {
1972 $doit = 1;
1973 }
1974 $self->rematein('install') if $doit;
1975}
1976
10b2abe6 1977#-> sub CPAN::Module::inst_file ;
5f05dabc 1978sub inst_file {
1979 my($self) = @_;
1980 my($dir,@packpath);
1981 @packpath = split /::/, $self->{ID};
1982 $packpath[-1] .= ".pm";
1983 foreach $dir (@INC) {
1984 my $pmfile = CPAN->catfile($dir,@packpath);
1985 if (-f $pmfile){
1986 return $pmfile;
1987 }
1988 }
1989}
1990
10b2abe6 1991#-> sub CPAN::Module::xs_file ;
5f05dabc 1992sub xs_file {
1993 my($self) = @_;
1994 my($dir,@packpath);
1995 @packpath = split /::/, $self->{ID};
1996 push @packpath, $packpath[-1];
1997 $packpath[-1] .= "." . $Config::Config{'dlext'};
1998 foreach $dir (@INC) {
1999 my $xsfile = CPAN->catfile($dir,'auto',@packpath);
2000 if (-f $xsfile){
2001 return $xsfile;
2002 }
2003 }
2004}
2005
10b2abe6 2006#-> sub CPAN::Module::inst_version ;
5f05dabc 2007sub inst_version {
2008 my($self) = @_;
2009 my $parsefile = $self->inst_file or return 0;
2010 my $have = MY->parse_version($parsefile);
2011 $have ||= 0;
2012 $have =~ s/\s+//g;
2013 $have ||= 0;
2014 $have;
2015}
2016
2017package CPAN::CacheMgr;
10b2abe6
CS
2018use vars qw($Du);
2019@CPAN::CacheMgr::ISA = qw(CPAN::Debug CPAN::InfoObj);
5f05dabc 2020use File::Find;
2021
10b2abe6 2022#-> sub CPAN::CacheMgr::as_string ;
5f05dabc 2023sub as_string {
2024 eval { require Data::Dumper };
2025 if ($@) {
2026 return shift->SUPER::as_string;
2027 } else {
2028 return Data::Dumper::Dumper(shift);
2029 }
2030}
2031
10b2abe6 2032#-> sub CPAN::CacheMgr::cachesize ;
5f05dabc 2033sub cachesize {
2034 shift->{DU};
2035}
2036
2037# sub check {
2038# my($self,@dirs) = @_;
2039# return unless -d $self->{ID};
2040# my $dir;
2041# @dirs = $self->dirs unless @dirs;
2042# for $dir (@dirs) {
2043# $self->disk_usage($dir);
2044# }
2045# }
2046
10b2abe6 2047#-> sub CPAN::CacheMgr::clean_cache ;
5f05dabc 2048sub clean_cache {
2049 my $self = shift;
2050 my $dir;
2051 while ($self->{DU} > $self->{'MAX'} and $dir = shift @{$self->{FIFO}}) {
2052 $self->force_clean_cache($dir);
2053 }
2054 $self->debug("leaving clean_cache with $self->{DU}") if $CPAN::DEBUG;
2055}
2056
10b2abe6 2057#-> sub CPAN::CacheMgr::dir ;
5f05dabc 2058sub dir {
2059 shift->{ID};
2060}
2061
10b2abe6 2062#-> sub CPAN::CacheMgr::entries ;
5f05dabc 2063sub entries {
2064 my($self,$dir) = @_;
2065 $dir ||= $self->{ID};
2066 my($cwd) = Cwd::cwd();
2067 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
2068 my $dh = DirHandle->new(".") or Carp::croak("Couldn't opendir $dir: $!");
2069 my(@entries);
2070 for ($dh->read) {
2071 next if $_ eq "." || $_ eq "..";
2072 if (-f $_) {
2073 push @entries, $CPAN::META->catfile($dir,$_);
2074 } elsif (-d _) {
2075 push @entries, $CPAN::META->catdir($dir,$_);
2076 } else {
2077 print STDERR "Warning: weird direntry in $dir: $_\n";
2078 }
2079 }
2080 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
2081 sort {-M $b <=> -M $a} @entries;
2082}
2083
10b2abe6 2084#-> sub CPAN::CacheMgr::disk_usage ;
5f05dabc 2085sub disk_usage {
2086 my($self,$dir) = @_;
2087 if (! defined $dir or $dir eq "") {
2088 $self->debug("Cannot determine disk usage for some reason") if $CPAN::DEBUG;
2089 return;
2090 }
2091 return if defined $self->{SIZE}{$dir};
2092 local($Du) = 0;
2093 find(
2094 sub {
2095 return if -l $_;
2096 $Du += -s;
2097 },
2098 $dir
2099 );
2100 $self->{SIZE}{$dir} = $Du/1024/1024;
2101 push @{$self->{FIFO}}, $dir;
2102 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
2103 $self->{DU} += $Du/1024/1024;
2104 if ($self->{DU} > $self->{'MAX'} ) {
2105 printf "...Hold on a sec... CPAN's cleaning the cache: %.2f MB > %.2f MB\n",
2106 $self->{DU}, $self->{'MAX'};
2107 $self->clean_cache;
2108 } else {
2109 $self->debug("NOT have to clean the cache: $self->{DU} <= $self->{'MAX'}") if $CPAN::DEBUG;
2110 $self->debug($self->as_string) if $CPAN::DEBUG;
2111 }
2112 $self->{DU};
2113}
2114
10b2abe6 2115#-> sub CPAN::CacheMgr::force_clean_cache ;
5f05dabc 2116sub force_clean_cache {
2117 my($self,$dir) = @_;
2118 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}") if $CPAN::DEBUG;
2119 File::Path::rmtree($dir);
2120 $self->{DU} -= $self->{SIZE}{$dir};
2121 delete $self->{SIZE}{$dir};
2122}
2123
10b2abe6 2124#-> sub CPAN::CacheMgr::new ;
5f05dabc 2125sub new {
2126 my $class = shift;
2127 my $self = { ID => $CPAN::Config->{'build_dir'}, MAX => $CPAN::Config->{'build_cache'}, DU => 0 };
2128 File::Path::mkpath($self->{ID});
2129 my $dh = DirHandle->new($self->{ID});
2130 bless $self, $class;
2131 $self->debug("dir [$self->{ID}]") if $CPAN::DEBUG;
2132 my $e;
2133 for $e ($self->entries) {
2134 next if $e eq ".." || $e eq ".";
2135 $self->debug("Have to check size $e") if $CPAN::DEBUG;
2136 $self->disk_usage($e);
2137 }
2138 $self;
2139}
2140
2141package CPAN::Debug;
2142
10b2abe6 2143#-> sub CPAN::Debug::debug ;
5f05dabc 2144sub debug {
2145 my($self,$arg) = @_;
2146 my($caller,$func,$line,@rest) = caller(1); # caller(0) eg Complete, caller(1) eg readline
2147 ($caller) = caller(0);
2148 $caller =~ s/.*:://;
2149# print "caller[$caller]func[$func]line[$line]rest[@rest]\n";
2150# print "CPAN::DEBUG{caller}[$CPAN::DEBUG{$caller}]CPAN::DEBUG[$CPAN::DEBUG]\n";
2151 if ($CPAN::DEBUG{$caller} & $CPAN::DEBUG){
2152 if (ref $arg) {
2153 eval { require Data::Dumper };
2154 if ($@) {
2155 print $arg->as_string;
2156 } else {
2157 print Data::Dumper::Dumper($arg);
2158 }
2159 } else {
2160 print "Debug($caller:$func,$line,@rest): $arg\n"
2161 }
2162 }
2163}
2164
2165package CPAN::Config;
2166import ExtUtils::MakeMaker 'neatvalue';
2167use vars qw(%can);
2168
2169%can = (
2170 'commit' => "Commit changes to disk",
2171 'defaults' => "Reload defaults from disk",
2172);
2173
10b2abe6 2174#-> sub CPAN::Config::edit ;
5f05dabc 2175sub edit {
2176 my($class,@args) = @_;
2177 return unless @args;
10b2abe6 2178 CPAN->debug("class[$class]args[".join(" | ",@args)."]");
5f05dabc 2179 my($o,$str,$func,$args,$key_exists);
2180 $o = shift @args;
2181 if($can{$o}) {
2182 $class->$o(@args);
2183 return 1;
10b2abe6
CS
2184 } else {
2185 if (ref($CPAN::Config->{$o}) eq ARRAY) {
5f05dabc 2186 $func = shift @args;
2187 # Let's avoid eval, it's easier to comprehend without.
2188 if ($func eq "push") {
2189 push @{$CPAN::Config->{$o}}, @args;
2190 } elsif ($func eq "pop") {
2191 pop @{$CPAN::Config->{$o}};
2192 } elsif ($func eq "shift") {
2193 shift @{$CPAN::Config->{$o}};
2194 } elsif ($func eq "unshift") {
2195 unshift @{$CPAN::Config->{$o}}, @args;
2196 } elsif ($func eq "splice") {
2197 splice @{$CPAN::Config->{$o}}, @args;
2198 } else {
2199 $CPAN::Config->{$o} = [@args];
2200 }
2201 } else {
5f05dabc 2202 $CPAN::Config->{$o} = $args[0];
10b2abe6
CS
2203 print " $o ";
2204 print defined $CPAN::Config->{$o} ? $CPAN::Config->{$o} : "UNDEFINED";
5f05dabc 2205 }
5f05dabc 2206 }
2207}
2208
10b2abe6 2209#-> sub CPAN::Config::commit ;
5f05dabc 2210sub commit {
2211 my($self, $configpm) = @_;
2212 my $mode;
2213 # mkpath!?
2214
2215 my($fh) = IO::File->new;
2216 $configpm ||= cfile();
2217 if (-f $configpm) {
2218 $mode = (stat $configpm)[2];
2219 if ($mode && ! -w _) {
2220 print "$configpm is not writable\n" and return;
2221 }
2222 #chmod 0644, $configpm; #?
2223 }
2224
2225 my $msg = <<EOF unless $configpm =~ /MyConfig/;
2226
2227# This is CPAN.pm's systemwide configuration file. This file provides
2228# defaults for users, and the values can be changed in a per-user configuration
2229# file. The user-config file is being looked for as ~/.cpan/CPAN/MyConfig.pm.
2230
2231EOF
2232 $msg ||= "\n";
2233 open $fh, ">$configpm" or warn "Couldn't open >$configpm: $!";
2234 print $fh qq[$msg\$CPAN::Config = \{\n];
2235 foreach (sort keys %$CPAN::Config) {
2236 print $fh " '$_' => ", ExtUtils::MakeMaker::neatvalue($CPAN::Config->{$_}), ",\n";
2237 }
2238
2239 print $fh "};\n1;\n__END__\n";
2240 close $fh;
2241
2242 #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
2243 #chmod $mode, $configpm;
2244 $self->defaults;
2245 print "commit: wrote $configpm\n";
2246 1;
2247}
2248
2249*default = \&defaults;
10b2abe6 2250#-> sub CPAN::Config::defaults ;
5f05dabc 2251sub defaults {
2252 my($self) = @_;
2253 $self->unload;
2254 $self->load;
2255 1;
2256}
2257
2258my $dot_cpan;
10b2abe6 2259#-> sub CPAN::Config::load ;
5f05dabc 2260sub load {
2261 my($self) = @_;
2262 eval {require CPAN::Config;}; # We eval, because of some MakeMaker problems
2263 unshift @INC, $CPAN::META->catdir($ENV{HOME},".cpan") unless $dot_cpan++;
2264 eval {require CPAN::MyConfig;}; # where you can override system wide settings
2265 unless ( $self->load_succeeded ) {
2266 require CPAN::FirstTime;
2267 my($configpm,$fh);
2268 if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
2269 $configpm = $INC{"CPAN/Config.pm"};
2270 } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
2271 $configpm = $INC{"CPAN/MyConfig.pm"};
2272 } else {
2273 my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
2274 my($configpmdir) = MY->catdir($path_to_cpan,"CPAN");
2275 my($configpmtest) = MY->catfile($configpmdir,"Config.pm");
2276 if (-d $configpmdir || File::Path::mkpath($configpmdir)) {
2277#_#_# following code dumped core on me with 5.003_11, a.k.
2278#_#_# $fh = IO::File->new;
2279#_#_# if ($fh->open(">$configpmtest")) {
2280#_#_# $fh->print("1;\n");
2281#_#_# $configpm = $configpmtest;
2282#_#_# }
2283 if (-w $configpmtest or -w $configpmdir) {
2284 $configpm = $configpmtest;
2285 }
2286 }
2287 unless ($configpm) {
2288 $configpmdir = MY->catdir($ENV{HOME},".cpan","CPAN");
2289 File::Path::mkpath($configpmdir);
2290 $configpmtest = MY->catfile($configpmdir,"MyConfig.pm");
2291 if (-w $configpmtest or -w $configpmdir) {
2292 $configpm = $configpmtest;
2293 } else {
2294 warn "WARNING: CPAN.pm is unable to create a configuration file.\n";
2295 }
2296 }
2297 }
2298 warn "Calling CPAN::FirstTime::init($configpm)";
2299 CPAN::FirstTime::init($configpm);
2300 }
2301}
2302
10b2abe6 2303#-> sub CPAN::Config::load_succeeded ;
5f05dabc 2304sub load_succeeded {
2305 my($miss) = 0;
2306 for (qw(
2307 cpan_home keep_source_where build_dir build_cache index_expire
2308 gzip tar unzip make pager makepl_arg make_arg make_install_arg
2309 urllist inhibit_startup_message
2310 )) {
2311 $miss++ unless defined $CPAN::Config->{$_}; # we want them all
2312 }
2313 return !$miss;
2314}
2315
10b2abe6 2316#-> sub CPAN::Config::unload ;
5f05dabc 2317sub unload {
2318 delete $INC{'CPAN/MyConfig.pm'};
2319 delete $INC{'CPAN/Config.pm'};
2320}
2321
10b2abe6 2322#-> sub CPAN::Config::cfile ;
5f05dabc 2323sub cfile {
2324 $INC{'CPAN/MyConfig.pm'} || $INC{'CPAN/Config.pm'};
2325}
2326
2327*h = \&help;
10b2abe6 2328#-> sub CPAN::Config::help ;
5f05dabc 2329sub help {
2330 print <<EOF;
2331Known options:
2332 defaults reload default config values from disk
2333 commit commit session changes to disk
2334
2335You may edit key values in the follow fashion:
2336
2337 o conf build_cache 15
2338
2339 o conf build_dir "/foo/bar"
2340
2341 o conf urllist shift
2342
2343 o conf urllist unshift ftp://ftp.foo.bar/
2344
2345EOF
2346 undef; #don't reprint CPAN::Config
2347}
2348
10b2abe6 2349#-> sub CPAN::Config::complete ;
5f05dabc 2350sub complete {
2351 my($word,$line,$pos) = @_;
2352 $word ||= "";
2353 my(@words) = split " ", $line;
2354 my(@o_conf) = (sort keys %CPAN::Config::can, sort keys %$CPAN::Config);
2355 return (@o_conf) unless @words>2;
2356 if($words[2] =~ /->(.*)/) {
2357 my $meth = $1;
2358 my(@methods) = qw(shift unshift push pop splice);
2359 return @methods unless $meth;
2360 return sort grep /^\Q$meth\E/, @methods;
2361 }
2362 return sort grep /^\Q$word\E/, @o_conf;
2363}
2364
23651;
2366
2367=head1 NAME
2368
2369CPAN - query, download and build perl modules from CPAN sites
2370
2371=head1 SYNOPSIS
2372
2373Interactive mode:
2374
2375 perl -MCPAN -e shell;
2376
2377Batch mode:
2378
2379 use CPAN;
2380
10b2abe6 2381 autobundle, clean, install, make, recompile, test
5f05dabc 2382
2383=head1 DESCRIPTION
2384
10b2abe6 2385The CPAN module is designed to automate the make and install of perl
42d3b621
A
2386modules and extensions. It includes some searching capabilities and
2387knows how to use Net::FTP or LWP (or lynx or an external ftp client)
2388to fetch the raw data from the net.
5f05dabc 2389
2390Modules are fetched from one or more of the mirrored CPAN
2391(Comprehensive Perl Archive Network) sites and unpacked in a dedicated
2392directory.
2393
2394The CPAN module also supports the concept of named and versioned
2395'bundles' of modules. Bundles simplify the handling of sets of
2396related modules. See BUNDLES below.
2397
2398The package contains a session manager and a cache manager. There is
2399no status retained between sessions. The session manager keeps track
2400of what has been fetched, built and installed in the current
2401session. The cache manager keeps track of the disk space occupied by
42d3b621
A
2402the make processes and deletes excess space according to a simple FIFO
2403mechanism.
5f05dabc 2404
10b2abe6
CS
2405All methods provided are accessible in a programmer style and in an
2406interactive shell style.
2407
5f05dabc 2408=head2 Interactive Mode
2409
2410The interactive mode is entered by running
2411
2412 perl -MCPAN -e shell
2413
2414which puts you into a readline interface. You will have most fun if
2415you install Term::ReadKey and Term::ReadLine to enjoy both history and
2416completion.
2417
2418Once you are on the command line, type 'h' and the rest should be
2419self-explanatory.
2420
10b2abe6
CS
2421The most common uses of the interactive modes are
2422
2423=over 2
2424
2425=item Searching for authors, bundles, distribution files and modules
2426
2427There are corresponding one-letter commands C<a>, C<b>, C<d>, and C<m>
42d3b621
A
2428for each of the four categories and another, C<i> for any of the
2429mentioned four. Each of the four entities is implemented as a class
2430with slightly differing methods for displaying an object.
10b2abe6
CS
2431
2432Arguments you pass to these commands are either strings matching exact
2433the identification string of an object or regular expressions that are
2434then matched case-insensitively against various attributes of the
2435objects. The parser recognizes a regualar expression only if you
2436enclose it between two slashes.
2437
2438The principle is that the number of found objects influences how an
2439item is displayed. If the search finds one item, we display the result
2440of object-E<gt>as_string, but if we find more than one, we display
2441each as object-E<gt>as_glimpse. E.g.
2442
2443 cpan> a ANDK
2444 Author id = ANDK
2445 EMAIL a.koenig@franz.ww.TU-Berlin.DE
2446 FULLNAME Andreas König
2447
2448
2449 cpan> a /andk/
2450 Author id = ANDK
2451 EMAIL a.koenig@franz.ww.TU-Berlin.DE
2452 FULLNAME Andreas König
2453
2454
2455 cpan> a /and.*rt/
2456 Author ANDYD (Andy Dougherty)
2457 Author MERLYN (Randal L. Schwartz)
2458
2459=item make, test, install, clean modules or distributions
2460
2461The four commands do indeed exist just as written above. Each of them
2462takes as many arguments as provided and investigates for each what it
2463might be. Is it a distribution file (recognized by embedded slashes),
2464this file is being processed. Is it a module, CPAN determines the
2465distribution file where this module is included and processes that.
2466
42d3b621
A
2467Any C<make> and C<test> are run unconditionally. A
2468
2469 C<install E<lt>distribution_fileE<gt>>
2470
2471also is run unconditionally. But for
2472
2473 C<install E<lt>moduleE<gt>>
2474
2475CPAN checks if an install is actually needed for it and prints
2476I<Foo up to date> in case the module doesnE<39>t need to be updated.
10b2abe6
CS
2477
2478CPAN also keeps track of what it has done within the current session
2479and doesnE<39>t try to build a package a second time regardless if it
2480succeeded or not. The C<force > command takes as first argument the
2481method to invoke (currently: make, test, or install) and executes the
2482command from scratch.
2483
2484Example:
2485
2486 cpan> install OpenGL
2487 OpenGL is up to date.
2488 cpan> force install OpenGL
2489 Running make
2490 OpenGL-0.4/
2491 OpenGL-0.4/COPYRIGHT
2492 [...]
2493
2494=back
2495
5f05dabc 2496=head2 CPAN::Shell
2497
2498The commands that are available in the shell interface are methods in
2499the package CPAN::Shell. If you enter the shell command, all your
10b2abe6
CS
2500input is split by the Text::ParseWords::shellwords() routine which
2501acts like most shells do. The first word is being interpreted as the
2502method to be called and the rest of the words are treated as arguments
2503to this method.
2504
2505=head2 ProgrammerE<39>s interface
5f05dabc 2506
10b2abe6
CS
2507If you do not enter the shell, the available shell commands are both
2508available as methods (C<CPAN::Shell-E<gt>install(...)>) and as
2509functions in the calling package (C<install(...)>). The
2510programmerE<39>s interface has beta status. Do not heavily rely on it,
42d3b621 2511changes may still be necessary.
5f05dabc 2512
2513=head2 Cache Manager
2514
2515Currently the cache manager only keeps track of the build directory
2516($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
42d3b621 2517deletes complete directories below C<build_dir> as soon as the size of
5f05dabc 2518all directories there gets bigger than $CPAN::Config->{build_cache}
2519(in MB). The contents of this cache may be used for later
2520re-installations that you intend to do manually, but will never be
10b2abe6
CS
2521trusted by CPAN itself. This is due to the fact that the user might
2522use these directories for building modules on different architectures.
5f05dabc 2523
2524There is another directory ($CPAN::Config->{keep_source_where}) where
2525the original distribution files are kept. This directory is not
2526covered by the cache manager and must be controlled by the user. If
2527you choose to have the same directory as build_dir and as
2528keep_source_where directory, then your sources will be deleted with
2529the same fifo mechanism.
2530
2531=head2 Bundles
2532
2533A bundle is just a perl module in the namespace Bundle:: that does not
2534define any functions or methods. It usually only contains documentation.
2535
2536It starts like a perl module with a package declaration and a $VERSION
2537variable. After that the pod section looks like any other pod with the
10b2abe6
CS
2538only difference, that I<one special pod section> exists starting with
2539(verbatim):
5f05dabc 2540
2541 =head1 CONTENTS
2542
2543In this pod section each line obeys the format
2544
2545 Module_Name [Version_String] [- optional text]
2546
2547The only required part is the first field, the name of a module
2548(eg. Foo::Bar, ie. I<not> the name of the distribution file). The rest
2549of the line is optional. The comment part is delimited by a dash just
2550as in the man page header.
2551
2552The distribution of a bundle should follow the same convention as
42d3b621 2553other distributions.
5f05dabc 2554
2555Bundles are treated specially in the CPAN package. If you say 'install
2556Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
2557the modules in the CONTENTS section of the pod. You can install your
2558own Bundles locally by placing a conformant Bundle file somewhere into
2559your @INC path. The autobundle() command which is available in the
2560shell interface does that for you by including all currently installed
2561modules in a snapshot bundle file.
2562
10b2abe6
CS
2563There is a meaningless Bundle::Demo available on CPAN. Try to install
2564it, it usually does no harm, just demonstrates what the Bundle
2565interface looks like.
2566
5f05dabc 2567=head2 autobundle
2568
42d3b621
A
2569C<autobundle> writes a bundle file into the
2570C<$CPAN::Config-E<gt>{cpan_home}/Bundle> directory. The file contains
2571a list of all modules that are both available from CPAN and currently
5f05dabc 2572installed within @INC. The name of the bundle file is based on the
2573current date and a counter.
2574
5f05dabc 2575=head2 recompile
2576
2577recompile() is a very special command in that it takes no argument and
2578runs the make/test/install cycle with brute force over all installed
2579dynamically loadable extensions (aka XS modules) with 'force' in
2580effect. Primary purpose of this command is to act as a rescue in case
2581your perl breaks binary compatibility. If one of the modules that CPAN
2582uses is in turn depending on binary compatibility (so you cannot run
2583CPAN commands), then you should try the CPAN::Nox module for recovery.
2584
42d3b621 2585Another popular use for recompile is to finish a network
10b2abe6
CS
2586installation. Imagine, you have a common source tree for two different
2587architectures. You decide to do a completely independent fresh
2588installation. You start on one architecture with the help of a Bundle
2589file produced earlier. CPAN installs the whole Bundle for you, but
2590when you try to repeat the job on the second architecture, CPAN
2591responds with a C<"Foo up to date"> message for all modules. So you
2592will be glad to run recompile in the second architecture and
2593youE<39>re done.
2594
5f05dabc 2595=head1 CONFIGURATION
2596
2597When the CPAN module is installed a site wide configuration file is
2598created as CPAN/Config.pm. The default values defined there can be
2599overridden in another configuration file: CPAN/MyConfig.pm. You can
2600store this file in $HOME/.cpan/CPAN/MyConfig.pm if you want, because
2601$HOME/.cpan is added to the search path of the CPAN module before the
2602use() or require() statements.
2603
2604Currently the following keys in the hash reference $CPAN::Config are
2605defined:
2606
42d3b621
A
2607 build_cache size of cache for directories to build modules
2608 build_dir locally accessible directory to build modules
2609 index_expire after how many days refetch index files
2610 cpan_home local directory reserved for this package
2611 gzip location of external program gzip
2612 inactivity_timeout breaks interactive Makefile.PLs after that
2613 many seconds inactivity. Set to 0 to never break.
5f05dabc 2614 inhibit_startup_message
42d3b621
A
2615 if true, does not print the startup message
2616 keep_source keep the source in a local directory?
2617 keep_source_where where keep the source (if we do)
2618 make location of external program make
2619 make_arg arguments that should always be passed to 'make'
2620 make_install_arg same as make_arg for 'make install'
2621 makepl_arg arguments passed to 'perl Makefile.PL'
2622 pager location of external program more (or any pager)
2623 tar location of external program tar
2624 unzip location of external program unzip
2625 urllist arrayref to nearby CPAN sites (or equivalent locations)
5f05dabc 2626
2627You can set and query each of these options interactively in the cpan
2628shell with the command set defined within the C<o conf> command:
2629
2630=over 2
2631
2632=item o conf E<lt>scalar optionE<gt>
2633
2634prints the current value of the I<scalar option>
2635
2636=item o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>
2637
2638Sets the value of the I<scalar option> to I<value>
2639
2640=item o conf E<lt>list optionE<gt>
2641
2642prints the current value of the I<list option> in MakeMaker's
2643neatvalue format.
2644
2645=item o conf E<lt>list optionE<gt> [shift|pop]
2646
2647shifts or pops the array in the I<list option> variable
2648
2649=item o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>
2650
42d3b621 2651works like the corresponding perl commands.
5f05dabc 2652
2653=back
2654
2655=head1 SECURITY
2656
2657There's no strong security layer in CPAN.pm. CPAN.pm helps you to
2658install foreign, unmasked, unsigned code on your machine. We compare
2659to a checksum that comes from the net just as the distribution file
2660itself. If somebody has managed to tamper with the distribution file,
2661they may have as well tampered with the CHECKSUMS file. Future
42d3b621 2662development will go towards strong authentification.
5f05dabc 2663
2664=head1 EXPORT
2665
2666Most functions in package CPAN are exported per default. The reason
2667for this is that the primary use is intended for the cpan shell or for
2668oneliners.
2669
2670=head1 Debugging
2671
2672The debugging of this module is pretty difficult, because we have
2673interferences of the software producing the indices on CPAN, of the
2674mirroring process on CPAN, of packaging, of configuration, of
2675synchronicity, and of bugs within CPAN.pm.
2676
2677In interactive mode you can try "o debug" which will list options for
2678debugging the various parts of the package. The output may not be very
2679useful for you as it's just a byproduct of my own testing, but if you
2680have an idea which part of the package may have a bug, it's sometimes
2681worth to give it a try and send me more specific output. You should
2682know that "o debug" has built-in completion support.
2683
2684=head2 Prerequisites
2685
2686If you have a local mirror of CPAN and can access all files with
2687"file:" URLs, then you only need perl5.003 to run this
42d3b621 2688module. Otherwise Net::FTP is recommended. LWP may be required for
5f05dabc 2689non-UNIX systems or if your nearest CPAN site is associated with an
2690URL that is not C<ftp:>.
2691
42d3b621
A
2692If you have neither Net::FTP nor LWP, there is a fallback mechanism
2693implemented for an external ftp command or for an external lynx
2694command.
2695
5f05dabc 2696This module presumes that all packages on CPAN
2697
2698=over 2
2699
2700=item *
2701
2702declare their $VERSION variable in an easy to parse manner. This
2703prerequisite can hardly be relaxed because it consumes by far too much
2704memory to load all packages into the running program just to determine
2705the $VERSION variable . Currently all programs that are dealing with
42d3b621 2706version use something like this
5f05dabc 2707
2708 perl -MExtUtils::MakeMaker -le \
2709 'print MM->parse_version($ARGV[0])' filename
2710
42d3b621 2711If you are author of a package and wonder if your $VERSION can be
5f05dabc 2712parsed, please try the above method.
2713
2714=item *
2715
2716come as compressed or gzipped tarfiles or as zip files and contain a
2717Makefile.PL (well we try to handle a bit more, but without much
2718enthusiasm).
2719
2720=back
2721
2722=head1 AUTHOR
2723
2724Andreas König E<lt>a.koenig@mind.deE<gt>
2725
2726=head1 SEE ALSO
2727
2728perl(1), CPAN::Nox(3)
2729
2730=cut
2731