| 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 |  |  |  |  |  |  |  |