1 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
2 # vim: ts=4 sts=4 sw=4:
5 @CPAN::Module::ISA = qw(CPAN::InfoObj);
13 #-> sub CPAN::Module::userid
18 return $ro->{userid} || $ro->{CPAN_USERID};
20 #-> sub CPAN::Module::description
23 my $ro = $self->ro or return "";
27 #-> sub CPAN::Module::distribution
30 CPAN::Shell->expand("Distribution",$self->cpan_file);
33 #-> sub CPAN::Module::_is_representative_module
34 sub _is_representative_module {
36 return $self->{_is_representative_module} if defined $self->{_is_representative_module};
37 my $pm = $self->cpan_file or return $self->{_is_representative_module} = 0;
39 $pm =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i; # see base_id
40 $pm =~ s|-\d+\.\d+.+$||;
43 $self->{_is_representative_module} = $pm eq $self->{ID} ? 1 : 0;
44 # warn "DEBUG: $pm eq $self->{ID} => $self->{_is_representative_module}";
45 $self->{_is_representative_module};
48 #-> sub CPAN::Module::undelay
51 delete $self->{later};
52 if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
58 #-> sub CPAN::Module::color_cmd_tmps ;
61 my($depth) = shift || 0;
62 my($color) = shift || 0;
63 my($ancestors) = shift || [];
64 # a module needs to recurse to its cpan_file
66 return if exists $self->{incommandcolor}
68 && $self->{incommandcolor}==$color;
69 return if $color==0 && !$self->{incommandcolor};
71 if ( $self->uptodate ) {
72 $self->{incommandcolor} = $color;
74 } elsif (my $have_version = $self->available_version) {
75 # maybe what we have is good enough
77 my $who_asked_for_me = $ancestors->[-1];
78 my $obj = CPAN::Shell->expandany($who_asked_for_me);
80 } elsif ($obj->isa("CPAN::Bundle")) {
81 # bundles cannot specify a minimum version
83 } elsif ($obj->isa("CPAN::Distribution")) {
84 if (my $prereq_pm = $obj->prereq_pm) {
85 for my $k (keys %$prereq_pm) {
86 if (my $want_version = $prereq_pm->{$k}{$self->id}) {
87 if (CPAN::Version->vcmp($have_version,$want_version) >= 0) {
88 $self->{incommandcolor} = $color;
98 $self->{incommandcolor} = $color; # set me before recursion,
101 if ($depth>=$CPAN::MAX_RECURSION) {
102 die(CPAN::Exception::RecursiveDependency->new($ancestors));
104 # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
106 if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
107 $dist->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
111 # delete $self->{badtestcnt};
113 $self->{incommandcolor} = $color;
116 #-> sub CPAN::Module::as_glimpse ;
120 my $class = ref($self);
121 $class =~ s/^CPAN:://;
125 $CPAN::Shell::COLOR_REGISTERED
127 $CPAN::META->has_inst("Term::ANSIColor")
131 $color_on = Term::ANSIColor::color("green");
132 $color_off = Term::ANSIColor::color("reset");
134 my $uptodateness = " ";
135 unless ($class eq "Bundle") {
136 my $u = $self->uptodate;
137 $uptodateness = $u ? "=" : "<" if defined $u;
140 my $d = $self->distribution;
141 $d ? $d -> pretty_id : $self->cpan_userid;
143 push @m, sprintf("%-7s %1s %s%-22s%s (%s)\n",
154 #-> sub CPAN::Module::dslip_status
159 @{$stat->{D}}{qw,i c a b R M S,} = qw,idea
160 pre-alpha alpha beta released
163 @{$stat->{S}}{qw,m d u n a,} = qw,mailing-list
164 developer comp.lang.perl.*
167 @{$stat->{L}}{qw,p c + o h,} = qw,perl C C++ other hybrid,;
169 @{$stat->{I}}{qw,f r O p h n,} = qw,functions
171 object-oriented pragma
174 @{$stat->{P}}{qw,p g l b a 2 o d r n,} = qw,Standard-Perl
176 BSD Artistic Artistic_2
179 restricted_distribution
181 for my $x (qw(d s l i p)) {
182 $stat->{$x}{' '} = 'unknown';
183 $stat->{$x}{'?'} = 'unknown';
186 return +{} unless $ro && $ro->{statd};
193 DV => $stat->{D}{$ro->{statd}},
194 SV => $stat->{S}{$ro->{stats}},
195 LV => $stat->{L}{$ro->{statl}},
196 IV => $stat->{I}{$ro->{stati}},
197 PV => $stat->{P}{$ro->{statp}},
201 #-> sub CPAN::Module::as_string ;
205 CPAN->debug("$self entering as_string") if $CPAN::DEBUG;
206 my $class = ref($self);
207 $class =~ s/^CPAN:://;
209 push @m, $class, " id = $self->{ID}\n";
210 my $sprintf = " %-12s %s\n";
211 push @m, sprintf($sprintf, 'DESCRIPTION', $self->description)
212 if $self->description;
213 my $sprintf2 = " %-12s %s (%s)\n";
215 $userid = $self->userid;
218 if ($author = CPAN::Shell->expand('Author',$userid)) {
221 if ($m = $author->email) {
228 $author->fullname . $email
232 push @m, sprintf($sprintf, 'CPAN_VERSION', $self->cpan_version)
233 if $self->cpan_version;
234 if (my $cpan_file = $self->cpan_file) {
235 push @m, sprintf($sprintf, 'CPAN_FILE', $cpan_file);
236 if (my $dist = CPAN::Shell->expand("Distribution",$cpan_file)) {
237 my $upload_date = $dist->upload_date;
239 push @m, sprintf($sprintf, 'UPLOAD_DATE', $upload_date);
243 my $sprintf3 = " %-12s %1s%1s%1s%1s%1s (%s,%s,%s,%s,%s)\n";
244 my $dslip = $self->dslip_status;
248 @{$dslip}{qw(D S L I P DV SV LV IV PV)},
250 my $local_file = $self->inst_file;
251 unless ($self->{MANPAGE}) {
254 $manpage = $self->manpage_headline($local_file);
256 # If we have already untarred it, we should look there
257 my $dist = $CPAN::META->instance('CPAN::Distribution',
259 # warn "dist[$dist]";
260 # mff=manifest file; mfh=manifest handle
265 (-f ($mff = File::Spec->catfile($dist->{build_dir}, "MANIFEST")))
267 $mfh = FileHandle->new($mff)
269 CPAN->debug("mff[$mff]") if $CPAN::DEBUG;
270 my $lfre = $self->id; # local file RE
273 my($lfl); # local file file
275 my(@mflines) = <$mfh>;
280 while (length($lfre)>5 and !$lfl) {
281 ($lfl) = grep /$lfre/, @mflines;
282 CPAN->debug("lfl[$lfl]lfre[$lfre]") if $CPAN::DEBUG;
285 $lfl =~ s/\s.*//; # remove comments
286 $lfl =~ s/\s+//g; # chomp would maybe be too system-specific
287 my $lfl_abs = File::Spec->catfile($dist->{build_dir},$lfl);
288 # warn "lfl_abs[$lfl_abs]";
290 $manpage = $self->manpage_headline($lfl_abs);
294 $self->{MANPAGE} = $manpage if $manpage;
297 for $item (qw/MANPAGE/) {
298 push @m, sprintf($sprintf, $item, $self->{$item})
299 if exists $self->{$item};
301 for $item (qw/CONTAINS/) {
302 push @m, sprintf($sprintf, $item, join(" ",@{$self->{$item}}))
303 if exists $self->{$item} && @{$self->{$item}};
305 push @m, sprintf($sprintf, 'INST_FILE',
306 $local_file || "(not installed)");
307 push @m, sprintf($sprintf, 'INST_VERSION',
308 $self->inst_version) if $local_file;
309 if (%{$CPAN::META->{is_tested}||{}}) { # XXX needs to be methodified somehow
310 my $available_file = $self->available_file;
311 if ($available_file && $available_file ne $local_file) {
312 push @m, sprintf($sprintf, 'AVAILABLE_FILE', $available_file);
313 push @m, sprintf($sprintf, 'AVAILABLE_VERSION', $self->available_version);
319 #-> sub CPAN::Module::manpage_headline
320 sub manpage_headline {
321 my($self,$local_file) = @_;
322 my(@local_file) = $local_file;
323 $local_file =~ s/\.pm(?!\n)\Z/.pod/;
324 push @local_file, $local_file;
326 for $locf (@local_file) {
327 next unless -f $locf;
328 my $fh = FileHandle->new($locf)
329 or $Carp::Frontend->mydie("Couldn't open $locf: $!");
333 $inpod = m/^=(?!head1\s+NAME\s*$)/ ? 0 :
334 m/^=head1\s+NAME\s*$/ ? 1 : $inpod;
351 #-> sub CPAN::Module::cpan_file ;
352 # Note: also inherited by CPAN::Bundle
355 # CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
360 if ($ro && defined $ro->{CPAN_FILE}) {
361 return $ro->{CPAN_FILE};
363 my $userid = $self->userid;
365 if ($CPAN::META->exists("CPAN::Author",$userid)) {
366 my $author = $CPAN::META->instance("CPAN::Author",
368 my $fullname = $author->fullname;
369 my $email = $author->email;
370 unless (defined $fullname && defined $email) {
371 return sprintf("Contact Author %s",
375 return "Contact Author $fullname <$email>";
377 return "Contact Author $userid (Email address not available)";
385 #-> sub CPAN::Module::cpan_version ;
391 # Can happen with modules that are not on CPAN
394 $ro->{CPAN_VERSION} = 'undef'
395 unless defined $ro->{CPAN_VERSION};
399 #-> sub CPAN::Module::force ;
402 $self->{force_update} = 1;
405 #-> sub CPAN::Module::fforce ;
408 $self->{force_update} = 2;
411 #-> sub CPAN::Module::notest ;
414 # $CPAN::Frontend->mywarn("XDEBUG: set notest for Module");
418 #-> sub CPAN::Module::rematein ;
420 my($self,$meth) = @_;
421 $CPAN::Frontend->myprint(sprintf("Running %s for module '%s'\n",
424 my $cpan_file = $self->cpan_file;
425 if ($cpan_file eq "N/A" || $cpan_file =~ /^Contact Author/) {
426 $CPAN::Frontend->mywarn(sprintf qq{
427 The module %s isn\'t available on CPAN.
429 Either the module has not yet been uploaded to CPAN, or it is
430 temporary unavailable. Please contact the author to find out
431 more about the status. Try 'i %s'.
438 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
439 $pack->called_for($self->id);
440 if (exists $self->{force_update}) {
441 if ($self->{force_update} == 2) {
442 $pack->fforce($meth);
447 $pack->notest($meth) if exists $self->{notest} && $self->{notest};
449 $pack->{reqtype} ||= "";
450 CPAN->debug("dist-reqtype[$pack->{reqtype}]".
451 "self-reqtype[$self->{reqtype}]") if $CPAN::DEBUG;
452 if ($pack->{reqtype}) {
453 if ($pack->{reqtype} eq "b" && $self->{reqtype} =~ /^[rc]$/) {
454 $pack->{reqtype} = $self->{reqtype};
456 exists $pack->{install}
459 UNIVERSAL::can($pack->{install},"failed") ?
460 $pack->{install}->failed :
461 $pack->{install} =~ /^NO/
464 delete $pack->{install};
465 $CPAN::Frontend->mywarn
466 ("Promoting $pack->{ID} from 'build_requires' to 'requires'");
470 $pack->{reqtype} = $self->{reqtype};
477 $pack->unforce if $pack->can("unforce") && exists $self->{force_update};
478 $pack->unnotest if $pack->can("unnotest") && exists $self->{notest};
479 delete $self->{force_update};
480 delete $self->{notest};
487 #-> sub CPAN::Module::perldoc ;
488 sub perldoc { shift->rematein('perldoc') }
489 #-> sub CPAN::Module::readme ;
490 sub readme { shift->rematein('readme') }
491 #-> sub CPAN::Module::look ;
492 sub look { shift->rematein('look') }
493 #-> sub CPAN::Module::cvs_import ;
494 sub cvs_import { shift->rematein('cvs_import') }
495 #-> sub CPAN::Module::get ;
496 sub get { shift->rematein('get',@_) }
497 #-> sub CPAN::Module::make ;
498 sub make { shift->rematein('make') }
499 #-> sub CPAN::Module::test ;
502 # $self->{badtestcnt} ||= 0;
503 $self->rematein('test',@_);
506 #-> sub CPAN::Module::uptodate ;
510 my $inst = $self->inst_version or return undef;
511 my $cpan = $self->cpan_version;
513 CPAN::Version->vgt($cpan,$inst) and return 0;
514 my $inst_file = $self->inst_file;
515 # trying to support deprecated.pm by Nicholas 2009-02
516 my $in_priv_or_arch = "";
518 if ($] >= 5.011) { # probably harmful when distros say INSTALLDIRS=perl?
519 if (0 == CPAN::Version->vcmp($cpan,$inst)) {
520 if ($in_priv_or_arch = $self->_in_priv_or_arch($inst_file)) {
521 if (my $distribution = $self->distribution) {
522 unless ($isa_perl = $distribution->isa_perl) {
532 "returning uptodate. ",
533 "inst_file[$inst_file]",
534 "cpan[$cpan]inst[$inst]",
535 "in_priv_or_arch[$in_priv_or_arch]",
536 "isa_perl[$isa_perl]",
541 # returns true if installed in privlib or archlib
542 sub _in_priv_or_arch {
543 my($self,$inst_file) = @_;
544 for my $confdirname (qw(archlibexp privlibexp)) {
545 my $confdir = $Config::Config{$confdirname};
546 if ($confdir eq substr($inst_file,0,length($confdir))) {
553 #-> sub CPAN::Module::install ;
559 not exists $self->{force_update}
561 $CPAN::Frontend->myprint(sprintf("%s is up to date (%s).\n",
569 if ($ro && $ro->{stats} && $ro->{stats} eq "a") {
570 $CPAN::Frontend->mywarn(qq{
572 The module $self->{ID} has no active maintainer.\n\n\n
574 $CPAN::Frontend->mysleep(5);
576 return $doit ? $self->rematein('install') : 1;
578 #-> sub CPAN::Module::clean ;
579 sub clean { shift->rematein('clean') }
581 #-> sub CPAN::Module::inst_file ;
584 $self->_file_in_path([@INC]);
587 #-> sub CPAN::Module::available_file ;
590 my $sep = $Config::Config{path_sep};
591 my $perllib = $ENV{PERL5LIB};
592 $perllib = $ENV{PERLLIB} unless defined $perllib;
593 my @perllib = split(/$sep/,$perllib) if defined $perllib;
595 if ($CPAN::Perl5lib_tempfile) {
596 my $yaml = CPAN->_yaml_loadfile($CPAN::Perl5lib_tempfile);
597 @cpan_perl5inc = @{$yaml->[0]{inc} || []};
599 $self->_file_in_path([@cpan_perl5inc,@perllib,@INC]);
602 #-> sub CPAN::Module::file_in_path ;
604 my($self,$path) = @_;
606 @packpath = split /::/, $self->{ID};
607 $packpath[-1] .= ".pm";
608 if (@packpath == 1 && $packpath[0] eq "readline.pm") {
609 unshift @packpath, "Term", "ReadLine"; # historical reasons
611 foreach $dir (@$path) {
612 my $pmfile = File::Spec->catfile($dir,@packpath);
620 #-> sub CPAN::Module::xs_file ;
624 @packpath = split /::/, $self->{ID};
625 push @packpath, $packpath[-1];
626 $packpath[-1] .= "." . $Config::Config{'dlext'};
627 foreach $dir (@INC) {
628 my $xsfile = File::Spec->catfile($dir,'auto',@packpath);
636 #-> sub CPAN::Module::inst_version ;
639 my $parsefile = $self->inst_file or return;
640 my $have = $self->parse_version($parsefile);
644 #-> sub CPAN::Module::inst_version ;
645 sub available_version {
647 my $parsefile = $self->available_file or return;
648 my $have = $self->parse_version($parsefile);
652 #-> sub CPAN::Module::parse_version ;
654 my($self,$parsefile) = @_;
655 my $have = eval { MM->parse_version($parsefile); };
657 $CPAN::Frontend->mywarn("Error while parsing version number in file '$parsefile'\n");
659 my $leastsanity = eval { defined $have && length $have; };
660 $have = "undef" unless $leastsanity;
661 $have =~ s/^ //; # since the %vd hack these two lines here are needed
662 $have =~ s/ $//; # trailing whitespace happens all the time
664 $have = CPAN::Version->readable($have);
666 $have =~ s/\s*//g; # stringify to float around floating point issues
667 $have; # no stringify needed, \s* above matches always
670 #-> sub CPAN::Module::reports
673 $self->distribution->reports;