File Coverage

lib/CPANPLUS/Configure.pm
Criterion Covered Total %
statement 188 209 89.9
branch 48 74 64.8
condition 11 22 50.0
subroutine 23 23 100.0
pod 5 5 100.0
total 275 333 82.5


line stmt bran cond sub pod time code
1             package CPANPLUS::Configure;
2 20     20   1406769 use strict;
  20         268  
  20         914  
3              
4              
5 20     20   8311 use CPANPLUS::Internals::Constants;
  20         79  
  20         6733  
6 20     20   164 use CPANPLUS::Error;
  20         48  
  20         1219  
7 20     20   8603 use CPANPLUS::Config;
  20         98  
  20         1258  
8              
9 20     20   151 use Log::Message;
  20         54  
  20         206  
10 20     20   4451 use Module::Load qw[load];
  20         50  
  20         183  
11 20     20   1450 use Params::Check qw[check];
  20         101  
  20         1150  
12 20     20   138 use File::Basename qw[dirname];
  20         52  
  20         963  
13 20     20   11420 use Module::Loaded ();
  20         14396  
  20         574  
14 20     20   155 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
  20         57  
  20         201  
15              
16 20     20   6435 use vars qw[$AUTOLOAD $VERSION $MIN_CONFIG_VERSION];
  20         46  
  20         1038  
17 20     20   116 use base qw[CPANPLUS::Internals::Utils];
  20         51  
  20         2523  
