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