4 # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
5 # vim: ts=4 sts=4 sw=4:
21 "CPAN/Distroprefs.pm",
23 "CPAN/HandleConfig.pm",
26 "CPAN/Reporter/Config.pm",
27 "CPAN/Reporter/History.pm",
28 "CPAN/Reporter/PrereqCheck.pm",
35 # record the initial timestamp for reload.
36 $reload = { map {$INC{$_} ? ($_,(stat $INC{$_})[9]) : ()} @relo };
37 @CPAN::Shell::ISA = qw(CPAN::Debug);
40 $COLOR_REGISTERED ||= 0;
43 '!' => "eval the rest of the line as perl",
45 autobundle => "write inventory into a bundle file",
46 b => "info about bundle",
48 clean => "clean up a distribution's build directory",
50 d => "info about a distribution",
53 failed => "list all failed actions within current session",
54 fforce => "redo a command from scratch",
55 force => "redo a command",
56 get => "download a distribution",
58 help => "overview over commands; 'help ...' explains specific commands",
59 hosts => "statistics about recently used hosts",
60 i => "info about authors/bundles/distributions/modules",
61 install => "install a distribution",
62 install_tested => "install all distributions tested OK",
63 is_tested => "list all distributions tested OK",
64 look => "open a subshell in a distribution's directory",
65 ls => "list distributions matching a fileglob",
66 m => "info about a module",
67 make => "make/build a distribution",
68 mkmyconfig => "write current config into a CPAN/MyConfig.pm file",
69 notest => "run a (usually install) command but leave out the test phase",
70 o => "'o conf ...' for config stuff; 'o debug ...' for debugging",
71 perldoc => "try to get a manpage for a module",
73 quit => "leave the cpan shell",
74 r => "review upgradable modules",
75 readme => "display the README of a distro with a pager",
76 recent => "show recent uploads to the CPAN",
78 reload => "'reload cpan' or 'reload index'",
79 report => "test a distribution and send a test report to cpantesters",
80 reports => "info about reported tests from cpantesters",
83 test => "test a distribution",
84 u => "display uninstalled modules",
85 upgrade => "combine 'r' command with immediate installation",
88 $autoload_recursion ||= 0;
90 #-> sub CPAN::Shell::AUTOLOAD ;
91 sub AUTOLOAD { ## no critic
92 $autoload_recursion++;
94 my $class = shift(@_);
95 # warn "autoload[$l] class[$class]";
98 warn "Refusing to autoload '$l' while signal pending";
99 $autoload_recursion--;
102 if ($autoload_recursion > 1) {
103 my $fullcommand = join " ", map { "'$_'" } $l, @_;
104 warn "Refusing to autoload $fullcommand in recursion\n";
105 $autoload_recursion--;
109 # XXX needs to be reconsidered
110 if ($CPAN::META->has_inst('CPAN::WAIT')) {
113 $CPAN::Frontend->mywarn(qq{
114 Commands starting with "w" require CPAN::WAIT to be installed.
115 Please consider installing CPAN::WAIT to use the fulltext index.
116 For this you just need to type
121 $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }.
125 $autoload_recursion--;
130 #-> sub CPAN::Shell::h ;
132 my($class,$about) = @_;
133 if (defined $about) {
135 if (exists $Help->{$about}) {
136 if (ref $Help->{$about}) { # aliases
137 $about = ${$Help->{$about}};
139 $help = $Help->{$about};
141 $help = "No help available";
143 $CPAN::Frontend->myprint("$about\: $help\n");
145 my $filler = " " x (80 - 28 - length($CPAN::VERSION));
146 $CPAN::Frontend->myprint(qq{
147 Display Information $filler (ver $CPAN::VERSION)
148 command argument description
149 a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
150 i WORD or /REGEXP/ about any of the above
151 ls AUTHOR or GLOB about files in the author's directory
152 (with WORD being a module, bundle or author name or a distribution
153 name of the form AUTHOR/DISTRIBUTION)
155 Download, Test, Make, Install...
156 get download clean make clean
157 make make (implies get) look open subshell in dist directory
158 test make test (implies make) readme display these README files
159 install make install (implies test) perldoc display POD documentation
162 r WORDs or /REGEXP/ or NONE report updates for some/matching/all modules
163 upgrade WORDs or /REGEXP/ or NONE upgrade some/matching/all modules
166 force CMD try hard to do command fforce CMD try harder
167 notest CMD skip testing
170 h,? display this menu ! perl-code eval a perl command
171 o conf [opt] set and query options q quit the cpan shell
172 reload cpan load CPAN.pm again reload index load newer indices
173 autobundle Snapshot recent latest CPAN uploads});
179 #-> sub CPAN::Shell::a ;
182 # authors are always UPPERCASE
184 $_ = uc $_ unless /=/;
186 $CPAN::Frontend->myprint($self->format_result('Author',@arg));
189 #-> sub CPAN::Shell::globls ;
191 my($self,$s,$pragmas) = @_;
192 # ls is really very different, but we had it once as an ordinary
193 # command in the Shell (upto rev. 321) and we could not handle
195 my(@accept,@preexpand);
196 if ($s =~ /[\*\?\/]/) {
197 if ($CPAN::META->has_inst("Text::Glob")) {
198 if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
199 my $rau = Text::Glob::glob_to_regex(uc $au);
200 CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
202 push @preexpand, map { $_->id . "/" . $pathglob }
203 CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
205 my $rau = Text::Glob::glob_to_regex(uc $s);
206 push @preexpand, map { $_->id }
207 CPAN::Shell->expand_by_method('CPAN::Author',
212 $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
215 push @preexpand, uc $s;
218 unless (/^[A-Z0-9\-]+(\/|$)/i) {
219 $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
224 my $silent = @accept>1;
227 for my $a (@accept) {
228 my($author,$pathglob);
229 if ($a =~ m|(.*?)/(.*)|) {
232 $author = CPAN::Shell->expand_by_method('CPAN::Author',
235 or $CPAN::Frontend->mydie("No author found for $a2\n");
237 $author = CPAN::Shell->expand_by_method('CPAN::Author',
240 or $CPAN::Frontend->mydie("No author found for $a\n");
243 my $alpha = substr $author->id, 0, 1;
245 if ($alpha eq $last_alpha) {
249 $last_alpha = $alpha;
251 $CPAN::Frontend->myprint($ad);
253 for my $pragma (@$pragmas) {
254 if ($author->can($pragma)) {
258 push @results, $author->ls($pathglob,$silent); # silent if
261 for my $pragma (@$pragmas) {
262 my $unpragma = "un$pragma";
263 if ($author->can($unpragma)) {
264 $author->$unpragma();
271 #-> sub CPAN::Shell::local_bundles ;
273 my($self,@which) = @_;
274 my($incdir,$bdir,$dh);
275 foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
276 my @bbase = "Bundle";
277 while (my $bbase = shift @bbase) {
278 $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
279 CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
280 if ($dh = DirHandle->new($bdir)) { # may fail
282 for $entry ($dh->read) {
283 next if $entry =~ /^\./;
284 next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
285 if (-d File::Spec->catdir($bdir,$entry)) {
286 push @bbase, "$bbase\::$entry";
288 next unless $entry =~ s/\.pm(?!\n)\Z//;
289 $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
297 #-> sub CPAN::Shell::b ;
299 my($self,@which) = @_;
300 CPAN->debug("which[@which]") if $CPAN::DEBUG;
301 $self->local_bundles;
302 $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
305 #-> sub CPAN::Shell::d ;
306 sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}
308 #-> sub CPAN::Shell::m ;
309 sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
311 $CPAN::Frontend->myprint($self->format_result('Module',@_));
314 #-> sub CPAN::Shell::i ;
318 @args = '/./' unless @args;
320 for my $type (qw/Bundle Distribution Module/) {
321 push @result, $self->expand($type,@args);
323 # Authors are always uppercase.
324 push @result, $self->expand("Author", map { uc $_ } @args);
326 my $result = @result == 1 ?
327 $result[0]->as_string :
329 "No objects found of any type for argument @args\n" :
331 (map {$_->as_glimpse} @result),
332 scalar @result, " items found\n",
334 $CPAN::Frontend->myprint($result);
337 #-> sub CPAN::Shell::o ;
339 # CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o
340 # conf' calls through to CPAN::HandleConfig::edit. 'o conf' should
341 # probably have been called 'set' and 'o debug' maybe 'set debug' or
342 # 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
344 my($self,$o_type,@o_what) = @_;
346 CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
347 if ($o_type eq 'conf') {
349 ($cfilter) = $o_what[0] =~ m|^/(.*)/$| if @o_what;
350 if (!@o_what or $cfilter) { # print all things, "o conf"
352 my $qrfilter = eval 'qr/$cfilter/';
354 $CPAN::Frontend->myprint("\$CPAN::Config options from ");
356 if (exists $INC{'CPAN/Config.pm'}) {
357 push @from, $INC{'CPAN/Config.pm'};
359 if (exists $INC{'CPAN/MyConfig.pm'}) {
360 push @from, $INC{'CPAN/MyConfig.pm'};
362 $CPAN::Frontend->myprint(join " and ", map {"'$_'"} @from);
363 $CPAN::Frontend->myprint(":\n");
364 for $k (sort keys %CPAN::HandleConfig::can) {
365 next unless $k =~ /$qrfilter/;
366 $v = $CPAN::HandleConfig::can{$k};
367 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
369 $CPAN::Frontend->myprint("\n");
370 for $k (sort keys %CPAN::HandleConfig::keys) {
371 next unless $k =~ /$qrfilter/;
372 CPAN::HandleConfig->prettyprint($k);
374 $CPAN::Frontend->myprint("\n");
376 if (CPAN::HandleConfig->edit(@o_what)) {
378 $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
382 } elsif ($o_type eq 'debug') {
384 @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
387 my($what) = shift @o_what;
388 if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
389 $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
392 if ( exists $CPAN::DEBUG{$what} ) {
393 $CPAN::DEBUG |= $CPAN::DEBUG{$what};
394 } elsif ($what =~ /^\d/) {
395 $CPAN::DEBUG = $what;
396 } elsif (lc $what eq 'all') {
398 for (values %CPAN::DEBUG) {
404 for (keys %CPAN::DEBUG) {
405 next unless lc($_) eq lc($what);
406 $CPAN::DEBUG |= $CPAN::DEBUG{$_};
409 $CPAN::Frontend->myprint("unknown argument [$what]\n")
414 my $raw = "Valid options for debug are ".
415 join(", ",sort(keys %CPAN::DEBUG), 'all').
416 qq{ or a number. Completion works on the options. }.
417 qq{Case is ignored.};
419 $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
420 $CPAN::Frontend->myprint("\n\n");
423 $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n");
425 for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
426 $v = $CPAN::DEBUG{$k};
427 $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v)
428 if $v & $CPAN::DEBUG;
431 $CPAN::Frontend->myprint("Debugging turned off completely.\n");
434 $CPAN::Frontend->myprint(qq{
436 conf set or get configuration variables
437 debug set or get debugging options
442 # CPAN::Shell::paintdots_onreload
443 sub paintdots_onreload {
446 if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
450 # $CPAN::Frontend->myprint(".($subr)");
451 $CPAN::Frontend->myprint(".");
452 if ($subr =~ /\bshell\b/i) {
453 # warn "debug[$_[0]]";
455 # It would be nice if we could detect that a
456 # subroutine has actually changed, but for now we
457 # practically always set the GOTOSHELL global
467 #-> sub CPAN::Shell::hosts ;
470 my $fullstats = CPAN::FTP->_ftp_statistics();
471 my $history = $fullstats->{history} || [];
473 while (my $last = pop @$history) {
474 my $attempts = $last->{attempts} or next;
477 $start = $attempts->[-1]{start};
478 if ($#$attempts > 0) {
479 for my $i (0..$#$attempts-1) {
480 my $url = $attempts->[$i]{url} or next;
485 $start = $last->{start};
487 next unless $last->{thesiteurl}; # C-C? bad filenames?
489 $S{end} ||= $last->{end};
490 my $dltime = $last->{end} - $start;
491 my $dlsize = $last->{filesize} || 0;
492 my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
493 my $s = $S{ok}{$url} ||= {};
496 $s->{dlsize} += $dlsize/1024;
498 $s->{dltime} += $dltime;
501 for my $url (keys %{$S{ok}}) {
502 next if $S{ok}{$url}{dltime} == 0; # div by zero
503 push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)},
504 $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime},
508 for my $url (keys %{$S{no}}) {
509 push @{$res->{no}}, [$S{no}{$url},
514 if ($S{start} && $S{end}) {
515 $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown";
516 $R .= sprintf "Log ends : %s\n", $S{end} ? scalar(localtime $S{end}) : "unknown";
518 if ($res->{ok} && @{$res->{ok}}) {
519 $R .= sprintf "\nSuccessful downloads:
520 N kB secs kB/s url\n";
522 for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) {
523 $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_;
527 if ($res->{no} && @{$res->{no}}) {
528 $R .= sprintf "\nUnsuccessful downloads:\n";
530 for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) {
531 $R .= sprintf "%4d %s\n", @$_;
535 $CPAN::Frontend->myprint($R);
538 # here is where 'reload cpan' is done
539 #-> sub CPAN::Shell::reload ;
541 my($self,$command,@arg) = @_;
543 $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
544 if ($command =~ /^cpan$/i) {
546 chdir $CPAN::iCwd if $CPAN::iCwd; # may fail
548 MFILE: for my $f (@relo) {
549 next unless exists $INC{$f};
553 $CPAN::Frontend->myprint("($p");
554 local($SIG{__WARN__}) = paintdots_onreload(\$redef);
555 $self->_reload_this($f) or $failed++;
556 my $v = eval "$p\::->VERSION";
557 $CPAN::Frontend->myprint("v$v)");
559 $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
561 my $errors = $failed == 1 ? "error" : "errors";
562 $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ".
565 } elsif ($command =~ /^index$/i) {
566 CPAN::Index->force_reload;
568 $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN modules
569 index re-reads the index files\n});
573 # reload means only load again what we have loaded before
574 #-> sub CPAN::Shell::_reload_this ;
576 my($self,$f,$args) = @_;
577 CPAN->debug("f[$f]") if $CPAN::DEBUG;
578 return 1 unless $INC{$f}; # we never loaded this, so we do not
580 my $pwd = CPAN::anycwd();
581 CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG;
584 $file = File::Spec->catfile($inc,split /\//, $f);
588 CPAN->debug("file[$file]") if $CPAN::DEBUG;
590 unless ($file && -f $file) {
591 # this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
593 unless (CPAN->has_inst("File::Basename")) {
594 @inc = File::Basename::dirname($file);
596 # do we ever need this?
597 @inc = substr($file,0,-length($f)-1); # bring in back to me!
600 CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
602 $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
605 my $mtime = (stat $file)[9];
606 $reload->{$f} ||= -1;
607 my $must_reload = $mtime != $reload->{$f};
609 $must_reload ||= $args->{reloforce}; # o conf defaults needs this
611 my $fh = FileHandle->new($file) or
612 $CPAN::Frontend->mydie("Could not open $file: $!");
616 CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128)))
625 $reload->{$f} = $mtime;
627 $CPAN::Frontend->myprint("__unchanged__");
632 #-> sub CPAN::Shell::mkmyconfig ;
634 my($self, $cpanpm, %args) = @_;
635 require CPAN::FirstTime;
636 my $home = CPAN::HandleConfig::home();
637 $cpanpm = $INC{'CPAN/MyConfig.pm'} ||
638 File::Spec->catfile(split /\//, "$home/.cpan/CPAN/MyConfig.pm");
639 File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm;
640 CPAN::HandleConfig::require_myconfig_or_config();
641 $CPAN::Config ||= {};
646 keep_source_where => undef,
649 CPAN::FirstTime::init($cpanpm, %args);
652 #-> sub CPAN::Shell::_binary_extensions ;
653 sub _binary_extensions {
654 my($self) = shift @_;
655 my(@result,$module,%seen,%need,$headerdone);
656 for $module ($self->expand('Module','/./')) {
657 my $file = $module->cpan_file;
658 next if $file eq "N/A";
659 next if $file =~ /^Contact Author/;
660 my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
661 next if $dist->isa_perl;
662 next unless $module->xs_file;
664 $CPAN::Frontend->myprint(".");
665 push @result, $module;
667 # print join " | ", @result;
668 $CPAN::Frontend->myprint("\n");
672 #-> sub CPAN::Shell::recompile ;
674 my($self) = shift @_;
675 my($module,@module,$cpan_file,%dist);
676 @module = $self->_binary_extensions();
677 for $module (@module) { # we force now and compile later, so we
679 $cpan_file = $module->cpan_file;
680 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
684 for $cpan_file (sort keys %dist) {
685 $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n");
686 my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
688 $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
689 # stop a package from recompiling,
690 # e.g. IO-1.12 when we have perl5.003_10
694 #-> sub CPAN::Shell::scripts ;
696 my($self, $arg) = @_;
697 $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n");
699 for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) {
700 unless ($CPAN::META->has_inst($req)) {
701 $CPAN::Frontend->mywarn(" $req not available\n");
704 my $p = HTML::LinkExtor->new();
705 my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html";
706 unless (-f $indexfile) {
707 $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n");
709 $p->parse_file($indexfile);
712 if ($arg =~ s|^/(.+)/$|$1|) {
713 $qrarg = eval 'qr/$arg/'; # hide construct from 5.004
715 for my $l ($p->links) {
717 next unless $tag eq "a";
719 my $href = $att{href};
720 next unless $href =~ s|^\.\./authors/id/./../||;
723 if ($href =~ $qrarg) {
727 if ($href =~ /\Q$arg\E/) {
735 # now filter for the latest version if there is more than one of a name
741 $stems{$stem} ||= [];
742 push @{$stems{$stem}}, $href;
744 for (sort keys %stems) {
746 if (@{$stems{$_}} > 1) {
747 $highest = List::Util::reduce {
748 Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b
751 $highest = $stems{$_}[0];
753 $CPAN::Frontend->myprint("$highest\n");
757 #-> sub CPAN::Shell::report ;
759 my($self,@args) = @_;
760 unless ($CPAN::META->has_inst("CPAN::Reporter")) {
761 $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
763 local $CPAN::Config->{test_report} = 1;
764 $self->force("test",@args); # force is there so that the test be
765 # re-run (as documented)
768 # compare with is_tested
769 #-> sub CPAN::Shell::install_tested
771 my($self,@some) = @_;
772 $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"),
776 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
779 $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
782 my $yaml_content = CPAN->_yaml_loadfile($yaml);
783 my $id = $yaml_content->[0]{distribution}{ID};
785 $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
788 my $do = CPAN::Shell->expandany($id);
790 $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n");
793 unless ($do->{build_dir}) {
794 $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n");
797 unless ($do->{build_dir} eq $b) {
798 $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n");
804 $CPAN::Frontend->mywarn("No tested distributions found.\n"),
807 @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some;
808 $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"),
811 # @some = grep { not $_->uptodate } @some;
812 # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"),
813 # return unless @some;
815 CPAN->debug("some[@some]");
817 my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id;
818 $CPAN::Frontend->myprint("install_tested: Running for $id\n");
819 $CPAN::Frontend->mysleep(1);
824 #-> sub CPAN::Shell::upgrade ;
826 my($self,@args) = @_;
827 $self->install($self->r(@args));
830 #-> sub CPAN::Shell::_u_r_common ;
832 my($self) = shift @_;
833 my($what) = shift @_;
834 CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
835 Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
836 $what && $what =~ /^[aru]$/;
838 @args = '/./' unless @args;
839 my(@result,$module,%seen,%need,$headerdone,
840 $version_undefs,$version_zeroes,
841 @version_undefs,@version_zeroes);
842 $version_undefs = $version_zeroes = 0;
843 my $sprintf = "%s%-25s%s %9s %9s %s\n";
844 my @expand = $self->expand('Module',@args);
845 if ($CPAN::DEBUG) { # Looks like noise to me, was very useful for debugging
847 my $expand = scalar @expand;
848 $CPAN::Frontend->myprint(sprintf "%d matches in the database, time[%d]\n", $expand, time);
852 # hard to believe that the more complex sorting can lead to
853 # stack curruptions on older perl
854 @sexpand = sort {$a->id cmp $b->id} @expand;
861 $a->[1]{ID} cmp $b->[1]{ID},
863 [$_->_is_representative_module,
869 $CPAN::Frontend->myprint(sprintf "sorted at time[%d]\n", time);
872 MODULE: for $module (@sexpand) {
873 my $file = $module->cpan_file;
874 next MODULE unless defined $file; # ??
876 my($latest) = $module->cpan_version;
877 my($inst_file) = $module->inst_file;
878 CPAN->debug("file[$file]latest[$latest]") if $CPAN::DEBUG;
880 return if $CPAN::Signal;
882 eval { # version.pm involved!
885 $have = $module->inst_version;
886 } elsif ($what eq "r") {
887 $have = $module->inst_version;
889 if ($have eq "undef") {
891 push @version_undefs, $module->as_glimpse;
892 } elsif (CPAN::Version->vcmp($have,0)==0) {
894 push @version_zeroes, $module->as_glimpse;
896 ++$next_MODULE unless CPAN::Version->vgt($latest, $have);
897 # to be pedantic we should probably say:
898 # && !($have eq "undef" && $latest ne "undef" && $latest gt "");
899 # to catch the case where CPAN has a version 0 and we have a version undef
900 } elsif ($what eq "u") {
906 } elsif ($what eq "r") {
908 } elsif ($what eq "u") {
913 next MODULE if $next_MODULE;
915 $CPAN::Frontend->mywarn
916 (sprintf("Error while comparing cpan/installed versions of '%s':
923 (defined $have ? $have : "[UNDEFINED]"),
924 (ref $have ? ref $have : ""),
926 (ref $latest ? ref $latest : ""),
930 return if $CPAN::Signal; # this is sometimes lengthy
933 push @result, sprintf "%s %s\n", $module->id, $have;
934 } elsif ($what eq "r") {
935 push @result, $module->id;
936 next MODULE if $seen{$file}++;
937 } elsif ($what eq "u") {
938 push @result, $module->id;
939 next MODULE if $seen{$file}++;
940 next MODULE if $file =~ /^Contact/;
942 unless ($headerdone++) {
943 $CPAN::Frontend->myprint("\n");
944 $CPAN::Frontend->myprint(sprintf(
959 $CPAN::META->has_inst("Term::ANSIColor")
963 $color_on = Term::ANSIColor::color("green");
964 $color_off = Term::ANSIColor::color("reset");
966 $CPAN::Frontend->myprint(sprintf $sprintf,
973 $need{$module->id}++;
977 $CPAN::Frontend->myprint("No modules found for @args\n");
978 } elsif ($what eq "r") {
979 $CPAN::Frontend->myprint("All modules are up to date for @args\n");
983 if ($version_zeroes) {
984 my $s_has = $version_zeroes > 1 ? "s have" : " has";
985 $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
986 qq{a version number of 0\n});
987 if ($CPAN::Config->{show_zero_versions}) {
989 $CPAN::Frontend->myprint(qq{ they are\n\t@version_zeroes\n});
990 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }.
991 qq{to hide them)\n});
993 $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }.
994 qq{to show them)\n});
997 if ($version_undefs) {
998 my $s_has = $version_undefs > 1 ? "s have" : " has";
999 $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
1000 qq{parsable version number\n});
1001 if ($CPAN::Config->{show_unparsable_versions}) {
1003 $CPAN::Frontend->myprint(qq{ they are\n\t@version_undefs\n});
1004 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }.
1005 qq{to hide them)\n});
1007 $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }.
1008 qq{to show them)\n});
1015 #-> sub CPAN::Shell::r ;
1017 shift->_u_r_common("r",@_);
1020 #-> sub CPAN::Shell::u ;
1022 shift->_u_r_common("u",@_);
1025 #-> sub CPAN::Shell::failed ;
1027 my($self,$only_id,$silent) = @_;
1029 DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
1031 NAY: for my $nosayer ( # order matters!
1040 next unless exists $d->{$nosayer};
1041 next unless defined $d->{$nosayer};
1043 UNIVERSAL::can($d->{$nosayer},"failed") ?
1044 $d->{$nosayer}->failed :
1045 $d->{$nosayer} =~ /^NO/
1047 next NAY if $only_id && $only_id != (
1048 UNIVERSAL::can($d->{$nosayer},"commandid")
1050 $d->{$nosayer}->commandid
1052 $CPAN::CurrentCommandId
1057 next DIST unless $failed;
1061 # " %-45s: %s %s\n",
1064 UNIVERSAL::can($d->{$failed},"failed") ?
1066 $d->{$failed}->commandid,
1069 $d->{$failed}->text,
1070 $d->{$failed}{TIME}||0,
1083 $scope = "this command";
1084 } elsif ($CPAN::Index::HAVE_REANIMATED) {
1085 $scope = "this or a previous session";
1086 # it might be nice to have a section for previous session and
1089 $scope = "this session";
1096 map { sprintf "%5d %-45s: %s %s\n", @$_ }
1097 sort { $a->[0] <=> $b->[0] } @failed;
1100 map { sprintf " %-45s: %s %s\n", @$_[1..3] }
1107 $CPAN::Frontend->myprint("Failed during $scope:\n$print");
1108 } elsif (!$only_id || !$silent) {
1109 $CPAN::Frontend->myprint("Nothing failed in $scope\n");
1113 # XXX intentionally undocumented because completely bogus, unportable,
1116 #-> sub CPAN::Shell::status ;
1119 require Devel::Size;
1120 my $ps = FileHandle->new;
1121 open $ps, "/proc/$$/status";
1124 next unless /VmSize:\s+(\d+)/;
1128 $CPAN::Frontend->mywarn(sprintf(
1129 "%-27s %6d\n%-27s %6d\n",
1133 Devel::Size::total_size($CPAN::META)/1024,
1135 for my $k (sort keys %$CPAN::META) {
1136 next unless substr($k,0,4) eq "read";
1137 warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
1138 for my $k2 (sort keys %{$CPAN::META->{$k}}) {
1139 warn sprintf " %-25s %6d (keys: %6d)\n",
1141 Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
1142 scalar keys %{$CPAN::META->{$k}{$k2}};
1147 # compare with install_tested
1148 #-> sub CPAN::Shell::is_tested
1151 CPAN::Index->reload;
1152 for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
1154 if ($CPAN::META->{is_tested}{$b}) {
1155 $time = scalar(localtime $CPAN::META->{is_tested}{$b});
1157 $time = scalar localtime;
1160 $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b);
1164 #-> sub CPAN::Shell::autobundle ;
1167 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1168 my(@bundle) = $self->_u_r_common("a",@_);
1169 my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
1170 File::Path::mkpath($todir);
1171 unless (-d $todir) {
1172 $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
1175 my($y,$m,$d) = (localtime)[5,4,3];
1179 my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
1180 my($to) = File::Spec->catfile($todir,"$me.pm");
1182 $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
1183 $to = File::Spec->catfile($todir,"$me.pm");
1185 my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
1187 "package Bundle::$me;\n\n",
1188 "\$VERSION = '0.01';\n\n",
1192 "Bundle::$me - Snapshot of installation on ",
1193 $Config::Config{'myhostname'},
1196 "\n\n=head1 SYNOPSIS\n\n",
1197 "perl -MCPAN -e 'install Bundle::$me'\n\n",
1198 "=head1 CONTENTS\n\n",
1199 join("\n", @bundle),
1200 "\n\n=head1 CONFIGURATION\n\n",
1202 "\n\n=head1 AUTHOR\n\n",
1203 "This Bundle has been generated automatically ",
1204 "by the autobundle routine in CPAN.pm.\n",
1207 $CPAN::Frontend->myprint("\nWrote bundle file
1211 #-> sub CPAN::Shell::expandany ;
1214 CPAN->debug("s[$s]") if $CPAN::DEBUG;
1215 if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
1216 $s = CPAN::Distribution->normalize($s);
1217 return $CPAN::META->instance('CPAN::Distribution',$s);
1218 # Distributions spring into existence, not expand
1219 } elsif ($s =~ m|^Bundle::|) {
1220 $self->local_bundles; # scanning so late for bundles seems
1221 # both attractive and crumpy: always
1222 # current state but easy to forget
1224 return $self->expand('Bundle',$s);
1226 return $self->expand('Module',$s)
1227 if $CPAN::META->exists('CPAN::Module',$s);
1232 #-> sub CPAN::Shell::expand ;
1235 my($type,@args) = @_;
1236 CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
1237 my $class = "CPAN::$type";
1238 my $methods = ['id'];
1239 for my $meth (qw(name)) {
1240 next unless $class->can($meth);
1241 push @$methods, $meth;
1243 $self->expand_by_method($class,$methods,@args);
1246 #-> sub CPAN::Shell::expand_by_method ;
1247 sub expand_by_method {
1249 my($class,$methods,@args) = @_;
1252 my($regex,$command);
1253 if ($arg =~ m|^/(.*)/$|) {
1255 # FIXME: there seem to be some ='s in the author data, which trigger
1256 # a failure here. This needs to be contemplated.
1257 # } elsif ($arg =~ m/=/) {
1261 CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
1263 defined $regex ? $regex : "UNDEFINED",
1264 defined $command ? $command : "UNDEFINED",
1266 if (defined $regex) {
1267 if (CPAN::_sqlite_running()) {
1268 CPAN::Index->reload;
1269 $CPAN::SQLite->search($class, $regex);
1272 $CPAN::META->all_objects($class)
1274 unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) {
1275 # BUG, we got an empty object somewhere
1276 require Data::Dumper;
1277 CPAN->debug(sprintf(
1278 "Bug in CPAN: Empty id on obj[%s][%s]",
1280 Data::Dumper::Dumper($obj)
1284 for my $method (@$methods) {
1285 my $match = eval {$obj->$method() =~ /$regex/i};
1287 my($err) = $@ =~ /^(.+) at .+? line \d+\.$/;
1288 $err ||= $@; # if we were too restrictive above
1289 $CPAN::Frontend->mydie("$err\n");
1296 } elsif ($command) {
1297 die "equal sign in command disabled (immature interface), ".
1299 ! \$CPAN::Shell::ADVANCED_QUERY=1
1300 to enable it. But please note, this is HIGHLY EXPERIMENTAL code
1301 that may go away anytime.\n"
1302 unless $ADVANCED_QUERY;
1303 my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
1304 my($matchcrit) = $criterion =~ m/^~(.+)/;
1308 $CPAN::META->all_objects($class)
1310 my $lhs = $self->$method() or next; # () for 5.00503
1312 push @m, $self if $lhs =~ m/$matchcrit/;
1314 push @m, $self if $lhs eq $criterion;
1319 if ( $class eq 'CPAN::Bundle' ) {
1320 $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
1321 } elsif ($class eq "CPAN::Distribution") {
1322 $xarg = CPAN::Distribution->normalize($arg);
1326 if ($CPAN::META->exists($class,$xarg)) {
1327 $obj = $CPAN::META->instance($class,$xarg);
1328 } elsif ($CPAN::META->exists($class,$arg)) {
1329 $obj = $CPAN::META->instance($class,$arg);
1336 @m = sort {$a->id cmp $b->id} @m;
1337 if ( $CPAN::DEBUG ) {
1338 my $wantarray = wantarray;
1339 my $join_m = join ",", map {$_->id} @m;
1340 # $self->debug("wantarray[$wantarray]join_m[$join_m]");
1341 my $count = scalar @m;
1342 $self->debug("class[$class]wantarray[$wantarray]count m[$count]");
1344 return wantarray ? @m : $m[0];
1347 #-> sub CPAN::Shell::format_result ;
1350 my($type,@args) = @_;
1351 @args = '/./' unless @args;
1352 my(@result) = $self->expand($type,@args);
1353 my $result = @result == 1 ?
1354 $result[0]->as_string :
1356 "No objects of type $type found for argument @args\n" :
1358 (map {$_->as_glimpse} @result),
1359 scalar @result, " items found\n",
1364 #-> sub CPAN::Shell::report_fh ;
1366 my $installation_report_fh;
1367 my $previously_noticed = 0;
1370 return $installation_report_fh if $installation_report_fh;
1371 if ($CPAN::META->has_usable("File::Temp")) {
1372 $installation_report_fh
1374 dir => File::Spec->tmpdir,
1375 template => 'cpan_install_XXXX',
1380 unless ( $installation_report_fh ) {
1381 warn("Couldn't open installation report file; " .
1382 "no report file will be generated."
1383 ) unless $previously_noticed++;
1389 # The only reason for this method is currently to have a reliable
1390 # debugging utility that reveals which output is going through which
1391 # channel. No, I don't like the colors ;-)
1393 # to turn colordebugging on, write
1394 # cpan> o conf colorize_output 1
1396 #-> sub CPAN::Shell::colorize_output ;
1398 my $print_ornamented_have_warned = 0;
1399 sub colorize_output {
1400 my $colorize_output = $CPAN::Config->{colorize_output};
1401 if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
1402 unless ($print_ornamented_have_warned++) {
1403 # no myprint/mywarn within myprint/mywarn!
1404 warn "Colorize_output is set to true but Term::ANSIColor is not
1405 installed. To activate colorized output, please install Term::ANSIColor.\n\n";
1407 $colorize_output = 0;
1409 return $colorize_output;
1414 #-> sub CPAN::Shell::print_ornamented ;
1415 sub print_ornamented {
1416 my($self,$what,$ornament) = @_;
1417 return unless defined $what;
1419 local $| = 1; # Flush immediately
1420 if ( $CPAN::Be_Silent ) {
1421 print {report_fh()} $what;
1424 my $swhat = "$what"; # stringify if it is an object
1425 if ($CPAN::Config->{term_is_latin}) {
1426 # note: deprecated, need to switch to $LANG and $LC_*
1429 =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
1431 if ($self->colorize_output) {
1432 if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) {
1433 # if you want to have this configurable, please file a bugreport
1434 $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan";
1436 my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
1438 print "Term::ANSIColor rejects color[$ornament]: $@\n
1439 Please choose a different color (Hint: try 'o conf init /color/')\n";
1441 # GGOLDBACH/Test-GreaterVersion-0.008 broke without this
1442 # $trailer construct. We want the newline be the last thing if
1443 # there is a newline at the end ensuring that the next line is
1444 # empty for other players
1446 $trailer = $1 if $swhat =~ s/([\r\n]+)\z//;
1449 Term::ANSIColor::color("reset"),
1456 #-> sub CPAN::Shell::myprint ;
1458 # where is myprint/mywarn/Frontend/etc. documented? Where to use what?
1459 # I think, we send everything to STDOUT and use print for normal/good
1460 # news and warn for news that need more attention. Yes, this is our
1461 # working contract for now.
1463 my($self,$what) = @_;
1464 $self->print_ornamented($what,
1465 $CPAN::Config->{colorize_print}||'bold blue on_white',
1470 my($self,$category,$what) = @_;
1471 my $vname = $category . "_verbosity";
1472 CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
1473 if (!$CPAN::Config->{$vname}
1474 || $CPAN::Config->{$vname} =~ /^v/
1476 $CPAN::Frontend->myprint($what);
1480 #-> sub CPAN::Shell::myexit ;
1482 my($self,$what) = @_;
1483 $self->myprint($what);
1487 #-> sub CPAN::Shell::mywarn ;
1489 my($self,$what) = @_;
1490 $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
1493 # only to be used for shell commands
1494 #-> sub CPAN::Shell::mydie ;
1496 my($self,$what) = @_;
1497 $self->mywarn($what);
1499 # If it is the shell, we want the following die to be silent,
1500 # but if it is not the shell, we would need a 'die $what'. We need
1501 # to take care that only shell commands use mydie. Is this
1507 # sub CPAN::Shell::colorable_makemaker_prompt ;
1508 sub colorable_makemaker_prompt {
1510 if (CPAN::Shell->colorize_output) {
1511 my $ornament = $CPAN::Config->{colorize_print}||'bold blue on_white';
1512 my $color_on = eval { Term::ANSIColor::color($ornament); } || "";
1515 my $ans = ExtUtils::MakeMaker::prompt($foo,$bar);
1516 if (CPAN::Shell->colorize_output) {
1517 print Term::ANSIColor::color('reset');
1522 # use this only for unrecoverable errors!
1523 #-> sub CPAN::Shell::unrecoverable_error ;
1524 sub unrecoverable_error {
1525 my($self,$what) = @_;
1526 my @lines = split /\n/, $what;
1528 for my $l (@lines) {
1529 $longest = length $l if length $l > $longest;
1531 $longest = 62 if $longest > 62;
1532 for my $l (@lines) {
1533 if ($l =~ /^\s*$/) {
1538 if (length $l < 66) {
1539 $l = pack "A66 A*", $l, "<==";
1543 unshift @lines, "\n";
1544 $self->mydie(join "", @lines);
1547 #-> sub CPAN::Shell::mysleep ;
1549 my($self, $sleep) = @_;
1550 if (CPAN->has_inst("Time::HiRes")) {
1551 Time::HiRes::sleep($sleep);
1553 sleep($sleep < 1 ? 1 : int($sleep + 0.5));
1557 #-> sub CPAN::Shell::setup_output ;
1559 return if -t STDOUT;
1560 my $odef = select STDERR;
1567 #-> sub CPAN::Shell::rematein ;
1568 # RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here
1571 my($meth,@some) = @_;
1573 while($meth =~ /^(ff?orce|notest)$/) {
1574 push @pragma, $meth;
1575 $meth = shift @some or
1576 $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
1580 CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;
1582 # Here is the place to set "test_count" on all involved parties to
1583 # 0. We then can pass this counter on to the involved
1584 # distributions and those can refuse to test if test_count > X. In
1585 # the first stab at it we could use a 1 for "X".
1587 # But when do I reset the distributions to start with 0 again?
1588 # Jost suggested to have a random or cycling interaction ID that
1589 # we pass through. But the ID is something that is just left lying
1590 # around in addition to the counter, so I'd prefer to set the
1591 # counter to 0 now, and repeat at the end of the loop. But what
1592 # about dependencies? They appear later and are not reset, they
1593 # enter the queue but not its copy. How do they get a sensible
1596 # With configure_requires, "get" is vulnerable in recursion.
1598 my $needs_recursion_protection = "get|make|test|install";
1600 # construct the queue
1602 STHING: foreach $s (@some) {
1605 CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
1607 } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
1608 } elsif ($s =~ m|^/|) { # looks like a regexp
1609 if (substr($s,-1,1) eq ".") {
1610 $obj = CPAN::Shell->expandany($s);
1612 $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
1613 "not supported.\nRejecting argument '$s'\n");
1614 $CPAN::Frontend->mysleep(2);
1617 } elsif ($meth eq "ls") {
1618 $self->globls($s,\@pragma);
1621 CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
1622 $obj = CPAN::Shell->expandany($s);
1625 } elsif (ref $obj) {
1626 if ($meth =~ /^($needs_recursion_protection)$/) {
1627 # it would be silly to check for recursion for look or dump
1628 # (we are in CPAN::Shell::rematein)
1629 CPAN->debug("Going to test against recursion") if $CPAN::DEBUG;
1630 eval { $obj->color_cmd_tmps(0,1); };
1633 and $@->isa("CPAN::Exception::RecursiveDependency")) {
1634 $CPAN::Frontend->mywarn($@);
1638 Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@);
1644 CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c");
1646 } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
1647 $obj = $CPAN::META->instance('CPAN::Author',uc($s));
1648 if ($meth =~ /^(dump|ls|reports)$/) {
1651 $CPAN::Frontend->mywarn(
1653 "Don't be silly, you can't $meth ",
1657 $CPAN::Frontend->mysleep(2);
1659 } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") {
1660 CPAN::InfoObj->dump($s);
1663 ->mywarn(qq{Warning: Cannot $meth $s, }.
1664 qq{don't know what it is.
1669 to find objects with matching identifiers.
1671 $CPAN::Frontend->mysleep(2);
1675 # queuerunner (please be warned: when I started to change the
1676 # queue to hold objects instead of names, I made one or two
1677 # mistakes and never found which. I reverted back instead)
1678 QITEM: while (my $q = CPAN::Queue->first) {
1680 my $s = $q->as_string;
1681 my $reqtype = $q->reqtype || "";
1682 $obj = CPAN::Shell->expandany($s);
1684 # don't know how this can happen, maybe we should panic,
1685 # but maybe we get a solution from the first user who hits
1686 # this unfortunate exception?
1687 $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
1688 "to an object. Skipping.\n");
1689 $CPAN::Frontend->mysleep(5);
1690 CPAN::Queue->delete_first($s);
1693 $obj->{reqtype} ||= "";
1695 # force debugging because CPAN::SQLite somehow delivers us
1698 # local $CPAN::DEBUG = 1024; # Shell; probably fixed now
1700 CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]".
1701 "q-reqtype[$reqtype]") if $CPAN::DEBUG;
1703 if ($obj->{reqtype}) {
1704 if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) {
1705 $obj->{reqtype} = $reqtype;
1707 exists $obj->{install}
1710 UNIVERSAL::can($obj->{install},"failed") ?
1711 $obj->{install}->failed :
1712 $obj->{install} =~ /^NO/
1715 delete $obj->{install};
1716 $CPAN::Frontend->mywarn
1717 ("Promoting $obj->{ID} from 'build_requires' to 'requires'");
1721 $obj->{reqtype} = $reqtype;
1724 for my $pragma (@pragma) {
1727 $obj->can($pragma)) {
1728 $obj->$pragma($meth);
1731 if (UNIVERSAL::can($obj, 'called_for')) {
1732 $obj->called_for($s);
1734 CPAN->debug(qq{pragma[@pragma]meth[$meth]}.
1735 qq{ID[$obj->{ID}]}) if $CPAN::DEBUG;
1738 if ($meth =~ /^(report)$/) { # they came here with a pragma?
1740 } elsif (! UNIVERSAL::can($obj,$meth)) {
1742 my $serialized = "";
1744 } elsif ($CPAN::META->has_inst("YAML::Syck")) {
1745 $serialized = YAML::Syck::Dump($obj);
1746 } elsif ($CPAN::META->has_inst("YAML")) {
1747 $serialized = YAML::Dump($obj);
1748 } elsif ($CPAN::META->has_inst("Data::Dumper")) {
1749 $serialized = Data::Dumper::Dumper($obj);
1752 $serialized = overload::StrVal($obj);
1754 CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
1755 $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
1756 } elsif ($obj->$meth()) {
1757 CPAN::Queue->delete($s);
1758 CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG;
1760 CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG;
1764 for my $pragma (@pragma) {
1765 my $unpragma = "un$pragma";
1766 if ($obj->can($unpragma)) {
1770 if ($CPAN::Config->{halt_on_failure}
1772 CPAN::Distrostatus::something_has_just_failed()
1774 $CPAN::Frontend->mywarn("Stopping: '$meth' failed for '$s'.\n");
1775 CPAN::Queue->nullify_queue;
1778 CPAN::Queue->delete_first($s);
1780 if ($meth =~ /^($needs_recursion_protection)$/) {
1781 for my $obj (@qcopy) {
1782 $obj->color_cmd_tmps(0,0);
1787 #-> sub CPAN::Shell::recent ;
1790 if ($CPAN::META->has_inst("XML::LibXML")) {
1791 my $url = $CPAN::Defaultrecent;
1792 $CPAN::Frontend->myprint("Going to fetch '$url'\n");
1793 unless ($CPAN::META->has_usable("LWP")) {
1794 $CPAN::Frontend->mydie("LWP not installed; cannot continue");
1796 CPAN::LWP::UserAgent->config;
1798 eval { $Ua = CPAN::LWP::UserAgent->new; };
1800 $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
1802 my $resp = $Ua->get($url);
1803 unless ($resp->is_success) {
1804 $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
1806 $CPAN::Frontend->myprint("DONE\n\n");
1807 my $xml = XML::LibXML->new->parse_string($resp->content);
1809 my $s = $xml->serialize(2);
1810 $s =~ s/\n\s*\n/\n/g;
1811 $CPAN::Frontend->myprint($s);
1815 if ($url =~ /winnipeg/) {
1816 my $pubdate = $xml->findvalue("/rss/channel/pubDate");
1817 $CPAN::Frontend->myprint(" pubDate: $pubdate\n\n");
1818 for my $eitem ($xml->findnodes("/rss/channel/item")) {
1819 my $distro = $eitem->findvalue("enclosure/\@url");
1820 $distro =~ s|.*?/authors/id/./../||;
1821 my $size = $eitem->findvalue("enclosure/\@length");
1822 my $desc = $eitem->findvalue("description");
1823 $desc =~ s/.+? - //;
1824 $CPAN::Frontend->myprint("$distro [$size b]\n $desc\n");
1825 push @distros, $distro;
1827 } elsif ($url =~ /search.*uploads.rdf/) {
1828 # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
1829 # xmlns="http://purl.org/rss/1.0/"
1830 # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
1831 # xmlns:dc="http://purl.org/dc/elements/1.1/"
1832 # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
1833 # xmlns:admin="http://webns.net/mvcb/"
1836 my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']");
1837 $CPAN::Frontend->myprint(" dc:date: $dc_date\n\n");
1838 my $finish_eitem = 0;
1839 local $SIG{INT} = sub { $finish_eitem = 1 };
1840 EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) {
1841 my $distro = $eitem->findvalue("\@rdf:about");
1842 $distro =~ s|.*~||; # remove up to the tilde before the name
1843 $distro =~ s|/$||; # remove trailing slash
1844 $distro =~ s|([^/]+)|\U$1\E|; # upcase the name
1845 my $author = uc $1 or die "distro[$distro] without author, cannot continue";
1846 my $desc = $eitem->findvalue("*[local-name(.) = 'description']");
1848 SUBDIRTEST: while () {
1849 last SUBDIRTEST if ++$i >= 6; # half a dozen must do!
1850 if (my @ret = $self->globls("$distro*")) {
1851 @ret = grep {$_->[2] !~ /meta/} @ret;
1852 @ret = grep {length $_->[2]} @ret;
1854 $distro = "$author/$ret[0][2]";
1858 $distro =~ s|/|/*/|; # allow it to reside in a subdirectory
1861 next EITEM if $distro =~ m|\*|; # did not find the thing
1862 $CPAN::Frontend->myprint("____$desc\n");
1863 push @distros, $distro;
1864 last EITEM if $finish_eitem;
1869 # deprecated old version
1870 $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n");
1874 #-> sub CPAN::Shell::smoke ;
1877 my $distros = $self->recent;
1878 DISTRO: for my $distro (@$distros) {
1879 next if $distro =~ m|/Bundle-|; # XXX crude heuristic to skip bundles
1880 $CPAN::Frontend->myprint(sprintf "Going to download and test '$distro'\n");
1883 local $SIG{INT} = sub { $skip = 1 };
1885 $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_);
1888 $CPAN::Frontend->myprint(" skipped\n");
1893 $CPAN::Frontend->myprint("\r \n"); # leave the dirty line with a newline
1894 $self->test($distro);
1899 # set up the dispatching methods
1901 for my $command (qw(
1918 *$command = sub { shift->rematein($command, @_); };