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   1437083 use strict;
  20         276  
  20         689  
3              
4              
5 20     20   8086 use CPANPLUS::Internals::Constants;
  20         76  
  20         6660  
6 20     20   192 use CPANPLUS::Error;
  20         45  
  20         1374  
7 20     20   8277 use CPANPLUS::Config;
  20         78  
  20         1391  
8              
9 20     20   157 use Log::Message;
  20         43  
  20         205  
10 20     20   4475 use Module::Load qw[load];
  20         48  
  20         193  
11 20     20   1488 use Params::Check qw[check];
  20         53  
  20         1077  
12 20     20   126 use File::Basename qw[dirname];
  20         43  
  20         912  
13 20     20   11156 use Module::Loaded ();
  20         14413  
  20         583  
14 20     20   144 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
  20         51  
  20         220  
15              
16 20     20   5878 use vars qw[$AUTOLOAD $VERSION $MIN_CONFIG_VERSION];
  20         50  
  20         1010  
17 20     20   155 use base qw[CPANPLUS::Internals::Utils];
  20         50  
  20         2720  
18              
19             local $Params::Check::VERBOSE = 1;
20              
21             ### require, avoid circular use ###
22             require CPANPLUS::Internals;
23             $VERSION = "0.9914";
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   149 no strict 'refs';
  20         47  
  20         28297  
