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