File Coverage

blib/lib/CPAN/Dependency.pm
Criterion Covered Total %
statement 94 226 41.5
branch 17 96 17.7
condition 7 57 12.2
subroutine 23 30 76.6
pod 13 13 100.0
total 154 422 36.4


line stmt bran cond sub pod time code
1             package CPAN::Dependency;
2 9     9   635047 use strict;
  9         25  
  9         385  
3 9     9   47 use warnings;
  9         18  
  9         245  
4 9     9   58 use Carp;
  9         23  
  9         937  
5 9     9   9172 use CPANPLUS::Backend;
  9         9541046  
  9         309  
6 9     9   94 use Cwd;
  9         18  
  9         581  
7 9     9   42 use Exporter ();
  9         17  
  9         127  
8 9     9   44 use File::Spec;
  9         15  
  9         265  
9 9     9   297670 use File::Slurp;
  9         50825  
  9         769  
10 9     9   29958 use Module::CoreList;
  9         434145  
  9         171  
11 9     9   13887 use YAML qw(LoadFile DumpFile);
  9         60989  
  9         697  
12              
13 9     9   76 use constant ALL_CPAN => 'all CPAN modules';
  9         19  
  9         459  
14              
15 9     9   46 { no strict;
  9         19  
  9         3665  
16             $VERSION = '0.16';
17             @ISA = qw(Exporter);
18             @EXPORT = qw(ALL_CPAN);
19             }
20              
21             my($RESET,$BOLD,$RED,$GREEN,$YELLOW);
22              
23             =head1 NAME
24              
25             CPAN::Dependency - Analyzes CPAN modules and generates their dependency tree
26              
27             =head1 VERSION
28              
29             Version 0.16
30              
31             =head1 SYNOPSIS
32              
33             Find and print the 10 most required CPAN distributions by
34             stand-alone processing.
35              
36             use CPAN::Dependency;
37              
38             my $cpandep = CPAN::Dependency->new(process => ALL_CPAN);
39             $cpandep->run; # this may take some time..
40             $cpandep->calculate_score;
41              
42             my %score = $cpandep->score_by_dists;
43             my @dists = sort { $score{$b} <=> $score{$a} } keys %score;
44             print "Top 10 modules\n";
45             for my $dist (@dists[0..9]) {
46             printf "%5d %s\n", $score{$dist}, $dist;
47             }
48              
49             Same thing, but this time by loading the prerequisites information
50             from the CPANTS database.
51              
52             use CPAN::Dependency;
53             my $cpandep = new CPAN::Dependency;
54             $cpandep->load_cpants_db(file => 'cpants.db');
55             $cpandep->calculate_score;
56              
57             my %score = $cpandep->score_by_dists;
58             my @dists = sort { $score{$b} <=> $score{$a} } keys %score;
59             print "Top 10 modules\n";
60             for my $dist (@dists[0..9]) {
61             printf "%5d %s\n", $score{$dist}, $dist;
62             }
63              
64              
65             =head1 DESCRIPTION
66              
67             I
68             Check L<"See ALSO"> for similar, more recent modules.>
69              
70             This module can process a set of distributions, up to the whole CPAN,
71             and extract the dependency relations between these distributions.
72             Alternatively, it can load the prerequisites information from a
73             CPANTS database.
74              
75             It also calculates a score for each distribution based on the number
76             of times it appears in the prerequisites of other distributions.
77             The algorithm is described in more details in L<"SCORE CALCULATION">.
78              
79             C stores the data in an internal structure which can
80             be saved and loaded using C and C.
81             The structure looks like this:
82              
83             DEPS_TREE = {
84             DIST => {
85             author => STRING,
86             cpanid => STRING,
87             score => NUMBER,
88             prereqs => {
89             DIST => BOOLEAN,
90             ...
91             },
92             used_by => {
93             DIST => BOOLEAN,
94             ...
95             },
96             },
97             ....
98             }
99              
100             With each distribution name I are associated the following fields:
101              
102             =over 4
103              
104             =item *
105              
106             C is a string which contains the name of the author who wrote
107             (or last released) this distribution;
108              
109             =item *
110              
111             C is a string which contains the CPAN ID of the author who wrote
112             (or last released) this distribution;
113              
114             =item *
115              
116             C is a number which represents the score of the distribution;
117              
118             =item *
119              
120             C is a hashref which represents the prerequisites of the distribution;
121             each key is a prerequisite name and its value is a boolean which is true when
122             the distribution and the prerequisite are not from the same author;
123              
124             =item *
125              
126             C is a hashref which represents the distributions which use this
127             particular distribution; each key is a distribution name and its value is a
128             boolean which is true when both distributions are not from the same author;
129              
130             =back
131              
132             =head1 METHODS
133              
134             =over 4
135              
136             =item new()
137              
138             Creates and returns a new object.
139              
140             B
141              
142             =over 4
143              
144             =item *
145              
146             C - adds modules or distributions to the list of packages to process.
147              
148             =item *
149              
150             C - adds modules or distributions you don't want to process.
151              
152             =item *
153              
154             C - control whether to delete the CPANPLUS directory
155             during the process or not.
156              
157             =item *
158              
159             C - use colors (when C is also set).
160              
161             =item *
162              
163             C - sets debug level.
164              
165             =item *
166              
167             C - tells CPANPLUS to prefer binaries programs.
168              
169             =item *
170              
171             C - sets the verbose mode.
172              
173             =back
174              
175             B
176              
177             Creates a new C object with verbose mode enabled
178             and adds a few "big" modules to the process list:
179              
180             my $cpandep = new CPAN::Dependency verbose => 1,
181             process => [qw(WWW::Mechanize Maypole Template CPAN::Search::Lite)]
182              
183             Creates a new C object with verbose mode enabled
184             and adds all the distributions from the CPAN to the process list:
185              
186             my $cpandep = new CPAN::Dependency verbose => 1, process => ALL_CPAN;
187              
188             =cut
189              
190             sub new {
191 7     7 1 20892 my $self = {
192             backend => 0, # CPANPLUS::Backend object
193            
194             options => { # options
195             clean_build_dir => 0, # - delete CPANPLUS build directory ?
196             color => 0, # - use ANSI colors?
197             debug => 0, # - debug level
198             prefer_bin => 0, # - prefer binaries?
199             verbose => 0, # - verbose?
200             },
201            
202             process => [ ], # modules/distributions to process
203            
204             prereqs => { }, # distributions dependencies
205            
206             skip => { # distributions to skip (during processing)
207             'perl' => 1,
208             'parrot' => 1,
209             'ponie' => 1,
210             },
211            
212             ignore => { # distributions to ignore (during dependencies calculations)
213             'perl' => 1,
214             'parrot' => 1,
215             'ponie' => 1,
216             },
217             };
218 7   33     54 my $class = ref $_[0] || $_[0]; shift;
  7         18  
219 7         24 bless $self, $class;
220              
221 7         77 $self->{backend} = new CPANPLUS::Backend;
222 7 50       480007 croak "fatal: Can't create CPANPLUS::Backend object"
223             unless defined $self->{backend};
224 7         74 my $cpan = $self->{backend};
225 7         90 my $conf = $cpan->configure_object;
226              
227 7         240 $self->verbose(0);
228 7         49 $self->debug(0);
229 7         87 $self->color(1);
230              
231 7         94 $self->{build_dir} = File::Spec->catdir($conf->get_conf('base'),
232             $cpan->_perl_version(perl => $^X), $conf->_get_build('moddir'));
233            
234 7         4034 my %args = @_;
235              
236             # treat arguments for which an accessor exists
237 7         39 for my $attr (keys %args) {
238 12 100 33     118 defined($self->$attr($args{$attr})) and delete $args{$attr} if $self->can($attr);
239             }
240              
241             # treat remaining arguments
242 7         26 for my $attr (keys %args) {
243 1         36 carp "warning: Unknown option '$attr': ignoring"
244             }
245              
246 7         630 return $self
247             }
248              
249             #
250             # generate accessors for all existing attributes
251             #
252 9     9   53 { no strict 'refs';
  9         19  
  9         32635  
253             for my $attr (qw(clean_build_dir verbose)) {
254             *{__PACKAGE__.'::'.$attr} = sub {
255 15     15   4998 my $self = shift;
256 15         56 my $value = $self->{options}{$attr};
257 15 50       119 $self->{options}{$attr} = shift if @_;
258 15         164 return $value
259             }
260             }
261             }
262              
263              
264             =item process()
265              
266             Adds given distribution or module names to the list of packages to process.
267             The special argument C can be used to specify that you want to
268             process all packages in the CPAN.
269              
270             B
271              
272             Add distributions and modules to the process list, passing as a list:
273              
274             $cpandep->process('WWW::Mechanize', 'Maypole', 'CPAN-Search-Lite');
275              
276             Add distributions and modules to the process list, passing as an arrayref:
277              
278             $cpandep->process(['WWW-Mechanize', 'Maypole::Application', 'CPAN::Search::Lite']);
279              
280             =cut
281              
282             sub process {
283 1     1 1 1594 my $self = shift;
284 1 50 50     11 carp "error: No argument given to attribute process()" and return unless @_;
285 0 0       0 if($_[0] eq ALL_CPAN) {
286 0         0 push @{ $self->{process} }, sort keys %{ $self->{backend}->module_tree }
  0         0  
  0         0  
287             } else {
288 0 0       0 push @{ $self->{process} }, ref $_[0] ? @{$_[0]} : @_
  0         0  
  0         0  
289             }
290             }
291              
292              
293             =item skip()
294              
295             Adds given distribution or module names to the list of packages that you
296             I to process.
297              
298             B
299              
300             Add distributions and modules to the skip list, passing as a list:
301              
302             $cpandep->skip('LWP::UserAgent', 'Net_SSLeay.pm', 'CGI');
303              
304             Add distributions and modules to the skip list, passing as an arrayref:
305              
306             $cpandep->skip(['libwww-perl', 'Net::SSLeay', 'CGI.pm']);
307              
308             =cut
309              
310             sub skip {
311 4     4 1 2223 my $self = shift;
312 4 100 50     27 carp "error: No argument given to attribute skip()" and return unless @_;
313 3 100       24 my @packages = ref $_[0] ? @{$_[0]} : @_;
  2         12  
314 3         11 for my $package (@packages) {
315 8         55 my $dist = $self->{backend}->parse_module(module => $package)->package_name;
316 8         3115158 $self->{skip}{$dist} = 1;
317             }
318             }
319              
320              
321             =item run()
322              
323             Launches the execution of the C object.
324              
325             =cut
326              
327             sub run {
328 0     0 1 0 my $self = shift;
329 0         0 my $cpan = $self->{backend};
330              
331 0         0 my @dists = @{ $self->{process} };
  0         0  
332              
333 0         0 my($archive,$where) = ();
334              
335 0         0 for my $name (@dists) {
336 0         0 my $dist = $cpan->parse_module(module => $name);
337 0         0 my $dist_name = $dist->package_name;
338            
339 0         0 $self->_vprint($name);
340 0 0 0     0 $self->_vprint(" >> ${YELLOW}skip: already processed$RESET\n") and
      0        
341             next if not defined $dist or $self->{skip}{$dist_name}++;
342            
343 0 0 0     0 $self->_vprint(" >> ${YELLOW}skip: is a bundle$RESET\n") and
344             next if $dist->is_bundle;
345            
346 0         0 $self->_vprintf(" => $BOLD%s$RESET %s by %s (%s)\n", $dist_name,
347             $dist->package_version, $dist->author->cpanid, $dist->author->author);
348            
349 0         0 $archive = $where = '';
350            
351             # fetch and extract the distribution
352 0         0 eval {
353 0 0       0 $archive = $dist->fetch(force => 1) or next;
354 0 0       0 $where = $dist->extract(force => 1) or next;
355             };
356 0 0 0     0 $self->_vprint(" >> $BOLD${RED}CPANPLUS error: $@$RESET\n") and next if $@;
357              
358             # find its dependencies (that's the harder part)
359 0         0 my $deps = undef;
360            
361             # if there's a META.yml, we've won
362             # argh! this is no longer true! distributions like SVK include a META.yml
363             # with no prereqs :(
364 0 0       0 if(-f File::Spec->catfile($where, 'META.yml')) {
365 0         0 eval {
366 0         0 $deps = LoadFile(File::Spec->catfile($where, 'META.yml'));
367 0         0 $deps = $deps->{requires};
368             };
369 0 0       0 $self->_vprint(" >> $BOLD${RED}YAML error: $@$RESET\n") if $@;
370             }
371            
372             # if not, we must try harder
373 0 0 0     0 unless(defined $deps and ref $deps eq 'HASH' and keys %$deps) {
      0        
374 0         0 $self->_vprint(" >> $BOLD${YELLOW}no META.yml; using parsing method$RESET\n");
375              
376             # distribution uses Makefile.PL
377 0 0       0 if(-f File::Spec->catfile($where, 'Makefile.PL')) {
    0          
378 0         0 my $builder = read_file( File::Spec->catfile($where, 'Makefile.PL') );
379 0         0 $builder =~ /
380             (?: PREREQ_PM.*?=>.*?\{(.*?)\} )| # ExtUtils::MakeMaker
381             (?: requires\(([^)]*)\)) # Module::Install
382             /sx;
383 0   0     0 my $requires = $1 || $2;
384 0 0       0 if(not defined $requires) {
385 0         0 $self->_vprint(" >> $BOLD${YELLOW}don't know how to figure out prereqs from Makefile.PL for $where$RESET\n");
386             } else {
387 0         0 eval "{ no strict; \$deps = { $requires \n} }";
388             }
389              
390             # distribution uses Build.PL
391             } elsif(-f File::Spec->catfile($where, 'Build.PL')) {
392 0         0 my $builder = read_file( File::Spec->catfile($where, 'Build.PL') );
393 0         0 my($requires) = $builder =~ /requires.*?=>.*?\{(.*?)\}/s;
394 0         0 eval "{ no strict; \$deps = { $requires \n} }";
395            
396             } else {
397 0         0 $self->_vprint(" >> $BOLD${RED}error: no Makefile.PL or Build.PL found$RESET\n");
398             next
399 0         0 }
400             }
401              
402 0   0     0 $deps ||= {};
403 0         0 my %deps = ();
404            
405 0         0 $self->_vprint(" \e[1;32mprereqs: ", join(', ', sort keys %$deps), "\e[0m\n");
406            
407             # $deps contains module names, but we really want distribution names
408             # %deps will have the following structure:
409             #
410             # %deps = (
411             # DIST_NAME => {
412             # PREREQ_DIST_1 => COUNT,
413             # PREREQ_DIST_2 => COUNT,
414             # ...
415             # }
416             # )
417             #
418             # where COUNT is 0 when PREREQ_DIST_x and DIST_NAME have the same
419             # author, 1 otherwise.
420             #
421 0         0 for my $reqmod (keys %$deps) {
422 0         0 $reqmod =~ s/^\s+//g; $reqmod =~ s/\s+$//g;
  0         0  
423              
424 0 0 0     0 $self->_vprint(" >> $BOLD${YELLOW}ignoring prereq $reqmod$RESET\n")
425             and next if $self->{ignore}{$reqmod};
426              
427 0 0 0     0 $self->_vprint(" >> $BOLD${YELLOW}$reqmod is in Perl core$RESET\n")
428             and next if Module::CoreList->first_release($reqmod);
429            
430 0         0 my $reqdist = eval { $cpan->parse_module(module => $reqmod) };
  0         0  
431 0 0 0     0 $self->_vprint(" >> $BOLD${RED}error: no dist found for $reqmod$RESET\n")
      0        
432             and $deps{$reqmod} = 1 and next unless defined $reqdist;
433            
434 0 0 0     0 $self->_vprint(" >> $BOLD${YELLOW}$reqmod is in Perl core$RESET\n")
435             and next if $reqdist->package_is_perl_core;
436            
437 0 0       0 $deps{$reqdist->package_name} =
438             $reqdist->author->cpanid ne $dist->author->cpanid ? 1 : 0;
439             }
440            
441 0         0 $self->{prereqs}{$dist_name} = {
442             prereqs => { %deps },
443             used_by => { },
444             score => 0,
445             cpanid => $dist->author->cpanid,
446             author => $dist->author->author,
447             };
448            
449             } continue {
450             # clean up
451 0         0 eval {
452 0 0 0     0 $cpan->_rmdir(dir => $where) if defined $where and -d $where;
453 0 0       0 $cpan->_rmdir(dir => $self->{build_dir}) if $self->{options}{clean_build_dir};
454 0 0       0 $cpan->_mkdir(dir => $self->{build_dir}) if $self->{options}{clean_build_dir};
455             }
456             }
457              
458 0         0 $self->_vprint("${BOLD}END PROCESSING$RESET\n");
459             }
460              
461              
462             =item calculate_score()
463              
464             Calculate the score of each distribution by walking through the
465             dependency tree.
466              
467             =cut
468              
469             sub calculate_score {
470 0     0 1 0 my $self = shift;
471            
472             # now walk through the prereqs tree
473 0         0 for my $dist (keys %{$self->{prereqs}}) {
  0         0  
474 0         0 $self->_tree_walk($dist, 1);
475             }
476             }
477              
478              
479             =item deps_by_dists()
480              
481             Return the hashref of the object that contains the dependency tree indexed
482             by distribution names.
483              
484             =cut
485              
486             sub deps_by_dists {
487 0     0 1 0 return $_[0]->{prereqs}
488             }
489              
490              
491             =item score_by_dists()
492              
493             Returns a new hash that contains the score of the processed distributions,
494             indexed by the distribution names.
495              
496             =cut
497              
498             sub score_by_dists {
499 0     0 1 0 my $self = shift;
500 0         0 return map { $_ => $self->{prereqs}{$_}{score} } keys %{$self->{prereqs}};
  0         0  
  0         0  
501             }
502              
503              
504             =item save_deps_tree()
505              
506             Saves the dependency tree of the object to a YAML stream.
507             Expect one of the following options.
508              
509             B
510              
511             =over 4
512              
513             =item *
514              
515             C - saves to the given YAML file.
516              
517             =back
518              
519             B
520              
521             $cpandep->save_deps_tree(file => 'deps.yml');
522              
523             =cut
524              
525             sub save_deps_tree {
526 1     1 1 692 my $self = shift;
527 1 50 50     12 carp "error: No argument given to function save_deps_tree()" and return unless @_;
528 0         0 my %args = @_;
529 0 0       0 if(exists $args{file}) {
530 0 0       0 unlink($args{file}) if -f $args{file};
531 0         0 DumpFile($args{file}, $self->{prereqs});
532             }
533             }
534              
535              
536             =item load_deps_tree()
537              
538             Loads a YAML stream that contains a dependency tree into the current object.
539             Expect one of the following options.
540              
541             B
542              
543             =over 4
544              
545             =item *
546              
547             C - loads from the given YAML file.
548              
549             =back
550              
551             B
552              
553             $cpandep->load_deps_tree(file => 'deps.yml');
554              
555             =cut
556              
557             sub load_deps_tree {
558 1     1 1 718 my $self = shift;
559 1 50 50     12 carp "error: No argument given to function load_deps_tree()" and return unless @_;
560 0         0 my %args = @_;
561 0 0       0 if(exists $args{file}) {
562 0         0 $self->{prereqs} = LoadFile($args{file});
563             }
564             }
565              
566              
567             =item load_cpants_db()
568              
569             B
570              
571             Loads the prerequisites information from the given CPANTS database.
572             Expects one of the following options.
573              
574             B
575              
576             =over 4
577              
578             =item *
579              
580             C - loads from the given file.
581              
582             =back
583              
584             B
585              
586             $cpandep->load_cpants_db(file => 'cpants.db');
587              
588             =cut
589              
590             sub load_cpants_db {
591 1     1 1 740 my $self = shift;
592 1 50 50     13 carp "error: No argument given to function load_cpants_db()" and return unless @_;
593 0         0 my %args = @_;
594 0         0 my $cpants_db = $args{file};
595 0 0       0 -f $cpants_db or croak "fatal: Can't find file '$cpants_db'";
596              
597 0         0 eval 'use DBI';
598              
599 0 0       0 my $dbh = DBI->connect("dbi:SQLite:dbname=$cpants_db", '', '')
600             or croak "fatal: Can't read SQLite database: $DBI::errstr";
601              
602 0         0 my $dists_sth = $dbh->prepare(q{
603             SELECT dist.id, dist.dist, author.pauseid, author.name
604             FROM dist, author
605             WHERE author.id=dist.author
606             });
607              
608 0         0 my $prereqs_sth = $dbh->prepare('SELECT requires FROM prereq WHERE dist=?');
609              
610 0         0 my $cpan = $self->{backend};
611 0         0 my @distinfo = ();
612 0         0 $dists_sth->execute;
613 0         0 while(@distinfo = $dists_sth->fetchrow_array) {
614 0         0 my $dist_cpan_info = undef;
615 0         0 eval { $dist_cpan_info = $cpan->parse_module(module => $distinfo[1]) };
  0         0  
616              
617 0         0 $prereqs_sth->execute($distinfo[0]);
618 0         0 my $prereqs = $prereqs_sth->fetchall_arrayref;
619 0         0 my @prereqs = ();
620 0         0 push @prereqs, map { @$_ } @$prereqs;
  0         0  
621              
622 0         0 my %deps = ();
623 0         0 for my $reqmod (@prereqs) {
624 0         0 $reqmod =~ s/^\s+//g; $reqmod =~ s/\s+$//g;
  0         0  
625 0 0       0 next if $self->{ignore}{$reqmod};
626 0 0       0 next if Module::CoreList->first_release($reqmod);
627 0         0 my $reqdist = eval { $cpan->parse_module(module => $reqmod) };
  0         0  
628 0 0       0 unless(defined $reqdist) { $deps{$reqmod} = 1; next }
  0         0  
  0         0  
629 0 0       0 next if $reqdist->package_is_perl_core;
630 0 0       0 $deps{$reqdist->package_name} = $reqdist->author->cpanid ne $distinfo[2] ? 1 : 0;
631             }
632              
633             $self->{prereqs}{$distinfo[1]} = {
634             prereqs => { %deps },
635             used_by => { },
636             score => 0,
637             cpanid => $distinfo[2] || eval { $dist_cpan_info->author->cpanid },
638 0   0     0 author => $distinfo[3] || eval { $dist_cpan_info->author->author },
      0        
639             };
640             }
641              
642 0         0 $dbh->disconnect;
643             }
644              
645             =back
646              
647              
648             =head2 Internal Methods
649              
650             =over 4
651              
652             =item _tree_walk()
653              
654             Walks through the dependency tree and updates the score of each distribution.
655             See L<"SCORE CALCULATION">.
656              
657             =cut
658              
659             sub _tree_walk {
660 0     0   0 my $self = shift;
661 0         0 my $dist = shift;
662 0         0 my $depth = shift;
663 0         0 my $meta = $self->{prereqs}{$dist};
664              
665             # avoid cycle dependencies
666 0 0       0 return if $meta->{has_seen};
667 0         0 local $meta->{has_seen} = 1;
668            
669             #print '>'x$depth, " $dist => @{[keys %{$meta->{prereqs}}]}\n";
670 0         0 for my $reqdist (keys %{ $meta->{prereqs} }) {
  0         0  
671             # are $dist and $reqdist from the same author?
672 0         0 my $same_author = $meta->{prereqs}{$reqdist};
673            
674             # increase the score of the dist this one depends upon
675 0         0 $self->{prereqs}{$reqdist}{score} += $depth * $same_author;
676            
677             # adds the current dist to the 'used_by' list of its prereq
678 0 0 0     0 $self->{prereqs}{$reqdist}{used_by}{$dist} =
679             ($self->{prereqs}{$reqdist}{cpanid}||'') ne $meta->{cpanid} ? 1 : 0;
680            
681             # recurse
682 0         0 $self->_tree_walk($reqdist, $depth + $same_author);
683             }
684              
685 0         0 delete $meta->{has_seen};
686             }
687              
688             =item _vprint()
689              
690             Like C but prints only when option C is set.
691              
692             =cut
693              
694             sub _vprint {
695 0     0   0 my $self = shift;
696 0 0       0 print @_ if $self->{options}{verbose};
697 0         0 return 1
698             }
699              
700             =item _vprintf()
701              
702             Like C but prints only when option C is set.
703              
704             =cut
705              
706             sub _vprintf {
707 0     0   0 my $self = shift;
708 0 0       0 printf @_ if $self->{options}{verbose};
709 0         0 return 1
710             }
711              
712             =back
713              
714              
715             =head1 OPTIONS
716              
717             =over 4
718              
719             =item clean_build_dir()
720              
721             Control whether to delete the CPANPLUS build directory during the
722             processing of the selected modules or not.
723             This is a quite aggressive method to clean up things, but it's needed
724             when processing the whole CPAN because some distributions are badly
725             made, and some may be just too big for a ramdisk.
726             Default to false (0).
727              
728             =item color()
729              
730             Selects whether to use ANSI colors or not when verbose is enabled.
731             Defaults to yes (1).
732              
733             =cut
734              
735             sub color {
736 11     11 1 951 my $self = shift;
737 11         42 my $old = $self->{options}{color};
738 11 50       51 if(defined $_[0]) {
739 11         28 $self->{options}{color} = $_[0];
740 11 100       153 ($RESET , $BOLD , $RED , $GREEN , $YELLOW) =
741             $self->{options}{color} ?
742             ("\e[0m", "\e[1m", "\e[31m", "\e[32m", "\e[33m") :
743             ('')x5
744             }
745 11         43 return $old
746             }
747              
748             =item debug()
749              
750             Set debug level. Defaults to 0.
751              
752             =cut
753              
754             sub debug {
755 11     11 1 1358 my $self = shift;
756 11         36 my $old = $self->{options}{debug};
757 11 50       54 if(defined $_[0]) {
758 11         37 $self->{options}{debug} = $_[0];
759 11         55 $self->{backend}->configure_object->set_conf(verbose => $_[0]);
760             }
761 11         3261 return $old
762             }
763              
764             =item prefer_bin()
765              
766             Tells CPANPLUS to use binary programs instead of Perl modules when
767             there is the choice (i.e. use B instead of C).
768              
769             =cut
770              
771             sub prefer_bin {
772 4     4 1 1097 my $self = shift;
773 4         18 my $old = $self->{options}{prefer_bin};
774 4 50       21 if(defined $_[0]) {
775 4         12 $self->{options}{prefer_bin} = $_[0];
776 4         21 $self->{backend}->configure_object->set_conf(prefer_bin => $_[0]);
777             }
778 4         929 return $old
779             }
780              
781             =item verbose()
782              
783             Sets verbose mode to on (1) or off (0). Defaults to off.
784              
785             =back
786              
787              
788             =head1 SCORE CALCULATION
789              
790             Once the prerequisites for each distribution have been found, the score
791             of each distribution is calculated using the following algorithm:
792              
793             =over 4
794              
795             =item 1
796              
797             for each distribution I
798              
799             =item 2
800              
801             S< >S< >for each prerequisite I

