Upgrade to MakeMaker 6.30_04
[p5sagit/p5-mst-13.2.git] / lib / CPAN / HandleConfig.pm
CommitLineData
e82b9348 1package CPAN::HandleConfig;
2use strict;
87892b73 3use vars qw(%can %keys $VERSION);
1a43333d 4
ed84aac9 5$VERSION = sprintf "%.6f", substr(q$Rev: 740 $,4)/1000000 + 5.4;
e82b9348 6
7%can = (
4d1321a7 8 commit => "Commit changes to disk",
9 defaults => "Reload defaults from disk",
10 help => "Short help about 'o conf' usage",
11 init => "Interactive setting of all options",
e82b9348 12);
13
4d1321a7 14%keys = map { $_ => undef } (
ed84aac9 15 # allow_unauthenticated ?? some day...
4d1321a7 16 "build_cache",
17 "build_dir",
18 "bzip2",
19 "cache_metadata",
ed84aac9 20 "check_sigs",
4d1321a7 21 "commandnumber_in_prompt",
22 "cpan_home",
23 "curl",
24 "dontload_hash", # deprecated after 1.83_68 (rev. 581)
25 "dontload_list",
26 "ftp",
27 "ftp_passive",
28 "ftp_proxy",
29 "getcwd",
30 "gpg",
31 "gzip",
32 "histfile",
33 "histsize",
34 "http_proxy",
35 "inactivity_timeout",
36 "index_expire",
37 "inhibit_startup_message",
38 "keep_source_where",
39 "lynx",
40 "make",
41 "make_arg",
42 "make_install_arg",
43 "make_install_make_command",
44 "makepl_arg",
45 "mbuild_arg",
46 "mbuild_install_arg",
47 "mbuild_install_build_command",
48 "mbuildpl_arg",
49 "ncftp",
50 "ncftpget",
51 "no_proxy",
52 "pager",
ed84aac9 53 "password",
4d1321a7 54 "prefer_installer",
55 "prerequisites_policy",
56 "scan_cache",
57 "shell",
58 "show_upload_date",
59 "tar",
60 "term_is_latin",
ed84aac9 61 "term_ornaments",
4d1321a7 62 "unzip",
63 "urllist",
ed84aac9 64 "username",
4d1321a7 65 "wait_list",
66 "wget",
67 );
44d21104 68if ($^O eq "MSWin32") {
69 for my $k (qw(
70 mbuild_install_build_command
71 make_install_make_command
72 )) {
73 delete $keys{$k};
74 if (exists $CPAN::Config->{$k}) {
87892b73 75 for ("deleting previously set config variable '$k' => '$CPAN::Config->{$k}'") {
76 $CPAN::Frontend ? $CPAN::Frontend->mywarn($_) : warn $_;
77 }
44d21104 78 delete $CPAN::Config->{$k};
79 }
80 }
81}
e82b9348 82
83# returns true on successful action
84sub edit {
85 my($self,@args) = @_;
86 return unless @args;
87 CPAN->debug("self[$self]args[".join(" | ",@args)."]");
88 my($o,$str,$func,$args,$key_exists);
89 $o = shift @args;
9ddc4ed0 90 $DB::single = 1;
e82b9348 91 if($can{$o}) {
9ddc4ed0 92 $self->$o(args => \@args);
e82b9348 93 return 1;
94 } else {
95 CPAN->debug("o[$o]") if $CPAN::DEBUG;
96 unless (exists $keys{$o}) {
97 $CPAN::Frontend->mywarn("Warning: unknown configuration variable '$o'\n");
98 }
99 if ($o =~ /list$/) {
100 $func = shift @args;
101 $func ||= "";
102 CPAN->debug("func[$func]") if $CPAN::DEBUG;
103 my $changed;
104 # Let's avoid eval, it's easier to comprehend without.
105 if ($func eq "push") {
106 push @{$CPAN::Config->{$o}}, @args;
107 $changed = 1;
108 } elsif ($func eq "pop") {
109 pop @{$CPAN::Config->{$o}};
110 $changed = 1;
111 } elsif ($func eq "shift") {
112 shift @{$CPAN::Config->{$o}};
113 $changed = 1;
114 } elsif ($func eq "unshift") {
115 unshift @{$CPAN::Config->{$o}}, @args;
116 $changed = 1;
117 } elsif ($func eq "splice") {
118 splice @{$CPAN::Config->{$o}}, @args;
119 $changed = 1;
120 } elsif (@args) {
121 $CPAN::Config->{$o} = [@args];
122 $changed = 1;
123 } else {
124 $self->prettyprint($o);
125 }
4d1321a7 126 if ($changed) {
127 if ($o eq "urllist") {
128 # reset the cached values
129 undef $CPAN::FTP::Thesite;
130 undef $CPAN::FTP::Themethod;
131 } elsif ($o eq "dontload_list") {
132 # empty it, it will be built up again
133 $CPAN::META->{dontload_hash} = {};
134 }
e82b9348 135 }
136 return $changed;
ca79d794 137 } elsif ($o =~ /_hash$/) {
44d21104 138 @args = () if @args==1 && $args[0] eq "";
ca79d794 139 push @args, "" if @args % 2;
140 $CPAN::Config->{$o} = { @args };
141 } else {
e82b9348 142 $CPAN::Config->{$o} = $args[0] if defined $args[0];
143 $self->prettyprint($o);
144 }
145 }
146}
147
148sub prettyprint {
149 my($self,$k) = @_;
150 my $v = $CPAN::Config->{$k};
151 if (ref $v) {
9ddc4ed0 152 my(@report);
153 if (ref $v eq "ARRAY") {
154 @report = map {"\t[$_]\n"} @$v;
155 } else {
156 @report = map { sprintf("\t%-18s => %s\n",
157 map { "[$_]" } $_,
158 defined $v->{$_} ? $v->{$_} : "UNDEFINED"
159 )} keys %$v;
160 }
e82b9348 161 $CPAN::Frontend->myprint(
162 join(
163 "",
164 sprintf(
165 " %-18s\n",
166 $k
167 ),
9ddc4ed0 168 @report
e82b9348 169 )
170 );
171 } elsif (defined $v) {
172 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v);
173 } else {
174 $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, "UNDEFINED");
175 }
176}
177
178sub commit {
9ddc4ed0 179 my($self,@args) = @_;
180 my $configpm;
181 if (@args) {
182 if ($args[0] eq "args") {
183 # we have not signed that contract
184 } else {
185 $configpm = $args[0];
186 }
187 }
e82b9348 188 unless (defined $configpm){
189 $configpm ||= $INC{"CPAN/MyConfig.pm"};
190 $configpm ||= $INC{"CPAN/Config.pm"};
191 $configpm || Carp::confess(q{
192CPAN::Config::commit called without an argument.
193Please specify a filename where to save the configuration or try
194"o conf init" to have an interactive course through configing.
195});
196 }
197 my($mode);
198 if (-f $configpm) {
199 $mode = (stat $configpm)[2];
200 if ($mode && ! -w _) {
201 Carp::confess("$configpm is not writable");
202 }
203 }
204
205 my $msg;
206 $msg = <<EOF unless $configpm =~ /MyConfig/;
207
208# This is CPAN.pm's systemwide configuration file. This file provides
209# defaults for users, and the values can be changed in a per-user
210# configuration file. The user-config file is being looked for as
211# ~/.cpan/CPAN/MyConfig.pm.
212
213EOF
214 $msg ||= "\n";
215 my($fh) = FileHandle->new;
216 rename $configpm, "$configpm~" if -f $configpm;
217 open $fh, ">$configpm" or
218 $CPAN::Frontend->mydie("Couldn't open >$configpm: $!");
219 $fh->print(qq[$msg\$CPAN::Config = \{\n]);
220 foreach (sort keys %$CPAN::Config) {
44d21104 221 unless (exists $keys{$_}) {
222 $CPAN::Frontend->mywarn("Dropping unknown config variable '$_'\n");
223 delete $CPAN::Config->{$_};
224 next;
225 }
e82b9348 226 $fh->print(
227 " '$_' => ",
ca79d794 228 $self->neatvalue($CPAN::Config->{$_}),
e82b9348 229 ",\n"
230 );
231 }
232
233 $fh->print("};\n1;\n__END__\n");
234 close $fh;
235
236 #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
237 #chmod $mode, $configpm;
238###why was that so? $self->defaults;
9ddc4ed0 239 $CPAN::Frontend->myprint("commit: wrote '$configpm'\n");
e82b9348 240 1;
241}
242
ca79d794 243# stolen from MakeMaker; not taking the original because it is buggy;
244# bugreport will have to say: keys of hashes remain unquoted and can
245# produce syntax errors
246sub neatvalue {
247 my($self, $v) = @_;
248 return "undef" unless defined $v;
249 my($t) = ref $v;
250 return "q[$v]" unless $t;
251 if ($t eq 'ARRAY') {
252 my(@m, @neat);
253 push @m, "[";
254 foreach my $elem (@$v) {
255 push @neat, "q[$elem]";
256 }
257 push @m, join ", ", @neat;
258 push @m, "]";
259 return join "", @m;
260 }
261 return "$v" unless $t eq 'HASH';
262 my(@m, $key, $val);
263 while (($key,$val) = each %$v){
264 last unless defined $key; # cautious programming in case (undef,undef) is true
265 push(@m,"q[$key]=>".$self->neatvalue($val)) ;
266 }
267 return "{ ".join(', ',@m)." }";
268}
269
e82b9348 270sub defaults {
271 my($self) = @_;
c9869e1c 272 my $done;
273 for my $config (qw(CPAN/MyConfig.pm CPAN/Config.pm)) {
274 CPAN::Shell->reload_this($config) and $done++;
275 last if $done;
276 }
e82b9348 277 1;
278}
279
ed84aac9 280=head2 C<< CLASS->safe_quote ITEM >>
281
282Quotes an item to become safe against spaces
283in shell interpolation. An item is enclosed
284in double quotes if:
285
286 - the item contains spaces in the middle
287 - the item does not start with a quote
288
289This happens to avoid shell interpolation
290problems when whitespace is present in
291directory names.
292
293This method uses C<commands_quote> to determine
294the correct quote. If C<commands_quote> is
295a space, no quoting will take place.
296
297
298if it starts and ends with the same quote character: leave it as it is
299
300if it contains no whitespace: leave it as it is
301
302if it contains whitespace, then
303
304if it contains quotes: better leave it as it is
305
306else: quote it with the correct quote type for the box we're on
307
308=cut
309
310{
311 # Instead of patching the guess, set commands_quote
312 # to the right value
313 my ($quotes,$use_quote)
314 = $^O eq 'MSWin32'
315 ? ('"', '"')
316 : (q<"'>, "'")
317 ;
318
319 sub safe_quote {
320 my ($self, $command) = @_;
321 # Set up quote/default quote
322 my $quote = $CPAN::Config->{commands_quote} || $quotes;
323
324 if ($quote ne ' '
325 and $command =~ /\s/
326 and $command !~ /[$quote]/) {
327 return qq<$use_quote$command$use_quote>
328 }
329 return $command;
330 }
331}
332
e82b9348 333sub init {
9ddc4ed0 334 my($self,@args) = @_;
e82b9348 335 undef $CPAN::Config->{'inhibit_startup_message'}; # lazy trick to
336 # have the least
337 # important
338 # variable
339 # undefined
9ddc4ed0 340 $self->load(@args);
e82b9348 341 1;
342}
343
344# This is a piece of repeated code that is abstracted here for
345# maintainability. RMB
346#
347sub _configpmtest {
348 my($configpmdir, $configpmtest) = @_;
349 if (-w $configpmtest) {
350 return $configpmtest;
351 } elsif (-w $configpmdir) {
352 #_#_# following code dumped core on me with 5.003_11, a.k.
353 my $configpm_bak = "$configpmtest.bak";
354 unlink $configpm_bak if -f $configpm_bak;
355 if( -f $configpmtest ) {
356 if( rename $configpmtest, $configpm_bak ) {
357 $CPAN::Frontend->mywarn(<<END);
358Old configuration file $configpmtest
359 moved to $configpm_bak
360END
361 }
362 }
363 my $fh = FileHandle->new;
364 if ($fh->open(">$configpmtest")) {
365 $fh->print("1;\n");
366 return $configpmtest;
367 } else {
368 # Should never happen
369 Carp::confess("Cannot open >$configpmtest");
370 }
371 } else { return }
372}
373
87892b73 374sub require_myconfig_or_config () {
375 return if $INC{"CPAN/MyConfig.pm"};
376 local @INC = @INC;
377 my $home = home();
378 unshift @INC, File::Spec->catdir($home,'.cpan');
379 eval { require CPAN::MyConfig };
ed84aac9 380 my $err_myconfig = $@;
381 if ($err_myconfig and $err_myconfig !~ m#locate CPAN/MyConfig\.pm#) {
382 die "Error while requiring CPAN::MyConfig:\n$err_myconfig";
383 }
87892b73 384 unless ($INC{"CPAN/MyConfig.pm"}) { # this guy has settled his needs already
385 eval {require CPAN::Config;}; # not everybody has one
ed84aac9 386 my $err_config = $@;
387 if ($err_config and $err_config !~ m#locate CPAN/Config\.pm#) {
388 die "Error while requiring CPAN::Config:\n$err_config";
389 }
87892b73 390 }
391}
392
393sub home () {
394 my $home;
395 if ($CPAN::META->has_usable("File::HomeDir")) {
396 $home = File::HomeDir->my_data;
397 } else {
398 $home = $ENV{HOME};
399 }
400 $home;
401}
402
e82b9348 403sub load {
404 my($self, %args) = @_;
405 $CPAN::Be_Silent++ if $args{be_silent};
406
407 my(@miss);
408 use Carp;
87892b73 409 require_myconfig_or_config;
e82b9348 410 return unless @miss = $self->missing_config_data;
411
412 require CPAN::FirstTime;
413 my($configpm,$fh,$redo,$theycalled);
414 $redo ||= "";
415 $theycalled++ if @miss==1 && $miss[0] eq 'inhibit_startup_message';
416 if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) {
417 $configpm = $INC{"CPAN/Config.pm"};
418 $redo++;
419 } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) {
420 $configpm = $INC{"CPAN/MyConfig.pm"};
421 $redo++;
422 } else {
423 my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"});
424 my($configpmdir) = File::Spec->catdir($path_to_cpan,"CPAN");
425 my($configpmtest) = File::Spec->catfile($configpmdir,"Config.pm");
c9869e1c 426 my $inc_key;
e82b9348 427 if (-d $configpmdir or File::Path::mkpath($configpmdir)) {
c9869e1c 428 $configpm = _configpmtest($configpmdir,$configpmtest);
429 $inc_key = "CPAN/Config.pm";
e82b9348 430 }
431 unless ($configpm) {
87892b73 432 $configpmdir = File::Spec->catdir(home,".cpan","CPAN");
e82b9348 433 File::Path::mkpath($configpmdir);
434 $configpmtest = File::Spec->catfile($configpmdir,"MyConfig.pm");
c9869e1c 435 $configpm = _configpmtest($configpmdir,$configpmtest);
436 $inc_key = "CPAN/MyConfig.pm";
e82b9348 437 }
c9869e1c 438 if ($configpm) {
439 $INC{$inc_key} = $configpm;
440 } else {
441 my $text = qq{WARNING: CPAN.pm is unable to } .
442 qq{create a configuration file.};
443 output($text, 'confess');
444 }
445
e82b9348 446 }
447 local($") = ", ";
448 $CPAN::Frontend->myprint(<<END) if $redo && ! $theycalled;
0cf35e6a 449Sorry, we have to rerun the configuration dialog for CPAN.pm due to
450the following indispensable but missing parameters:
e82b9348 451
452@miss
453END
454 $CPAN::Frontend->myprint(qq{
455$configpm initialized.
456});
457
458 sleep 2;
459 CPAN::FirstTime::init($configpm, %args);
460}
461
462sub missing_config_data {
463 my(@miss);
464 for (
0cf35e6a 465 "build_cache",
466 "build_dir",
467 "cache_metadata",
468 "cpan_home",
469 "ftp_proxy",
ed84aac9 470 #"gzip",
0cf35e6a 471 "http_proxy",
472 "index_expire",
473 "inhibit_startup_message",
474 "keep_source_where",
ed84aac9 475 #"make",
0cf35e6a 476 "make_arg",
477 "make_install_arg",
478 "makepl_arg",
479 "mbuild_arg",
480 "mbuild_install_arg",
481 "mbuild_install_build_command",
482 "mbuildpl_arg",
483 "no_proxy",
ed84aac9 484 #"pager",
e82b9348 485 "prerequisites_policy",
0cf35e6a 486 "scan_cache",
ed84aac9 487 #"tar",
488 #"unzip",
0cf35e6a 489 "urllist",
e82b9348 490 ) {
44d21104 491 next unless exists $keys{$_};
e82b9348 492 push @miss, $_ unless defined $CPAN::Config->{$_};
493 }
494 return @miss;
495}
496
e82b9348 497sub help {
498 $CPAN::Frontend->myprint(q[
499Known options:
e82b9348 500 commit commit session changes to disk
4d1321a7 501 defaults reload default config values from disk
502 help this help
e82b9348 503 init go through a dialog to set all parameters
504
4d1321a7 505Edit key values as in the following (the "o" is a literal letter o):
e82b9348 506 o conf build_cache 15
e82b9348 507 o conf build_dir "/foo/bar"
e82b9348 508 o conf urllist shift
e82b9348 509 o conf urllist unshift ftp://ftp.foo.bar/
4d1321a7 510 o conf inhibit_startup_message 1
e82b9348 511
512]);
513 undef; #don't reprint CPAN::Config
514}
515
516sub cpl {
517 my($word,$line,$pos) = @_;
518 $word ||= "";
519 CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
520 my(@words) = split " ", substr($line,0,$pos+1);
521 if (
522 defined($words[2])
523 and
524 (
525 $words[2] =~ /list$/ && @words == 3
526 ||
527 $words[2] =~ /list$/ && @words == 4 && length($word)
528 )
529 ) {
530 return grep /^\Q$word\E/, qw(splice shift unshift pop push);
531 } elsif (@words >= 4) {
532 return ();
533 }
534 my %seen;
535 my(@o_conf) = sort grep { !$seen{$_}++ }
536 keys %can,
537 keys %$CPAN::Config,
538 keys %keys;
539 return grep /^\Q$word\E/, @o_conf;
540}
541
9ddc4ed0 542
4d1321a7 543package
544 CPAN::Config; ####::###### #hide from indexer
9ddc4ed0 545# note: J. Nick Koston wrote me that they are using
546# CPAN::Config->commit although undocumented. I suggested
547# CPAN::Shell->o("conf","commit") even when ugly it is at least
548# documented
549
550# that's why I added the CPAN::Config class with autoload and
551# deprecated warning
552
553use strict;
554use vars qw($AUTOLOAD $VERSION);
ed84aac9 555$VERSION = sprintf "%.2f", substr(q$Rev: 740 $,4)/100;
9ddc4ed0 556
557# formerly CPAN::HandleConfig was known as CPAN::Config
558sub AUTOLOAD {
559 my($l) = $AUTOLOAD;
560 $CPAN::Frontend->mywarn("Dispatching deprecated method '$l' to CPAN::HandleConfig");
561 $l =~ s/.*:://;
562 CPAN::HandleConfig->$l(@_);
563}
564
e82b9348 5651;
0cf35e6a 566
567__END__
568# Local Variables:
569# mode: cperl
ca79d794 570# cperl-indent-level: 4
0cf35e6a 571# End: