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