of this distribution

802              
803             =item 3
804              
805             S< >S< >S< >S< >if both I and I

are not made by the same author,

806             update the score of I

by adding it the current dependency depth

807              
808             =item 4
809              
810             S< >S< >S< >S< >recurse step 1 using I

811              
812             =back
813              
814             The aim of this algorithm is to increase the score of distributions
815             that are depended upon by many other distributions, while avoiding the
816             cases where one author releases a horde of modules which depend upon
817             each others.
818              
819              
820             =head1 PROCESSING NOTES
821              
822             C uses C when processing CPAN distributions,
823             which means that you need to configure CPANPLUS for the account that will
824             run the C based scripts. Simply execute the C
825             for this. If the account is not supposed to have access to the Internet,
826             use a mini-CPAN mirror. See also L<"Local mirror">.
827              
828              
829             =head1 SPEED TIPS
830              
831             Here are a few tips to speed up the processing when you want to process
832             many modules (or the whole CPAN).
833              
834             =head2 Local mirror
835              
836             If it's not the case yet, you should use C to create your own
837             mini-CPAN local mirror. Then you just need to configure C to
838             use your mini-CPAN instead of a network mirror. A mini-CPAN can also be
839             shared using a web server but if you want speed, you should keep one on
840             your local filesystem.
841              
842             Note that you can also add your own private distributions into your
843             mini-CPAN using C. This is useful if you want to
844             use C on modules that are not publicly shared on
845             the CPAN.
846              
847             For more information see L and L.
848              
849             =head2 Ramdisk
850              
851             If your system supports this feature (most modern systems do), you should
852             create a ramdisk and move the C build directory onto the ramdisk.
853             Here are the instructions for Linux. Other systems are left as an exercise
854             for the reader C<:-)>
855              
856             =head3 Ramdisk for Linux
857              
858             The following commands must be executed as root.
859             cpanplus is assumed to be the user that will executes this module.
860              
861             =over 4
862              
863             =item *
864              
865             Create a ramdisk of S<32 MB>:
866              
867             dd if=/dev/zero of=/dev/ram0 bs=1M count=32
868              
869             =item *
870              
871             Format it and creates an Ext2 filesystem:
872              
873             mke2fs -L ramdisk0 /dev/ram0
874              
875             =item *
876              
877             Now mount it:
878              
879             mkdir /mnt/ramdisk
880             mount /dev/ram0 /mnt/ramdisk/
881             mkdir /mnt/ramdisk/cpanplus
882             chown cpanplus /mnt/ramdisk/cpanplus/
883              
884             =item *
885              
886             Now, as the user cpanplus, move the build directory onto the ramdisk
887             and symlink it:
888              
889             mv .cpanplus/5.8.5 /mnt/ramdisk/cpanplus/
890             ln -s /mnt/ramdisk/cpanplus/5.8.5 .cpanplus/5.8.5
891              
892             =back
893              
894             Note that we are explicitly avoiding to move the whole F<.cpanplus/>
895             directory because it will grow really big during the processing:
896             some C cache files are already big, and the sub-directory
897             F will contain a copy of each processed archive. When processing
898             the whole CPAN, it means that you'll have here a complete copy of your
899             mini-CPAN, so be sure that you have enough disk space (or symlink
900             this directory as well to another volume when you have enough space).
901              
902             =head3 Ramdisk for Mac OS X
903              
904             Here is a small shell script that creates, format and mount a ramdisk
905             of S<64 MB>. Its size can be changed by changing the number of blocks,
906             where one block is S<512 bytes>. This is a version for OS X.5 and newer:
907              
908             #!/bin/sh
909             BLOCK=128000
910             diskutil erasevolume HFS+ "ramdisk" `hdiutil attach -nomount ram://$BLOCKS`
911              
912             and here is a version for OS X.4 and previous:
913              
914             #!/bin/sh
915             BLOCK=128000
916             dev=`hdid -nomount ram://$BLOCKS`
917             newfs_hfs -v RAMDisk $dev
918             mkdir /Volumes/RAMDisk
919             chmod 777 /Volumes/RAMDisk
920             mount -t hfs $dev /Volumes/RAMDisk
921              
922             Then follow the same instructions for moving the F directory
923             as given for Linux.
924              
925             =head3 Ramdisk for Solaris
926              
927             Beginning with Solaris 9 12/03, Solaris includes a C
928             command for managing ramdisks. Below are the links for the documentation
929             of that command.
930              
931             =over 4
932              
933             =item *
934              
935             Solaris 11:
936             C (L)
937              
938             =item *
939              
940             Solaris 10:
941             C (L)
942              
943             =item *
944              
945             Solaris 9 12/03:
946             C (L)
947              
948             =back
949              
950             Ramdisks can also be created in previous versions of Solaris using
951             a pseudo-device. Below are the links for the corresponding documentation.
952              
953             =over 4
954              
955             =item *
956              
957             Solaris 10:
958             C (L),
959             C (L)
960              
961             =item *
962              
963             Solaris 9:
964             C (L)
965              
966             =item *
967              
968             Solaris 8:
969             C (L)
970              
971             =item *
972              
973             Solaris 7:
974             C (L)
975              
976             =item *
977              
978             Solaris 2.6:
979             C (L)
980              
981             =back
982              
983             =head3 Ramdisk for FreeBSD
984              
985             Based on L,
986             the following commands should create a 256 megabytes ramdisk under S.
987              
988             /sbin/mdconfig -a -t malloc -s 256M -u 10
989             /sbin/newfs -U /dev/md10
990             /sbin/mount /dev/md10 /mnt/ramdisk
991              
992             The equivalent script using C for S is left as an
993             exercise for the reader.
994              
995              
996             =head3 Ramdisk for Windows
997              
998             It seems there is no built-in mechanism or tool for creating a ramdisk under
999             Windows, but the following links give a few ways to do so.
1000              
1001             =over 4
1002              
1003             =item *
1004              
1005             Microsoft C for Windows 2000: L
1006              
1007             =item *
1008              
1009             AR Soft RAMDisk (free): L
1010              
1011             =item *
1012              
1013             Cenatek RAMDisk (commercial): L
1014              
1015             =item *
1016              
1017             SuperSeed RamDisk (commercial): L
1018              
1019             =back
1020              
1021              
1022             =head1 DIAGNOSTICS
1023              
1024             =over 4
1025              
1026             =item Can't create CPANPLUS::Backend object
1027              
1028             B<(F)> C was unable to create and return a new object.
1029              
1030             =item Can't find file '%s'
1031              
1032             B<(F)> The file given in argument could not be found.
1033              
1034             =item Can't read SQLite database: %s
1035              
1036             B<(F)> The SQLite database could not be read by the DBI driver.
1037             Details follow. The message "file is encrypted or is not a database(1)"
1038             usually means that the is not an SQLite database or not in a version
1039             handled by the available C module.
1040              
1041             =item No argument given to attribute %s
1042              
1043             B<(W)> As the message implies, you didn't supply the expected argument to
1044             the attribute.
1045              
1046             =item No argument given to function %s
1047              
1048             B<(W)> As the message implies, you didn't supply the expected arguments to
1049             the function.
1050              
1051             =item Unknown option '%s': ignoring
1052              
1053             B<(W)> You gave to C an unknown attribute name.
1054              
1055             =back
1056              
1057              
1058             =head1 SEE ALSO
1059              
1060             =head2 Similar modules
1061              
1062             C was more a experiment at a given time (in 2005, for the
1063             CPAN Phalanx project), and there are now more recent modules on the CPAN in
1064             the same field, but with more features:
1065              
1066             L - Find dependencies for modules on the CPAN
1067              
1068             The CPANTS modules: L, L
1069             (see also L)
1070              
1071             L - Find generic dependencies for Perl programs and modules
1072             (not restricted to the CPAN)
1073              
1074             L - Generate dependency graphs and reports
1075              
1076              
1077             =head2 Related modules
1078              
1079             L
1080              
1081             L
1082              
1083             L
1084              
1085              
1086             =head1 AUTHOR
1087              
1088             SEbastien Aperghis-Tramoni, Esebastien@aperghis.netE
1089              
1090             =head1 BUGS
1091              
1092             Please report any bugs or feature requests to
1093             C, or through the web interface at
1094             L.
1095             I will be notified, and then you'll automatically be notified
1096             of progress on your bug as I make changes.
1097              
1098             =head1 COPYRIGHT & LICENSE
1099              
1100             Copyright 2005 SEbastien Aperghis-Tramoni, All Rights Reserved.
1101              
1102             This program is free software; you can redistribute it and/or modify it
1103             under the same terms as Perl itself.
1104              
1105             =cut
1106              
1107             1; # End of CPAN::Dependency