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