29              
30             *$meth = sub {
31 3971     3971   7327 my $self = shift;
32 3971 100       10021 $self->{'_'.$meth} = $_[0] if @_;
33 3971         12998 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 2716 my $class = shift;
91 17         83 my %hash = @_;
92              
93             ### XXX pass on options to ->init() like rescan?
94 17         45 my ($load);
95 17         113 my $tmpl = {
96             load_configs => { default => 1, store => \$load },
97             };
98              
99 17 50       124 check( $tmpl, \%hash ) or (
100             warn(Params::Check->last_error), return
101             );
102              
103 17   33     2087 $Config ||= CPANPLUS::Config->new;
104 17         66 my $self = bless {}, $class;
105 17         111 $self->conf( $Config );
106              
107             ### you want us to load other configs?
108             ### these can override things in the default config
109 17 100       66 $self->init if $load;
110              
111             ### after processing the config files, check what
112             ### @INC and PERL5LIB are set to.
113 17         97 $self->_lib( \@INC );
114 17         128 $self->_perl5lib( $ENV{'PERL5LIB'} );
115              
116 17         118 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 3378 my $self = shift;
144 4         17 my $obj = $self->conf;
145 4         30 my %hash = @_;
146              
147 4         10 my ($rescan);
148 4         28 my $tmpl = {
149             rescan => { default => 0, store => \$rescan },
150             };
151              
152 4 50       48 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         386 my $cur_base = $self->get_conf('base');
160              
161             ### warn if we find an old style config specified
162             ### via environment variables
163 4         12 { my $env = ENV_CPANPLUS_CONFIG;
164 4 100 66     31 if( $ENV{$env} and not $warned ) {
165 1         4 $warned++;
166 1         10 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         12 local @INC = ( LIB_DIR->($cur_base), @INC );
  4         20  
  4         40  
176              
177             ### only set it up once
178 4 100 100     37 if( !$loaded++ or $rescan ) {
179             ### find plugins & extra configs
180             ### check $home/.cpanplus/lib as well
181 3         1502 require Module::Pluggable;
182              
183 3         20683 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         24 my %confs = map { $_ => $_ }
196 4         341 grep { $_ !~ /::ISA::/ } __PACKAGE__->configs;
  6         12701  
197 8         26 my @confs = grep { defined }
198 4         15 map { delete $confs{$_} } CONFIG_SYSTEM, CONFIG_USER;
  8         29  
199 4         36 push @confs, sort keys %confs;
200              
201 4         15 for my $plugin ( @confs ) {
202 6         46 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       79 if( my $loc = Module::Loaded::is_loaded( $plugin ) ) {
207 3         89 msg(loc(" Already loaded '%1' (%2)", $plugin, $loc), 0);
208 3         35 next;
209             } else {
210 3         93 msg(loc(" Loading config '%1'", $plugin),0);
211              
212 3 50       32 if( eval { load $plugin; 1 } ) {
  3         26  
  3         1132  
213 3         19 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       35 if( $@ ) {
221 0         0 error(loc("Could not load '%1': %2", $plugin, $@));
222 0         0 next;
223             }
224              
225 3         43 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       44 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         26 $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         20  
244 4         17 my %inc = map { $_ => $_ } @INC;
  53         152  
245 4         21 for my $l ( @$lib ) {
246 0 0       0 push @INC, $l unless $inc{$l};
247             }
248 4         24 $self->_lib( \@INC );
249             }
250              
251 4         33 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       27 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   2 my $self = shift;
294 1 50       5 my $pm = shift or return;
295 1   33     3 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         3 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         4 my $cfg_pkg = CONFIG . '::';
309 1 50       39 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         18 $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 673 my $self = shift;
329 1   50     5 my $pm = shift || CONFIG_USER;
330 1   50     6 my $savedir = shift || '';
331              
332 1 50       6 my $file = $self->_config_pm_to_file( $pm, $savedir ) or return;
333 1         75 my $dir = dirname( $file );
334              
335 1 50       66 unless( -d $dir ) {
336 1 50       17 $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       9 return unless $self->can_save($file);
342              
343             ### find only accessors that are not private
344 1         8 my @acc = sort grep { $_ !~ /^_/ } $self->conf->ls_accessors;
  6         48  
345              
346             ### for dumping the values
347 20     20   204 use Data::Dumper;
  20         62  
  20         20795  
348              
349 1         4 my @lines;
350 1         3 for my $acc ( @acc ) {
351              
352 2         12 push @lines, "### $acc section", $/;
353              
354 2         9 for my $key ( $self->conf->$acc->ls_accessors ) {
355 43         492 my $val = Dumper( $self->conf->$acc->$key );
356              
357 43         9198 $val =~ s/\$VAR1\s+=\s+//;
358 43         104 $val =~ s/;\n//;
359              
360 43         185 push @lines, '$'. "conf->set_${acc}( $key => $val );", $/;
361             }
362 2         15 push @lines, $/,$/;
363              
364             }
365              
366 1         6 my $str = join '', map { " $_" } @lines;
  94         165  
367              
368             ### use a variable to make sure the pod parser doesn't snag it
369 1         8 my $is = '=';
370 1         31 my $time = gmtime;
371              
372              
373 1         47 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       54 $self->_move( file => $file, to => "$file~" ) if -f $file;
413              
414 1         21 my $fh = new FileHandle;
415 1 50       88 $fh->open(">$file")
416             or (error(loc("Could not open '%1' for writing: %2", $file, $!)),
417             return );
418              
419 1         164 $fh->print($msg);
420 1         34 $fh->close;
421              
422 1         100 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 3790 my $self = shift;
437 6         22 my $conf = $self->conf;
438 6         30 my %hash = @_;
439              
440 6         13 my $type;
441 6         55 my $tmpl = {
442             type => { required => 1, default => '',
443             strict_type => 1, store => \$type },
444             };
445              
446 6 50       48 check($tmpl, \%hash) or return;
447              
448 6         683 my %seen;
449 63         1230 return sort grep { !$seen{$_}++ }
450 6 50       19 map { $_->$type->ls_accessors if $_->can($type) }
  6         25  
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 3843     3843   117611 my $self = shift;
513 3843         10451 my $conf = $self->conf;
514              
515 3843         7086 my $name = $AUTOLOAD;
516 3843         24326 $name =~ s/.+:://;
517              
518 3843         24490 my ($private, $action, $field) =
519             $name =~ m/^(_)?((?:[gs]et|add))_([a-z]+)$/;
520              
521 3843         9165 my $type = '';
522 3843 100       9133 $type .= '_' if $private;
523 3843 100       8957 $type .= $field if $field;
524              
525 3843         13631 my $type_code = $conf->can($type);
526 3843 100       72087 unless ( $type_code ) {
527 1         9 error( loc("Invalid method type: '%1'", $name) );
528 1         13 return;
529             }
530 3842         8116 my $type_obj = $type_code->();
531              
532 3842 50       444581 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 3842 100       10382 if( $action eq 'get' ) {
    100          
    50          
539 3502         8337 for my $key (@_) {
540 3502         6752 my @list = ();
541              
542             ### get it from the user config first
543 3502 100 33     9060 if( my $code = $type_obj->can($key) ) {
    50          
544 3501         73339 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         28 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 3501 100       346215 return wantarray ? @list : $list[0];
558             }
559              
560             ### set an existing key to a new value ###
561             } elsif ( $action eq 'set' ) {
562 334         1438 my %args = @_;
563              
564 334         1403 while( my($key,$val) = each %args ) {
565              
566 334 50       963 if( my $code = $type_obj->can($key) ) {
567 334         5244 $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         32900 return 1;
576              
577             ### add a new key to the config ###
578             } elsif ( $action eq 'add' ) {
579 6         29 my %args = @_;
580              
581 6         36 while( my($key,$val) = each %args ) {
582              
583 6 50       23 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         105 $type_obj->mk_accessors( $key );
589 6         192 $type_obj->$key( $val );
590             }
591             }
592 6         575 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   1949 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