Upgrade to CPAN 1.87_63
[p5sagit/p5-mst-13.2.git] / lib / CPAN / FirstTime.pm
CommitLineData
8d97e4a1 1# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
5f05dabc 2package CPAN::Mirrored::By;
e82b9348 3use strict;
1a43333d 4use vars qw($VERSION);
7fefbd44 5$VERSION = sprintf "%.6f", substr(q$Rev: 825 $,4)/1000000 + 5.4;
5f05dabc 6
7sub new {
8 my($self,@arg) = @_;
9 bless [@arg], $self;
10}
da199366 11sub continent { shift->[0] }
12sub country { shift->[1] }
5f05dabc 13sub url { shift->[2] }
14
15package CPAN::FirstTime;
16
17use strict;
f915a99a 18use ExtUtils::MakeMaker ();
05454584 19use FileHandle ();
09d9d230 20use File::Basename ();
05454584 21use File::Path ();
5de3f0da 22use File::Spec;
8962fc49 23use vars qw($VERSION $urllist);
7fefbd44 24$VERSION = sprintf "%.6f", substr(q$Rev: 825 $,4)/1000000 + 5.4;
5f05dabc 25
26=head1 NAME
27
28CPAN::FirstTime - Utility for CPAN::Config file Initialization
29
30=head1 SYNOPSIS
31
32CPAN::FirstTime::init()
33
34=head1 DESCRIPTION
35
c9869e1c 36The init routine asks a few questions and writes a CPAN/Config.pm or
37CPAN/MyConfig.pm file (depending on what it is currently using).
38
5f05dabc 39
40=cut
41
9ddc4ed0 42use vars qw( %prompts );
43
5f05dabc 44sub init {
554a9ef5 45 my($configpm, %args) = @_;
5f05dabc 46 use Config;
9ddc4ed0 47 # extra arg in 'o conf init make' selects only $item =~ /make/
48 my $matcher = $args{args} && @{$args{args}} ? $args{args}[0] : '';
8962fc49 49 if ($matcher =~ /^\w+$/) {
50 if (
51 exists $CPAN::HandleConfig::keys{$matcher}
52 ) {
53 $matcher = "\\b$matcher\\b";
54 } else {
55 $CPAN::Frontend->myprint("'$matcher' is not a valid configuration variable");
56 return;
57 }
58 }
c9869e1c 59 CPAN->debug("matcher[$matcher]") if $CPAN::DEBUG;
554a9ef5 60
f610777f 61 unless ($CPAN::VERSION) {
62 require CPAN::Nox;
63 }
87892b73 64 require CPAN::HandleConfig;
65 CPAN::HandleConfig::require_myconfig_or_config();
5f05dabc 66 $CPAN::Config ||= {};
da199366 67 local($/) = "\n";
68 local($\) = "";
13bc20ff 69 local($|) = 1;
da199366 70
5fc0f0f6 71 my($ans,$default);
f610777f 72
da199366 73 #
8962fc49 74 #= Files, directories
da199366 75 #
76
8962fc49 77 unless ($matcher) {
78 $CPAN::Frontend->myprint($prompts{manual_config});
79 }
09d9d230 80
554a9ef5 81 my $manual_conf;
82
7fefbd44 83 local *_real_prompt;
554a9ef5 84 if ( $args{autoconfig} ) {
85 $manual_conf = "no";
8962fc49 86 } elsif ($matcher) {
87 $manual_conf = "yes";
554a9ef5 88 } else {
8962fc49 89 my $_conf = prompt("Would you like me to configure as much as possible ".
90 "automatically?", "yes");
91 $manual_conf = ($_conf and $_conf =~ /^y/i) ? "no" : "yes";
554a9ef5 92 }
8962fc49 93 CPAN->debug("manual_conf[$manual_conf]") if $CPAN::DEBUG;
09d9d230 94 my $fastread;
95 {
f915a99a 96 if ($manual_conf =~ /^y/i) {
09d9d230 97 $fastread = 0;
09d9d230 98 } else {
99 $fastread = 1;
36263cb3 100 $CPAN::Config->{urllist} ||= [];
f915a99a 101
102 local $^W = 0;
c9d9b473 103 # prototype should match that of &MakeMaker::prompt
8962fc49 104 my $current_second = time;
105 my $current_second_count = 0;
106 my $i_am_mad = 0;
f915a99a 107 *_real_prompt = sub ($;$) {
09d9d230 108 my($q,$a) = @_;
109 my($ret) = defined $a ? $a : "";
554a9ef5 110 $CPAN::Frontend->myprint(sprintf qq{%s [%s]\n\n}, $q, $ret);
111 eval { require Time::HiRes };
112 unless ($@) {
8962fc49 113 if (time == $current_second) {
114 $current_second_count++;
115 if ($current_second_count > 20) {
116 # I don't like more than 20 prompts per second
117 $i_am_mad++;
118 }
119 } else {
120 $current_second = time;
121 $current_second_count = 0;
122 $i_am_mad-- if $i_am_mad>0;
123 }
124 if ($i_am_mad>0){
125 #require Carp;
126 #Carp::cluck("SLEEEEEEEEPIIIIIIIIIIINGGGGGGGGGGG");
127 Time::HiRes::sleep(0.1);
128 }
554a9ef5 129 }
09d9d230 130 $ret;
131 };
132 }
133 }
9ddc4ed0 134
8962fc49 135 if (!$matcher or 'cpan_home keep_source_where build_dir' =~ /$matcher/){
136 $CPAN::Frontend->myprint($prompts{config_intro});
9ddc4ed0 137
8962fc49 138 if (!$matcher or 'cpan_home' =~ /$matcher/) {
139 my $cpan_home = $CPAN::Config->{cpan_home}
140 || File::Spec->catdir($ENV{HOME}, ".cpan");
5f05dabc 141
8962fc49 142 if (-d $cpan_home) {
143 $CPAN::Frontend->myprint(qq{
5f05dabc 144
145I see you already have a directory
146 $cpan_home
147Shall we use it as the general CPAN build and cache directory?
148
554a9ef5 149});
8962fc49 150 } else {
151 # no cpan-home, must prompt and get one
152 $CPAN::Frontend->myprint($prompts{cpan_home_where});
153 }
f610777f 154
8962fc49 155 $default = $cpan_home;
156 while ($ans = prompt("CPAN build and cache directory?",$default)) {
157 unless (File::Spec->file_name_is_absolute($ans)) {
158 require Cwd;
159 my $cwd = Cwd::cwd();
160 my $absans = File::Spec->catdir($cwd,$ans);
161 $CPAN::Frontend->mywarn("The path '$ans' is not an ".
162 "absolute path. Please specify ".
163 "an absolute path\n");
164 $default = $absans;
165 next;
166 }
167 eval { File::Path::mkpath($ans); }; # dies if it can't
168 if ($@) {
169 $CPAN::Frontend->mywarn("Couldn't create directory $ans.\n".
170 "Please retry.\n");
171 next;
172 }
173 if (-d $ans && -w _) {
174 last;
175 } else {
176 $CPAN::Frontend->mywarn("Couldn't find directory $ans\n".
177 "or directory is not writable. Please retry.\n");
178 }
179 }
180 $CPAN::Config->{cpan_home} = $ans;
181 }
5f05dabc 182
8962fc49 183 if (!$matcher or 'keep_source_where' =~ /$matcher/) {
184 my_dflt_prompt("keep_source_where",
185 File::Spec->catdir($CPAN::Config->{cpan_home},"sources"),
186 $matcher,
187 );
188 }
5f05dabc 189
8962fc49 190 if (!$matcher or 'build_dir' =~ /$matcher/) {
191 my_dflt_prompt("build_dir",
192 File::Spec->catdir($CPAN::Config->{cpan_home},"build"),
193 $matcher
194 );
195 }
196 }
5f05dabc 197
da199366 198 #
8962fc49 199 #= Cache size, Index expire
da199366 200 #
201
8962fc49 202 if (!$matcher or 'build_cache' =~ /$matcher/){
203 $CPAN::Frontend->myprint($prompts{build_cache_intro});
5f05dabc 204
8962fc49 205 # large enough to build large dists like Tk
206 my_dflt_prompt(build_cache => 100, $matcher);
207 }
5e05dca5 208
8962fc49 209 if (!$matcher or 'index_expire' =~ /$matcher/) {
210 $CPAN::Frontend->myprint($prompts{index_expire_intro});
5e05dca5 211
8962fc49 212 my_dflt_prompt(index_expire => 1, $matcher);
c9869e1c 213 }
9d61fa1d 214
8962fc49 215 if (!$matcher or 'scan_cache' =~ /$matcher/){
216 $CPAN::Frontend->myprint($prompts{scan_cache_intro});
9d61fa1d 217
8962fc49 218 my_prompt_loop(scan_cache => 'atstart', $matcher, 'atstart|never');
219 }
9d61fa1d 220
221 #
8962fc49 222 #= cache_metadata
5fc0f0f6 223 #
5fc0f0f6 224
8962fc49 225 my_yn_prompt(cache_metadata => 1, $matcher);
5fc0f0f6 226
227 #
8962fc49 228 #= Do we follow PREREQ_PM?
554a9ef5 229 #
554a9ef5 230
8962fc49 231 if (!$matcher or 'prerequisites_policy' =~ /$matcher/){
232 $CPAN::Frontend->myprint($prompts{prerequisites_policy_intro});
9ddc4ed0 233
8962fc49 234 my_prompt_loop(prerequisites_policy => 'ask', $matcher,
235 'follow|ask|ignore');
236 }
554a9ef5 237
238 #
8962fc49 239 #= Module::Signature
f610777f 240 #
8962fc49 241 if (!$matcher or 'check_sigs' =~ /$matcher/) {
242 my_yn_prompt(check_sigs => 0, $matcher);
243 }
f610777f 244
da199366 245 #
8962fc49 246 #= CPAN::Reporter
ed84aac9 247 #
8962fc49 248 if (!$matcher or 'test_report' =~ /$matcher/) {
249 my_yn_prompt(test_report => 0, $matcher);
250 if (
251 $CPAN::Config->{test_report} &&
252 $CPAN::META->has_inst("CPAN::Reporter") &&
253 CPAN::Reporter->can('configure')
254 ) {
255 $CPAN::Frontend->myprint("\nProceeding to configure CPAN::Reporter.\n");
256 CPAN::Reporter::configure();
257 $CPAN::Frontend->myprint("\nReturning to CPAN configuration.\n");
258 }
259 }
ed84aac9 260
261 #
8962fc49 262 #= External programs
da199366 263 #
264
8962fc49 265 my @external_progs = qw/bzip2 gzip tar unzip make
554a9ef5 266 curl lynx wget ncftpget ncftp ftp
8962fc49 267 gpg/;
268 my(@path) = split /$Config{'path_sep'}/, $ENV{'PATH'};
269 if (!$matcher or "@external_progs" =~ /$matcher/) {
270 $CPAN::Frontend->myprint($prompts{external_progs});
271
272 my $old_warn = $^W;
273 local $^W if $^O eq 'MacOS';
274 local $^W = $old_warn;
275 my $progname;
276 for $progname (@external_progs) {
277 if ($^O eq 'MacOS') {
278 $CPAN::Config->{$progname} = 'not_here';
279 next;
280 }
281 next if $matcher && $progname !~ /$matcher/;
282
283 my $progcall = $progname;
284 # we don't need ncftp if we have ncftpget
285 next if $progname eq "ncftp" && $CPAN::Config->{ncftpget} gt " ";
286 my $path = $CPAN::Config->{$progname}
287 || $Config::Config{$progname}
288 || "";
289 if (File::Spec->file_name_is_absolute($path)) {
290 # testing existence is not good enough, some have these exe
291 # extensions
292
293 # warn "Warning: configured $path does not exist\n" unless -e $path;
294 # $path = "";
295 } elsif ($path =~ /^\s+$/) {
296 # preserve disabled programs
297 } else {
298 $path = '';
299 }
300 unless ($path) {
301 # e.g. make -> nmake
302 $progcall = $Config::Config{$progname} if $Config::Config{$progname};
303 }
09d9d230 304
8962fc49 305 $path ||= find_exe($progcall,[@path]);
306 $CPAN::Frontend->mywarn("Warning: $progcall not found in PATH\n") unless
307 $path; # not -e $path, because find_exe already checked that
308 $ans = prompt("Where is your $progname program?",$path) || $path;
309 $CPAN::Config->{$progname} = $ans;
310 }
5f05dabc 311 }
8962fc49 312
313 if (!$matcher or 'pager' =~ /$matcher/) {
314 my $path = $CPAN::Config->{'pager'} ||
315 $ENV{PAGER} || find_exe("less",[@path]) ||
316 find_exe("more",[@path]) || ($^O eq 'MacOS' ? $ENV{EDITOR} : 0 )
317 || "more";
318 $ans = prompt("What is your favorite pager program?",$path);
319 $CPAN::Config->{'pager'} = $ans;
55e314ee 320 }
8962fc49 321
322 if (!$matcher or 'shell' =~ /$matcher/) {
323 my $path = $CPAN::Config->{'shell'};
324 if (File::Spec->file_name_is_absolute($path)) {
325 $CPAN::Frontend->mywarn("Warning: configured $path does not exist\n")
326 unless -e $path;
327 $path = "";
328 }
329 $path ||= $ENV{SHELL};
330 $path ||= $ENV{COMSPEC} if $^O eq "MSWin32";
331 if ($^O eq 'MacOS') {
332 $CPAN::Config->{'shell'} = 'not_here';
333 } else {
334 $path =~ s,\\,/,g if $^O eq 'os2'; # Cosmetic only
335 $ans = prompt("What is your favorite shell?",$path);
336 $CPAN::Config->{'shell'} = $ans;
337 }
f14b5cec 338 }
da199366 339
340 #
8962fc49 341 #= Installer, arguments to make etc.
da199366 342 #
343
8962fc49 344 if (!$matcher or 'prefer_installer' =~ /$matcher/){
345 $CPAN::Frontend->myprint($prompts{prefer_installer_intro});
e82b9348 346
8962fc49 347 my_prompt_loop(prefer_installer => 'EUMM', $matcher, 'MB|EUMM');
348 }
e82b9348 349
8962fc49 350 if (!$matcher or 'makepl_arg make_arg' =~ /$matcher/){
351 $CPAN::Frontend->myprint($prompts{makepl_arg_intro});
e82b9348 352
8962fc49 353 my_dflt_prompt(makepl_arg => "", $matcher);
354 my_dflt_prompt(make_arg => "", $matcher);
355 }
e82b9348 356
44d21104 357 require CPAN::HandleConfig;
358 if (exists $CPAN::HandleConfig::keys{make_install_make_command}) {
359 # as long as Windows needs $self->_build_command, we cannot
360 # support sudo on windows :-)
361 my_dflt_prompt(make_install_make_command => $CPAN::Config->{make} || "",
362 $matcher);
363 }
e82b9348 364
9ddc4ed0 365 my_dflt_prompt(make_install_arg => $CPAN::Config->{make_arg} || "",
366 $matcher);
e82b9348 367
8962fc49 368 if (!$matcher or 'mbuildpl_arg mbuild_arg' =~ /$matcher/){
369 $CPAN::Frontend->myprint($prompts{mbuildpl_arg_intro});
e82b9348 370
8962fc49 371 my_dflt_prompt(mbuildpl_arg => "", $matcher);
e82b9348 372
8962fc49 373 my_dflt_prompt(mbuild_arg => "", $matcher);
374 }
e82b9348 375
44d21104 376 if (exists $CPAN::HandleConfig::keys{mbuild_install_build_command}) {
377 # as long as Windows needs $self->_build_command, we cannot
378 # support sudo on windows :-)
379 my_dflt_prompt(mbuild_install_build_command => "./Build", $matcher);
380 }
8d97e4a1 381
9ddc4ed0 382 my_dflt_prompt(mbuild_install_arg => "", $matcher);
5f05dabc 383
da199366 384 #
8962fc49 385 #= Alarm period
386 #
387
388 if (!$matcher or 'inactivity_timeout' =~ /$matcher/) {
389 $CPAN::Frontend->myprint($prompts{inactivity_timeout_intro});
390 $default = $CPAN::Config->{inactivity_timeout} || 0;
391 $CPAN::Config->{inactivity_timeout} =
392 prompt("Timeout for inactivity during {Makefile,Build}.PL?",$default);
393 }
394
395 #
396 #= Proxies
da199366 397 #
398
8962fc49 399 my @proxy_vars = qw/ftp_proxy http_proxy no_proxy/;
400 my @proxy_user_vars = qw/proxy_user proxy_pass/;
401 if (!$matcher or "@proxy_vars @proxy_user_vars" =~ /$matcher/){
402 $CPAN::Frontend->myprint($prompts{proxy_intro});
10b2abe6 403
8962fc49 404 for (@proxy_vars) {
405 if (!$matcher or /$matcher/){
406 $default = $CPAN::Config->{$_} || $ENV{$_} || "";
407 $CPAN::Config->{$_} = prompt("Your $_?",$default);
408 }
409 }
10b2abe6 410
8962fc49 411 if ($CPAN::Config->{ftp_proxy} ||
412 $CPAN::Config->{http_proxy}) {
10b2abe6 413
8962fc49 414 $default = $CPAN::Config->{proxy_user} || $CPAN::LWP::UserAgent::USER || "";
da199366 415
8962fc49 416 $CPAN::Frontend->myprint($prompts{proxy_user});
09d9d230 417
8962fc49 418 if ($CPAN::Config->{proxy_user} = prompt("Your proxy user id?",$default)) {
419 $CPAN::Frontend->myprint($prompts{proxy_pass});
c9869e1c 420
8962fc49 421 if ($CPAN::META->has_inst("Term::ReadKey")) {
422 Term::ReadKey::ReadMode("noecho");
423 } else {
424 $CPAN::Frontend->myprint($prompts{password_warn});
425 }
426 $CPAN::Config->{proxy_pass} = prompt_no_strip("Your proxy password?");
427 if ($CPAN::META->has_inst("Term::ReadKey")) {
428 Term::ReadKey::ReadMode("restore");
429 }
430 $CPAN::Frontend->myprint("\n\n");
431 }
432 }
5f05dabc 433 }
434
8962fc49 435 #
436 #= how FTP works
437 #
9ddc4ed0 438
8962fc49 439 my_yn_prompt(ftp_passive => 1, $matcher);
c049f953 440
8962fc49 441 #
442 #= how cwd works
443 #
c049f953 444
8962fc49 445 if (!$matcher or 'getcwd' =~ /$matcher/){
446 $CPAN::Frontend->myprint($prompts{getcwd_intro});
c049f953 447
8962fc49 448 my_prompt_loop(getcwd => 'cwd', $matcher,
449 'cwd|getcwd|fastcwd|backtickcwd');
450 }
451
452 #
453 #= the CPAN shell itself
454 #
455
456 my_yn_prompt(commandnumber_in_prompt => 1, $matcher);
457 my_yn_prompt(term_ornaments => 1, $matcher);
458 if ("colorize_output colorize_print colorize_warn" =~ $matcher) {
459 my_yn_prompt(colorize_output => 0, $matcher);
460 if ($CPAN::Config->{colorize_output}) {
461 for my $tuple (
462 ["colorize_print", "bold blue"],
463 ["colorize_warn", "bold red"],
464 ) {
465 my_dflt_prompt($tuple->[0] => $tuple->[1], $matcher);
466 if ($CPAN::META->has_inst("Term::ANSIColor")) {
467 eval { Term::ANSIColor::color($CPAN::Config->{$tuple->[0]})};
468 if ($@) {
469 $CPAN::Config->{$tuple->[0]} = $tuple->[1];
470 $CPAN::Frontend->mywarn($@."setting to default '$tuple->[1]'\n");
471 }
472 }
c049f953 473 }
c049f953 474 }
475 }
476
09d9d230 477 #
8962fc49 478 #== term_is_latin
479 #
480
481 if (!$matcher or 'term_is_latin' =~ /$matcher/){
482 $CPAN::Frontend->myprint($prompts{term_is_latin});
483 my_yn_prompt(term_is_latin => 1, $matcher);
484 }
485
486 #
487 #== save history in file 'histfile'
488 #
489
490 if (!$matcher or 'histfile histsize' =~ /$matcher/) {
491 $CPAN::Frontend->myprint($prompts{histfile_intro});
492 defined($default = $CPAN::Config->{histfile}) or
493 $default = File::Spec->catfile($CPAN::Config->{cpan_home},"histfile");
494 $ans = prompt("File to save your history?", $default);
495 $CPAN::Config->{histfile} = $ans;
496
497 if ($CPAN::Config->{histfile}) {
498 defined($default = $CPAN::Config->{histsize}) or $default = 100;
499 $ans = prompt("Number of lines to save?", $default);
500 $CPAN::Config->{histsize} = $ans;
501 }
502 }
503
504 #
505 #== do an ls on the m or the d command
506 #
507 if (!$matcher or 'show_upload_date' =~ /$matcher/) {
508 $CPAN::Frontend->myprint($prompts{show_upload_date_intro});
509
510 defined($default = $CPAN::Config->{show_upload_date}) or
511 $default = 'n';
512 $ans = prompt("Always try to show upload date with 'd' and 'm' command (yes/no)?",
513 ($default ? 'yes' : 'no'));
514 $CPAN::Config->{show_upload_date} = ($ans =~ /^[y1]/i ? 1 : 0);
515 }
516
517 #
518 #= MIRRORED.BY and conf_sites()
09d9d230 519 #
520
8962fc49 521 if ($matcher){
522 if ("urllist" =~ $matcher) {
523 # conf_sites would go into endless loop with the smash prompt
524 local *_real_prompt;
525 *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt;
526 conf_sites();
527 }
528 } elsif ($fastread) {
529 $CPAN::Frontend->myprint("Autoconfigured everything but 'urllist'.\n".
530 "Please call 'o conf init urllist' to configure ".
531 "your CPAN server(s) now!");
532 } else {
533 conf_sites();
534 }
09d9d230 535
8962fc49 536 # We don't ask this one now, it's plain silly and maybe is not
537 # even used correctly everywhere.
ca79d794 538 $CPAN::Config->{inhibit_startup_message} = 0;
5f05dabc 539
554a9ef5 540 $CPAN::Frontend->myprint("\n\n");
8962fc49 541 if ($matcher) {
542 $CPAN::Frontend->myprint("Please remember to call 'o conf commit' to ".
543 "make the config permanent!\n\n");
544 } else {
545 CPAN::HandleConfig->commit($configpm);
546 }
5f05dabc 547}
548
9ddc4ed0 549sub my_dflt_prompt {
550 my ($item, $dflt, $m) = @_;
551 my $default = $CPAN::Config->{$item} || $dflt;
552
553 $DB::single = 1;
554 if (!$m || $item =~ /$m/) {
555 $CPAN::Config->{$item} = prompt($prompts{$item}, $default);
556 } else {
557 $CPAN::Config->{$item} = $default;
558 }
559}
560
8962fc49 561sub my_yn_prompt {
562 my ($item, $dflt, $m) = @_;
563 my $default;
564 defined($default = $CPAN::Config->{$item}) or $default = $dflt;
565
566 $DB::single = 1;
567 if (!$m || $item =~ /$m/) {
568 if (my $intro = $prompts{$item . "_intro"}) {
569 $CPAN::Frontend->myprint($intro);
570 }
571 my $ans = prompt($prompts{$item}, $default ? 'yes' : 'no');
572 $CPAN::Config->{$item} = ($ans =~ /^[y1]/i ? 1 : 0);
573 } else {
574 $CPAN::Config->{$item} = $default;
575 }
576}
577
9ddc4ed0 578sub my_prompt_loop {
579 my ($item, $dflt, $m, $ok) = @_;
580 my $default = $CPAN::Config->{$item} || $dflt;
581 my $ans;
582
583 $DB::single = 1;
584 if (!$m || $item =~ /$m/) {
585 do { $ans = prompt($prompts{$item}, $default);
586 } until $ans =~ /$ok/;
587 $CPAN::Config->{$item} = $ans;
588 } else {
589 $CPAN::Config->{$item} = $default;
590 }
591}
592
593
09d9d230 594sub conf_sites {
595 my $m = 'MIRRORED.BY';
5de3f0da 596 my $mby = File::Spec->catfile($CPAN::Config->{keep_source_where},$m);
09d9d230 597 File::Path::mkpath(File::Basename::dirname($mby));
598 if (-f $mby && -f $m && -M $m < -M $mby) {
599 require File::Copy;
600 File::Copy::copy($m,$mby) or die "Could not update $mby: $!";
601 }
911a92db 602 my $loopcount = 0;
de34a54b 603 local $^T = time;
d8773709 604 my $overwrite_local = 0;
605 if ($mby && -f $mby && -M _ <= 60 && -s _ > 0) {
606 my $mtime = localtime((stat _)[9]);
607 my $prompt = qq{Found $mby as of $mtime
608
c049f953 609I\'d use that as a database of CPAN sites. If that is OK for you,
610please answer 'y', but if you want me to get a new database now,
611please answer 'n' to the following question.
d8773709 612
c049f953 613Shall I use the local database in $mby?};
d8773709 614 my $ans = prompt($prompt,"y");
615 $overwrite_local = 1 unless $ans =~ /^y/i;
616 }
de34a54b 617 while ($mby) {
d8773709 618 if ($overwrite_local) {
8962fc49 619 $CPAN::Frontend->myprint(qq{Trying to overwrite $mby\n});
d8773709 620 $mby = CPAN::FTP->localize($m,$mby,3);
621 $overwrite_local = 0;
622 } elsif ( ! -f $mby ){
8962fc49 623 $CPAN::Frontend->myprint(qq{You have no $mby\n I\'m trying to fetch one\n});
36263cb3 624 $mby = CPAN::FTP->localize($m,$mby,3);
911a92db 625 } elsif (-M $mby > 60 && $loopcount == 0) {
8962fc49 626 $CPAN::Frontend->myprint(qq{Your $mby is older than 60 days,\n I\'m trying }.
627 qq{to fetch one\n});
628 $mby = CPAN::FTP->localize($m,$mby,3);
629 $loopcount++;
36263cb3 630 } elsif (-s $mby == 0) {
8962fc49 631 $CPAN::Frontend->myprint(qq{You have an empty $mby,\n I\'m trying to fetch one\n});
36263cb3 632 $mby = CPAN::FTP->localize($m,$mby,3);
633 } else {
634 last;
635 }
09d9d230 636 }
8962fc49 637 local $urllist = [];
09d9d230 638 read_mirrored_by($mby);
de34a54b 639 bring_your_own();
8962fc49 640 $CPAN::Config->{urllist} = $urllist;
09d9d230 641}
642
5f05dabc 643sub find_exe {
644 my($exe,$path) = @_;
55e314ee 645 my($dir);
646 #warn "in find_exe exe[$exe] path[@$path]";
5f05dabc 647 for $dir (@$path) {
5de3f0da 648 my $abs = File::Spec->catfile($dir,$exe);
13bc20ff 649 if (($abs = MM->maybe_command($abs))) {
5f05dabc 650 return $abs;
651 }
652 }
653}
654
f610777f 655sub picklist {
656 my($items,$prompt,$default,$require_nonempty,$empty_warning)=@_;
8962fc49 657 CPAN->debug("picklist('$items','$prompt','$default','$require_nonempty',".
658 "'$empty_warning')") if $CPAN::DEBUG;
f610777f 659 $default ||= '';
660
5fc0f0f6 661 my $pos = 0;
f610777f 662
663 my @nums;
8962fc49 664 SELECTION: while (1) {
ec385757 665
5fc0f0f6 666 # display, at most, 15 items at a time
667 my $limit = $#{ $items } - $pos;
668 $limit = 15 if $limit > 15;
669
670 # show the next $limit items, get the new position
8962fc49 671 $pos = display_some($items, $limit, $pos, $default);
5fc0f0f6 672 $pos = 0 if $pos >= @$items;
673
674 my $num = prompt($prompt,$default);
675
676 @nums = split (' ', $num);
8962fc49 677 {
678 my %seen;
679 @nums = grep { !$seen{$_}++ } @nums;
680 }
5fc0f0f6 681 my $i = scalar @$items;
8962fc49 682 if (grep (/\D/ || $_ < 1 || $_ > $i, @nums)){
683 $CPAN::Frontend->mywarn("invalid items entered, try again\n");
684 if ("@nums" =~ /\D/) {
685 $CPAN::Frontend->mywarn("(we are expecting at least one number between 1 and $i)\n");
686 }
687 next SELECTION;
688 }
689 if ($require_nonempty && !@nums) {
690 $CPAN::Frontend->mywarn("$empty_warning\n");
5fc0f0f6 691 }
8962fc49 692 $CPAN::Frontend->myprint("\n");
5fc0f0f6 693
694 # a blank line continues...
8962fc49 695 next SELECTION unless @nums;
5fc0f0f6 696 last;
f610777f 697 }
f610777f 698 for (@nums) { $_-- }
699 @{$items}[@nums];
700}
701
ec385757 702sub display_some {
8962fc49 703 my ($items, $limit, $pos, $default) = @_;
704 $pos ||= 0;
ec385757 705
8962fc49 706 my @displayable = @$items[$pos .. ($pos + $limit)];
ec385757 707 for my $item (@displayable) {
8962fc49 708 $CPAN::Frontend->myprint(sprintf "(%d) %s\n", ++$pos, $item);
ec385757 709 }
8962fc49 710 my $hit_what = $default ? "SPACE RETURN" : "RETURN";
711 $CPAN::Frontend->myprint(sprintf("%d more items, hit %s to show them\n",
712 (@$items - $pos),
713 $hit_what,
714 ))
715 if $pos < @$items;
716 return $pos;
ec385757 717}
718
5f05dabc 719sub read_mirrored_by {
de34a54b 720 my $local = shift or return;
9ddc4ed0 721 my(%all,$url,$expected_size,$default,$ans,$host,
722 $dst,$country,$continent,@location);
05454584 723 my $fh = FileHandle->new;
724 $fh->open($local) or die "Couldn't open $local: $!";
f14b5cec 725 local $/ = "\012";
05454584 726 while (<$fh>) {
5f05dabc 727 ($host) = /^([\w\.\-]+)/ unless defined $host;
728 next unless defined $host;
729 next unless /\s+dst_(dst|location)/;
730 /location\s+=\s+\"([^\"]+)/ and @location = (split /\s*,\s*/, $1) and
731 ($continent, $country) = @location[-1,-2];
732 $continent =~ s/\s\(.*//;
f610777f 733 $continent =~ s/\W+$//; # if Jarkko doesn't know latitude/longitude
5f05dabc 734 /dst_dst\s+=\s+\"([^\"]+)/ and $dst = $1;
735 next unless $host && $dst && $continent && $country;
736 $all{$continent}{$country}{$dst} = CPAN::Mirrored::By->new($continent,$country,$dst);
737 undef $host;
738 $dst=$continent=$country="";
739 }
05454584 740 $fh->close;
5f05dabc 741 $CPAN::Config->{urllist} ||= [];
8962fc49 742 my @previous_urls = @{$CPAN::Config->{urllist}};
f610777f 743
8962fc49 744 $CPAN::Frontend->myprint($prompts{urls_intro});
5f05dabc 745
f610777f 746 my (@cont, $cont, %cont, @countries, @urls, %seen);
8962fc49 747 my $no_previous_warn =
748 "Sorry! since you don't have any existing picks, you must make a\n" .
749 "geographic selection.";
750 my $offer_cont = [sort keys %all];
751 if (@previous_urls) {
752 push @$offer_cont, "(edit previous picks)";
753 $default = @$offer_cont;
754 }
755 @cont = picklist($offer_cont,
f610777f 756 "Select your continent (or several nearby continents)",
8962fc49 757 $default,
f610777f 758 ! @previous_urls,
759 $no_previous_warn);
760
761
762 foreach $cont (@cont) {
763 my @c = sort keys %{$all{$cont}};
764 @cont{@c} = map ($cont, 0..$#c);
765 @c = map ("$_ ($cont)", @c) if @cont > 1;
766 push (@countries, @c);
5f05dabc 767 }
8962fc49 768 if (@previous_urls && @countries) {
769 push @countries, "(edit previous picks)";
770 $default = @countries;
771 }
f610777f 772
773 if (@countries) {
774 @countries = picklist (\@countries,
775 "Select your country (or several nearby countries)",
8962fc49 776 $default,
f610777f 777 ! @previous_urls,
778 $no_previous_warn);
779 %seen = map (($_ => 1), @previous_urls);
780 # hmmm, should take list of defaults from CPAN::Config->{'urllist'}...
781 foreach $country (@countries) {
8962fc49 782 next if $country =~ /edit previous picks/;
f610777f 783 (my $bare_country = $country) =~ s/ \(.*\)//;
784 my @u = sort keys %{$all{$cont{$bare_country}}{$bare_country}};
785 @u = grep (! $seen{$_}, @u);
786 @u = map ("$_ ($bare_country)", @u)
8962fc49 787 if @countries > 1;
f610777f 788 push (@urls, @u);
789 }
790 }
791 push (@urls, map ("$_ (previous pick)", @previous_urls));
5fc0f0f6 792 my $prompt = "Select as many URLs as you like (by number),
793put them on one line, separated by blanks, e.g. '1 4 5'";
f610777f 794 if (@previous_urls) {
8962fc49 795 $default = join (' ', ((scalar @urls) - (scalar @previous_urls) + 1) ..
796 (scalar @urls));
797 $prompt .= "\n(or just hit RETURN to keep your previous picks)";
f610777f 798 }
799
800 @urls = picklist (\@urls, $prompt, $default);
801 foreach (@urls) { s/ \(.*\)//; }
8962fc49 802 push @$urllist, @urls;
de34a54b 803}
f610777f 804
de34a54b 805sub bring_your_own {
8962fc49 806 my %seen = map (($_ => 1), @$urllist);
de34a54b 807 my($ans,@urls);
f610777f 808 do {
de34a54b 809 my $prompt = "Enter another URL or RETURN to quit:";
810 unless (%seen) {
811 $prompt = qq{CPAN.pm needs at least one URL where it can fetch CPAN files from.
812
813Please enter your CPAN site:};
814 }
815 $ans = prompt ($prompt, "");
f610777f 816
817 if ($ans) {
de34a54b 818 $ans =~ s|/?\z|/|; # has to end with one slash
f610777f 819 $ans = "file:$ans" unless $ans =~ /:/; # without a scheme is a file:
820 if ($ans =~ /^\w+:\/./) {
8d97e4a1 821 push @urls, $ans unless $seen{$ans}++;
de34a54b 822 } else {
8962fc49 823 $CPAN::Frontend->
824 myprint(sprintf(qq{"%s" doesn\'t look like an URL at first sight.
8d97e4a1 825I\'ll ignore it for now.
826You can add it to your %s
827later if you\'re sure it\'s right.\n},
8962fc49 828 $ans,
829 $INC{'CPAN/MyConfig.pm'}
830 || $INC{'CPAN/Config.pm'}
831 || "configuration file",
832 ));
f610777f 833 }
834 }
de34a54b 835 } while $ans || !%seen;
f610777f 836
8962fc49 837 push @$urllist, @urls;
f610777f 838 # xxx delete or comment these out when you're happy that it works
8962fc49 839 $CPAN::Frontend->myprint("New set of picks:\n");
840 map { $CPAN::Frontend->myprint(" $_\n") } @$urllist;
5f05dabc 841}
842
f915a99a 843
844sub _strip_spaces {
845 $_[0] =~ s/^\s+//; # no leading spaces
846 $_[0] =~ s/\s+\z//; # no trailing spaces
847}
848
f915a99a 849sub prompt ($;$) {
7fefbd44 850 unless (defined &_real_prompt) {
851 *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt;
852 }
f915a99a 853 my $ans = _real_prompt(@_);
854
855 _strip_spaces($ans);
856
857 return $ans;
858}
859
860
861sub prompt_no_strip ($;$) {
862 return _real_prompt(@_);
863}
864
865
9ddc4ed0 866BEGIN {
867
868my @prompts = (
869
870manual_config => qq[
871
872CPAN is the world-wide archive of perl resources. It consists of about
8962fc49 873300 sites that all replicate the same contents around the globe. Many
874countries have at least one CPAN site already. The resources found on
875CPAN are easily accessible with the CPAN.pm module. If you want to use
876CPAN.pm, lots of things have to be configured. Fortunately, most of
877them can be determined automatically. If you prefer the automatic
878configuration, answer 'yes' below.
879
880If you prefer to enter a dialog instead, you can answer 'no' to this
881question and I'll let you configure in small steps one thing after the
882other. (Note: you can revisit this dialog anytime later by typing 'o
883conf init' at the cpan prompt.)
9ddc4ed0 884
885],
886
887config_intro => qq{
888
889The following questions are intended to help you with the
890configuration. The CPAN module needs a directory of its own to cache
891important index files and maybe keep a temporary mirror of CPAN files.
892This may be a site-wide directory or a personal directory.
893
894},
895
896# cpan_home => qq{ },
897
898cpan_home_where => qq{
899
900First of all, I\'d like to create this directory. Where?
901
902},
903
904keep_source_where => qq{
905
8962fc49 906Unless you are accessing the CPAN via the filesystem directly CPAN.pm
907needs to keep the source files it downloads somewhere. Please supply a
908directory where the downloaded files are to be kept.},
9ddc4ed0 909
910build_cache_intro => qq{
911
912How big should the disk cache be for keeping the build directories
913with all the intermediate files\?
914
915},
916
917build_cache =>
918"Cache size for build directory (in MB)?",
919
8962fc49 920build_dir =>
921
922"Directory where the build process takes place?",
9ddc4ed0 923
924scan_cache_intro => qq{
925
926By default, each time the CPAN module is started, cache scanning is
927performed to keep the cache size in sync. To prevent this, answer
928'never'.
929
930},
931
932scan_cache => "Perform cache scanning (atstart or never)?",
933
8962fc49 934cache_metadata_intro => qq{
9ddc4ed0 935
936To considerably speed up the initial CPAN shell startup, it is
937possible to use Storable to create a cache of metadata. If Storable
938is not available, the normal index mechanism will be used.
939
940},
941
8962fc49 942cache_metadata => qq{Cache metadata (yes/no)?},
943
944term_is_latin_intro => qq{
9ddc4ed0 945
946The next option deals with the charset (aka character set) your
947terminal supports. In general, CPAN is English speaking territory, so
948the charset does not matter much, but some of the aliens out there who
949upload their software to CPAN bear names that are outside the ASCII
950range. If your terminal supports UTF-8, you should say no to the next
951question. If it supports ISO-8859-1 (also known as LATIN1) then you
952should say yes. If it supports neither, your answer does not matter
953because you will not be able to read the names of some authors
954anyway. If you answer no, names will be output in UTF-8.
955
956},
957
8962fc49 958term_is_latin => qq{Your terminal expects ISO-8859-1 (yes/no)?},
959
c9869e1c 960histfile_intro => qq{
9ddc4ed0 961
962If you have one of the readline packages (Term::ReadLine::Perl,
963Term::ReadLine::Gnu, possibly others) installed, the interactive CPAN
964shell will have history support. The next two questions deal with the
965filename of the history file and with its size. If you do not want to
966set this variable, please hit SPACE RETURN to the following question.
967
968},
969
c9869e1c 970histfile => qq{File to save your history?},
971
9ddc4ed0 972show_upload_date_intro => qq{
973
974The 'd' and the 'm' command normally only show you information they
975have in their in-memory database and thus will never connect to the
976internet. If you set the 'show_upload_date' variable to true, 'm' and
977'd' will additionally show you the upload date of the module or
978distribution. Per default this feature is off because it may require a
979net connection to get at the upload date.
980
981},
982
983show_upload_date =>
984"Always try to show upload date with 'd' and 'm' command (yes/no)?",
985
986prerequisites_policy_intro => qq{
987
988The CPAN module can detect when a module which you are trying to build
989depends on prerequisites. If this happens, it can build the
990prerequisites for you automatically ('follow'), ask you for
991confirmation ('ask'), or just ignore them ('ignore'). Please set your
992policy to one of the three values.
993
994},
995
996prerequisites_policy =>
c9869e1c 997"Policy on building prerequisites (follow, ask or ignore)?",
9ddc4ed0 998
ed84aac9 999check_sigs_intro => qq{
1000
1001CPAN packages can be digitally signed by authors and thus verified
1002with the security provided by strong cryptography. The exact mechanism
1003is defined in the Module::Signature module. While this is generally
1004considered a good thing, it is not always convenient to the end user
1005to install modules that are signed incorrectly or where the key of the
1006author is not available or where some prerequisite for
1007Module::Signature has a bug and so on.
1008
1009With the check_sigs parameter you can turn signature checking on and
1010off. The default is off for now because the whole tool chain for the
1011functionality is not yet considered mature by some. The author of
1012CPAN.pm would recommend setting it to true most of the time and
1013turning it off only if it turns out to be annoying.
1014
1015Note that if you do not have Module::Signature installed, no signature
1016checks will be performed at all.
1017
1018},
1019
1020check_sigs =>
1021qq{Always try to check and verify signatures if a SIGNATURE file is in the package
1022and Module::Signature is installed (yes/no)?},
1023
8962fc49 1024test_report_intro =>
1025qq{
1026
1027The goal of the CPAN Testers project (http://testers.cpan.org/) is to
1028test as many CPAN packages as possible on as many platforms as
1029possible. This provides valuable feedback to module authors and
1030potential users to identify bugs or platform compatibility issues and
1031improves the overall quality and value of CPAN.
1032
1033One way you can contribute is to send test results for each module
1034that you install. If you install the CPAN::Reporter module, you have
1035the option to automatically generate and email test reports to CPAN
1036Testers whenever you run tests on a CPAN package.
1037
1038See the CPAN::Reporter documentation for additional details and
1039configuration settings. If your firewall blocks outgoing email,
1040you will need to configure CPAN::Reporter before sending reports.
1041
1042},
1043
1044test_report =>
1045qq{Email test reports if CPAN::Reporter is installed (yes/no)?},
1046
9ddc4ed0 1047external_progs => qq{
1048
1049The CPAN module will need a few external programs to work properly.
1050Please correct me, if I guess the wrong path for a program. Don\'t
1051panic if you do not have some of them, just press ENTER for those. To
8962fc49 1052disable the use of a program, you can type a space followed by ENTER.
9ddc4ed0 1053
1054},
1055
1056prefer_installer_intro => qq{
1057
1058When you have Module::Build installed and a module comes with both a
1059Makefile.PL and a Build.PL, which shall have precedence? The two
1060installer modules we have are the old and well established
8962fc49 1061ExtUtils::MakeMaker (for short: EUMM) which uses the Makefile.PL and
9ddc4ed0 1062the next generation installer Module::Build (MB) works with the
1063Build.PL.
1064
1065},
1066
1067prefer_installer =>
1068qq{In case you could choose, which installer would you prefer (EUMM or MB)?},
1069
1070makepl_arg_intro => qq{
1071
1072Every Makefile.PL is run by perl in a separate process. Likewise we
1073run \'make\' and \'make install\' in separate processes. If you have
1074any parameters \(e.g. PREFIX, LIB, UNINST or the like\) you want to
1075pass to the calls, please specify them here.
1076
1077If you don\'t understand this question, just press ENTER.
1078},
1079
1080makepl_arg => qq{
1081Parameters for the 'perl Makefile.PL' command?
1082Typical frequently used settings:
1083
1084 PREFIX=~/perl # non-root users (please see manual for more hints)
1085
1086Your choice: },
1087
1088make_arg => qq{Parameters for the 'make' command?
1089Typical frequently used setting:
1090
1091 -j3 # dual processor system
1092
1093Your choice: },
1094
1095
1096make_install_make_command => qq{Do you want to use a different make command for 'make install'?
1097Cautious people will probably prefer:
1098
1099 su root -c make
1100or
1101 sudo make
1102or
1103 /path1/to/sudo -u admin_account /path2/to/make
1104
1105or some such. Your choice: },
1106
1107
1108make_install_arg => qq{Parameters for the 'make install' command?
1109Typical frequently used setting:
1110
1111 UNINST=1 # to always uninstall potentially conflicting files
1112
1113Your choice: },
1114
1115
1116mbuildpl_arg_intro => qq{
1117
1118The next questions deal with Module::Build support.
1119
1120A Build.PL is run by perl in a separate process. Likewise we run
1121'./Build' and './Build install' in separate processes. If you have any
1122parameters you want to pass to the calls, please specify them here.
1123
1124},
1125
1126mbuildpl_arg => qq{Parameters for the 'perl Build.PL' command?
1127Typical frequently used settings:
1128
1129 --install_base /home/xxx # different installation directory
1130
1131Your choice: },
1132
1133mbuild_arg => qq{Parameters for the './Build' command?
1134Setting might be:
1135
1136 --extra_linker_flags -L/usr/foo/lib # non-standard library location
1137
1138Your choice: },
1139
1140
1141mbuild_install_build_command => qq{Do you want to use a different command for './Build install'?
1142Sudo users will probably prefer:
1143
1144 su root -c ./Build
1145or
1146 sudo ./Build
1147or
1148 /path1/to/sudo -u admin_account ./Build
1149
1150or some such. Your choice: },
1151
1152
1153mbuild_install_arg => qq{Parameters for the './Build install' command?
1154Typical frequently used setting:
1155
1156 --uninst 1 # uninstall conflicting files
1157
1158Your choice: },
1159
1160
1161
1162inactivity_timeout_intro => qq{
1163
1164Sometimes you may wish to leave the processes run by CPAN alone
8962fc49 1165without caring about them. Because the Makefile.PL or the Build.PL
1166sometimes contains question you\'re expected to answer, you can set a
1167timer that will kill a 'perl Makefile.PL' process after the specified
1168time in seconds.
9ddc4ed0 1169
1170If you set this value to 0, these processes will wait forever. This is
1171the default and recommended setting.
1172
1173},
1174
1175inactivity_timeout =>
1176qq{Timeout for inactivity during {Makefile,Build}.PL? },
1177
1178
c9869e1c 1179proxy_intro => qq{
9ddc4ed0 1180
1181If you\'re accessing the net via proxies, you can specify them in the
1182CPAN configuration or via environment variables. The variable in
1183the \$CPAN::Config takes precedence.
1184
1185},
1186
1187proxy_user => qq{
1188
1189If your proxy is an authenticating proxy, you can store your username
1190permanently. If you do not want that, just press RETURN. You will then
1191be asked for your username in every future session.
1192
1193},
1194
1195proxy_pass => qq{
1196
1197Your password for the authenticating proxy can also be stored
1198permanently on disk. If this violates your security policy, just press
1199RETURN. You will then be asked for the password in every future
1200session.
1201
1202},
1203
1204urls_intro => qq{
1205
1206Now we need to know where your favorite CPAN sites are located. Push
1207a few sites onto the array (just in case the first on the array won\'t
1208work). If you are mirroring CPAN to your local workstation, specify a
1209file: URL.
1210
8962fc49 1211First, pick a nearby continent and country by typing in the number(s)
1212in front of the item(s) you want to select. You can pick several of
1213each, separated by spaces. Then, you will be presented with a list of
1214URLs of CPAN mirrors in the countries you selected, along with
1215previously selected URLs. Select some of those URLs, or just keep the
1216old list. Finally, you will be prompted for any extra URLs -- file:,
1217ftp:, or http: -- that host a CPAN mirror.
9ddc4ed0 1218
1219},
1220
1221password_warn => qq{
1222
1223Warning: Term::ReadKey seems not to be available, your password will
1224be echoed to the terminal!
1225
1226},
1227
8962fc49 1228commandnumber_in_prompt => qq{
1229
1230The prompt of the cpan shell can contain the current command number
1231for easier tracking of the session or be a plain string. Do you want
1232the command number in the prompt (yes/no)?},
1233
1234ftp_passive => qq{
1235
1236Shall we always set FTP_PASSIVE envariable when dealing with ftp
1237download (yes/no)?},
1238
1239# taken from the manpage:
1240getcwd_intro => qq{
1241
1242CPAN.pm changes the current working directory often and needs to
1243determine its own current working directory. Per default it uses
1244Cwd::cwd but if this doesn't work on your system for some reason,
1245alternatives can be configured according to the following table:
1246
1247 cwd Cwd::cwd
1248 getcwd Cwd::getcwd
1249 fastcwd Cwd::fastcwd
1250 backtickcwd external command cwd
1251
1252},
1253
1254getcwd => qq{Preferred method for determining the current working directory?},
1255
1256index_expire_intro => qq{
1257
1258The CPAN indexes are usually rebuilt once or twice per hour, but the
1259typical CPAN mirror mirrors only once or twice per day. Depending on
1260the quality of your mirror and your desire to be on the bleeding edge,
1261you may want to set the following value to more or less than one day
1262(which is the default). It determines after how many days CPAN.pm
1263downloads new indexes.
1264
1265},
1266
1267index_expire => qq{Let the index expire after how many days?},
1268
1269term_ornaments => qq{
1270
1271When using Term::ReadLine, you can turn ornaments on so that your
1272input stands out against the output from CPAN.pm. Do you want to turn
1273ornaments on?},
1274
1275colorize_output => qq{
1276
1277When you have Term::ANSIColor installed, you can turn on colorized
1278output to have some visual differences between normal CPAN.pm output,
1279warnings, and the output of the modules being installed. Set your
1280favorite colors after some experimenting with the Term::ANSIColor
1281module. Do you want to turn on colored output?},
1282
1283colorize_print => qq{Color for normal output?},
1284
1285colorize_warn => qq{Color for warnings?},
1286
9ddc4ed0 1287);
1288
1289die "Coding error in \@prompts declaration. Odd number of elements, above"
1290 if (@prompts % 2);
1291
1292%prompts = @prompts;
1293
1294if (scalar(keys %prompts) != scalar(@prompts)/2) {
9ddc4ed0 1295 my %already;
9ddc4ed0 1296 for my $item (0..$#prompts) {
1297 next if $item % 2;
8962fc49 1298 die "$prompts[$item] is duplicated\n" if $already{$prompts[$item]}++;
9ddc4ed0 1299 }
9ddc4ed0 1300}
1301
8962fc49 1302} # EOBEGIN
9ddc4ed0 1303
5f05dabc 13041;