18              
19             local $Params::Check::VERBOSE = 1;
20              
21             ### require, avoid circular use ###
22             require CPANPLUS::Internals;
23             $VERSION = "0.9910";
24              
25             ### can't use O::A as we're using our own AUTOLOAD to get to
26             ### the config options.
27             for my $meth ( qw[conf _lib _perl5lib]) {
28 20     20   135 no strict 'refs';
  20         59  
  20         27753  
29              
30             *$meth = sub {
31 3969     3969   7161 my $self = shift;
32 3969 100       10297 $self->{'_'.$meth} = $_[0] if @_;
33 3969         12614 return $self->{'_'.$meth};
34             }
35             }
36              
37              
38             =pod
39              
40             =head1 NAME
41              
42             CPANPLUS::Configure - configuration for CPANPLUS
43              
44             =head1 SYNOPSIS
45              
46             $conf = CPANPLUS::Configure->new( );
47              
48             $bool = $conf->can_save;
49             $bool = $conf->save( $where );
50              
51             @opts = $conf->options( $type );
52              
53             $make = $conf->get_program('make');
54             $verbose = $conf->set_conf( verbose => 1 );
55              
56             =head1 DESCRIPTION
57              
58             This module deals with all the configuration issues for CPANPLUS.
59             Users can use objects created by this module to alter the behaviour
60             of CPANPLUS.
61              
62             Please refer to the C documentation on how to
63             obtain a C object.
64              
65             =head1 METHODS
66              
67             =head2 $Configure = CPANPLUS::Configure->new( load_configs => BOOL )
68              
69             This method returns a new object. Normal users will never need to
70             invoke the C method, but instead retrieve the desired object via
71             a method call on a C object.
72              
73             =over 4
74              
75             =item load_configs
76              
77             Controls whether or not additional user configurations are to be loaded
78             or not. Defaults to C.
79              
80             =back
81              
82             =cut
83              
84             ### store the CPANPLUS::Config object in a closure, so we only
85             ### initialize it once.. otherwise, on a 2nd ->new, settings
86             ### from configs on top of this one will be reset
87             { my $Config;
88              
89             sub new {
90 17     17 1 2740 my $class = shift;
91 17         90 my %hash = @_;
92              
93             ### XXX pass on options to ->init() like rescan?
94 17         41 my ($load);
95 17         110 my $tmpl = {
96             load_configs => { default => 1, store => \$load },
97             };
98              
99 17 50       129 check( $tmpl, \%hash ) or (
100             warn(Params::Check->last_error), return
101             );
102              
103 17   33     2126 $Config ||= CPANPLUS::Config->new;
104 17         72 my $self = bless {}, $class;
105 17         105 $self->conf( $Config );
106              
107             ### you want us to load other configs?
108             ### these can override things in the default config
109 17 100       93 $self->init if $load;
110              
111             ### after processing the config files, check what
112             ### @INC and PERL5LIB are set to.
113 17         127 $self->_lib( \@INC );
114 17         108 $self->_perl5lib( $ENV{'PERL5LIB'} );
115              
116 17         103 return $self;
117             }
118             }
119              
120             =head2 $bool = $Configure->init( [rescan => BOOL])
121              
122             Initialize the configure with other config files than just
123             the default 'CPANPLUS::Config'.
124              
125             Called from C to load user/system configurations
126              
127             If the C option is provided, your disk will be
128             examined again to see if there are new config files that
129             could be read. Defaults to C.
130              
131             Returns true on success, false on failure.
132              
133             =cut
134              
135             ### move the Module::Pluggable detection to runtime, rather
136             ### than compile time, so that a simple 'require CPANPLUS'
137             ### doesn't start running over your filesystem for no good
138             ### reason. Make sure we only do the M::P call once though.
139             ### we use $loaded to mark it
140             { my $loaded;
141             my $warned;
142             sub init {
143 4     4 1 2748 my $self = shift;
144 4         13 my $obj = $self->conf;
145 4         16 my %hash = @_;
146              
147 4         13 my ($rescan);
148 4         31 my $tmpl = {
149             rescan => { default => 0, store => \$rescan },
150             };
151              
152 4 50       19 check( $tmpl, \%hash ) or (
153             warn(Params::Check->last_error), return
154             );
155              
156             ### if the base dir is changed, we have to rescan it
157             ### for any CPANPLUS::Config::* files as well, so keep
158             ### track of it
159 4         321 my $cur_base = $self->get_conf('base');
160              
161             ### warn if we find an old style config specified
162             ### via environment variables
163 4         9 { my $env = ENV_CPANPLUS_CONFIG;
164 4 100 66     25 if( $ENV{$env} and not $warned ) {
165 1         3 $warned++;
166 1         7 error(loc("Specifying a config file in your environment " .
167             "using %1 is obsolete.\nPlease follow the ".
168             "directions outlined in %2 or use the '%3' command\n".
169             "in the default shell to use custom config files.",
170             $env, "CPANPLUS::Configure->save", 's save'));
171             }
172             }
173              
174             { ### make sure that the homedir is included now
175 4         11 local @INC = ( LIB_DIR->($cur_base), @INC );
  4         16  
  4         23  
176              
177             ### only set it up once
178 4 100 100     41 if( !$loaded++ or $rescan ) {
179             ### find plugins & extra configs
180             ### check $home/.cpanplus/lib as well
181 3         1356 require Module::Pluggable;
182              
183 3         20461 Module::Pluggable->import(
184             search_path => ['CPANPLUS::Config'],
185             search_dirs => [ LIB_DIR->($cur_base) ],
186             except => qr/::SUPER$/,
187             sub_name => 'configs'
188             );
189             }
190              
191              
192             ### do system config, user config, rest.. in that order
193             ### apparently, on a 2nd invocation of -->configs, a
194             ### ::ISA::CACHE package can appear.. that's bad...
195 6         22 my %confs = map { $_ => $_ }
196 4         328 grep { $_ !~ /::ISA::/ } __PACKAGE__->configs;
  6         12413  
197 8         23 my @confs = grep { defined }
198 4         18 map { delete $confs{$_} } CONFIG_SYSTEM, CONFIG_USER;
  8         21  
199 4         84 push @confs, sort keys %confs;
200              
201 4         65 for my $plugin ( @confs ) {
202 6         33 msg(loc("Found config '%1'", $plugin),0);
203              
204             ### if we already did this the /last/ time around don't
205             ### run the setup again.
206 6 100       95 if( my $loc = Module::Loaded::is_loaded( $plugin ) ) {
207 3         74 msg(loc(" Already loaded '%1' (%2)", $plugin, $loc), 0);
208 3         30 next;
209             } else {
210 3         96 msg(loc(" Loading config '%1'", $plugin),0);
211              
212 3 50       29 if( eval { load $plugin; 1 } ) {
  3         19  
  3         897  
213 3         18 msg(loc(" Loaded '%1' (%2)",
214             $plugin, Module::Loaded::is_loaded( $plugin ) ), 0);
215             } else {
216 0         0 error(loc(" Error loading '%1': %2", $plugin, $@));
217             }
218             }
219              
220 3 50       54 if( $@ ) {
221 0         0 error(loc("Could not load '%1': %2", $plugin, $@));
222 0         0 next;
223             }
224              
225 3         41 my $sub = $plugin->can('setup');
226 3 50       18 $sub->( $self ) if $sub;
227             }
228             }
229              
230             ### did one of the plugins change the base dir? then we should
231             ### scan the dirs again
232 4 50       34 if( $cur_base ne $self->get_conf('base') ) {
233 0         0 msg(loc("Base dir changed from '%1' to '%2', rescanning",
234             $cur_base, $self->get_conf('base')), 0);
235 0         0 $self->init( @_, rescan => 1 );
236             }
237              
238             ### clean up the paths once more, just in case
239 4         28 $obj->_clean_up_paths;
240              
241             ### XXX in case the 'lib' param got changed, we need to
242             ### add that now, or it's not propagating ;(
243 4         13 { my $lib = $self->get_conf('lib');
  4         24  
244 4         18 my %inc = map { $_ => $_ } @INC;
  53         140  
245 4         20 for my $l ( @$lib ) {
246 0 0       0 push @INC, $l unless $inc{$l};
247             }
248 4         19 $self->_lib( \@INC );
249             }
250              
251 4         25 return 1;
252             }
253             }
254             =pod
255              
256             =head2 can_save( [$config_location] )
257              
258             Check if we can save the configuration to the specified file.
259             If no file is provided, defaults to your personal config.
260              
261             Returns true if the file can be saved, false otherwise.
262              
263             =cut
264              
265             sub can_save {
266 1     1 1 3 my $self = shift;
267 1   33     4 my $file = shift || CONFIG_USER_FILE->();
268              
269 1 50       31 return 1 unless -e $file;
270              
271 0         0 chmod 0644, $file;
272 0         0 return (-w $file);
273             }
274              
275             =pod
276              
277             =head2 $file = $conf->save( [$package_name] )
278              
279             Saves the configuration to the package name you provided.
280             If this package is not C, it will
281             be saved in your C<.cpanplus> directory, otherwise it will
282             be attempted to be saved in the system wide directory.
283              
284             If no argument is provided, it will default to your personal
285             config.
286              
287             Returns the full path to the file if the config was saved,
288             false otherwise.
289              
290             =cut
291              
292             sub _config_pm_to_file {
293 1     1   4 my $self = shift;
294 1 50       4 my $pm = shift or return;
295 1   33     5 my $dir = shift || CONFIG_USER_LIB_DIR->();
296              
297             ### only 3 types of files know: home, system and 'other'
298             ### so figure out where to save them based on their type
299 1         2 my $file;
300 1 50       7 if( $pm eq CONFIG_USER ) {
    50          
301 0         0 $file = CONFIG_USER_FILE->();
302              
303             } elsif ( $pm eq CONFIG_SYSTEM ) {
304 0         0 $file = CONFIG_SYSTEM_FILE->();
305              
306             ### third party file
307             } else {
308 1         3 my $cfg_pkg = CONFIG . '::';
309 1 50       37 unless( $pm =~ /^$cfg_pkg/ ) {
310 0         0 error(loc(
311             "WARNING: Your config package '%1' is not in the '%2' ".
312             "namespace and will not be automatically detected by %3",
313             $pm, $cfg_pkg, 'CPANPLUS'
314             ));
315             }
316              
317 1         17 $file = File::Spec->catfile(
318             $dir,
319             split( '::', $pm )
320             ) . '.pm';
321             }
322              
323 1         5 return $file;
324             }
325              
326              
327             sub save {
328 1     1 1 665 my $self = shift;
329 1   50     6 my $pm = shift || CONFIG_USER;
330 1   50     7 my $savedir = shift || '';
331              
332 1 50       4 my $file = $self->_config_pm_to_file( $pm, $savedir ) or return;
333 1         75 my $dir = dirname( $file );
334              
335 1 50       62 unless( -d $dir ) {
336 1 50       15 $self->_mkdir( dir => $dir ) or (
337             error(loc("Can not create directory '%1' to save config to",$dir)),
338             return
339             )
340             }
341 1 50       7 return unless $self->can_save($file);
342              
343             ### find only accessors that are not private
344 1         6 my @acc = sort grep { $_ !~ /^_/ } $self->conf->ls_accessors;
  6         39  
345              
346             ### for dumping the values
347 20     20   201 use Data::Dumper;
  20         50  
  20         20457  
348              
349 1         4 my @lines;
350 1         4 for my $acc ( @acc ) {
351              
352 2         9 push @lines, "### $acc section", $/;
353              
354 2         8 for my $key ( $self->conf->$acc->ls_accessors ) {
355 43         421 my $val = Dumper( $self->conf->$acc->$key );
356              
357 43         9300 $val =~ s/\$VAR1\s+=\s+//;
358 43         117 $val =~ s/;\n//;
359              
360 43         211 push @lines, '$'. "conf->set_${acc}( $key => $val );", $/;
361             }
362 2         11 push @lines, $/,$/;
363              
364             }
365              
366 1         4 my $str = join '', map { " $_" } @lines;
  94         156  
367              
368             ### use a variable to make sure the pod parser doesn't snag it
369 1         10 my $is = '=';
370 1         27 my $time = gmtime;
371              
372              
373 1         26 my $msg = <<_END_OF_CONFIG_;
374             ###############################################
375             ###
376             ### Configuration structure for $pm
377             ###
378             ###############################################
379              
380             #last changed: $time GMT
381              
382             ### minimal pod, so you can find it with perldoc -l, etc
383             ${is}pod
384              
385             ${is}head1 NAME
386              
387             $pm
388              
389             ${is}head1 DESCRIPTION
390              
391             This is a CPANPLUS configuration file. Editing this
392             config changes the way CPANPLUS will behave
393              
394             ${is}cut
395              
396             package $pm;
397              
398             use strict;
399              
400             sub setup {
401             my \$conf = shift;
402              
403             $str
404              
405             return 1;
406             }
407              
408             1;
409              
410             _END_OF_CONFIG_
411              
412 1 50       19 $self->_move( file => $file, to => "$file~" ) if -f $file;
413              
414 1         12 my $fh = new FileHandle;
415 1 50       40 $fh->open(">$file")
416             or (error(loc("Could not open '%1' for writing: %2", $file, $!)),
417             return );
418              
419 1         100 $fh->print($msg);
420 1         33 $fh->close;
421              
422 1         64 return $file;
423             }
424              
425             =pod
426              
427             =head2 options( type => TYPE )
428              
429             Returns a list of all valid config options given a specific type
430             (like for example C of C) or false if the type does
431             not exist
432              
433             =cut
434              
435             sub options {
436 6     6 1 3657 my $self = shift;
437 6         17 my $conf = $self->conf;
438 6         21 my %hash = @_;
439              
440 6         10 my $type;
441 6         35 my $tmpl = {
442             type => { required => 1, default => '',
443             strict_type => 1, store => \$type },
444             };
445              
446 6 50       24 check($tmpl, \%hash) or return;
447              
448 6         550 my %seen;
449 63         1143 return sort grep { !$seen{$_}++ }
450 6 50       16 map { $_->$type->ls_accessors if $_->can($type) }
  6         21  
451             $self->conf;
452             }
453              
454             =pod
455              
456             =head1 ACCESSORS
457              
458             Accessors that start with a C<_> are marked private -- regular users
459             should never need to use these.
460              
461             See the C documentation for what items can be
462             set and retrieved.
463              
464             =head2 get_SOMETHING( ITEM, [ITEM, ITEM, ... ] );
465              
466             The C style accessors merely retrieves one or more desired
467             config options.
468              
469             =head2 set_SOMETHING( ITEM => VAL, [ITEM => VAL, ITEM => VAL, ... ] );
470              
471             The C style accessors set the current value for one
472             or more config options and will return true upon success, false on
473             failure.
474              
475             =head2 add_SOMETHING( ITEM => VAL, [ITEM => VAL, ITEM => VAL, ... ] );
476              
477             The C style accessor adds a new key to a config key.
478              
479             Currently, the following accessors exist:
480              
481             =over 4
482              
483             =item set|get_conf
484              
485             Simple configuration directives like verbosity and favourite shell.
486              
487             =item set|get_program
488              
489             Location of helper programs.
490              
491             =item _set|_get_build
492              
493             Locations of where to put what files for CPANPLUS.
494              
495             =item _set|_get_source
496              
497             Locations and names of source files locally.
498              
499             =item _set|_get_mirror
500              
501             Locations and names of source files remotely.
502              
503             =item _set|_get_fetch
504              
505             Special settings pertaining to the fetching of files.
506              
507             =back
508              
509             =cut
510              
511             sub AUTOLOAD {
512 3841     3841   112074 my $self = shift;
513 3841         10463 my $conf = $self->conf;
514              
515 3841         7407 my $name = $AUTOLOAD;
516 3841         21967 $name =~ s/.+:://;
517              
518 3841         24811 my ($private, $action, $field) =
519             $name =~ m/^(_)?((?:[gs]et|add))_([a-z]+)$/;
520              
521 3841         9223 my $type = '';
522 3841 100       9039 $type .= '_' if $private;
523 3841 100       8186 $type .= $field if $field;
524              
525 3841         14161 my $type_code = $conf->can($type);
526 3841 100       71008 unless ( $type_code ) {
527 1         5 error( loc("Invalid method type: '%1'", $name) );
528 1         14 return;
529             }
530 3840         7957 my $type_obj = $type_code->();
531              
532 3840 50       434215 unless( scalar @_ ) {
533 0         0 error( loc("No arguments provided!") );
534 0         0 return;
535             }
536              
537             ### retrieve a current value for an existing key ###
538 3840 100       9755 if( $action eq 'get' ) {
    100          
    50          
539 3500         8068 for my $key (@_) {
540 3500         6457 my @list = ();
541              
542             ### get it from the user config first
543 3500 100 33     8455 if( my $code = $type_obj->can($key) ) {
    50          
544 3499         71547 push @list, $code->();
545              
546             ### XXX EU::AI compatibility hack to provide lookups like in
547             ### cpanplus 0.04x; we renamed ->_get_build('base') to
548             ### ->get_conf('base')
549             } elsif ( $type eq '_build' and $key eq 'base' ) {
550 1         29 return $self->get_conf($key);
551              
552             } else {
553 0         0 error( loc(q[No such key '%1' in field '%2'], $key, $type) );
554 0         0 return;
555             }
556              
557 3499 100       339058 return wantarray ? @list : $list[0];
558             }
559              
560             ### set an existing key to a new value ###
561             } elsif ( $action eq 'set' ) {
562 334         1339 my %args = @_;
563              
564 334         1347 while( my($key,$val) = each %args ) {
565              
566 334 50       874 if( my $code = $type_obj->can($key) ) {
567 334         5070 $code->( $val );
568              
569             } else {
570 0         0 error( loc(q[No such key '%1' in field '%2'], $key, $type) );
571 0         0 return;
572             }
573             }
574              
575 334         32582 return 1;
576              
577             ### add a new key to the config ###
578             } elsif ( $action eq 'add' ) {
579 6         18 my %args = @_;
580              
581 6         28 while( my($key,$val) = each %args ) {
582              
583 6 50       17 if( $type_obj->can($key) ) {
584 0         0 error( loc( q[Key '%1' already exists for field '%2'],
585             $key, $type));
586 0         0 return;
587             } else {
588 6         85 $type_obj->mk_accessors( $key );
589 6         151 $type_obj->$key( $val );
590             }
591             }
592 6         615 return 1;
593              
594             } else {
595              
596 0         0 error( loc(q[Unknown action '%1'], $action) );
597 0         0 return;
598             }
599             }
600              
601 3     3   2191 sub DESTROY { 1 };
602              
603             1;
604              
605             =pod
606              
607             =head1 BUG REPORTS
608              
609             Please report bugs or other issues to Ebug-cpanplus@rt.cpan.org.
610              
611             =head1 AUTHOR
612              
613             This module by Jos Boumans Ekane@cpan.orgE.
614              
615             =head1 COPYRIGHT
616              
617             The CPAN++ interface (of which this module is a part of) is copyright (c)
618             2001 - 2007, Jos Boumans Ekane@cpan.orgE. All rights reserved.
619              
620             This library is free software; you may redistribute and/or modify it
621             under the same terms as Perl itself.
622              
623             =head1 SEE ALSO
624              
625             L, L, L
626              
627             =cut
628              
629             # Local variables:
630             # c-indentation-style: bsd
631             # c-basic-offset: 4
632             # indent-tabs-mode: nil
633             # End:
634             # vim: expandtab shiftwidth=4:
635