- Moved unused argc, temp variable into small scope.
[dragonfly.git] / contrib / perl5 / lib / CPAN / FirstTime.pm
1 package CPAN::Mirrored::By;
2
3 sub new { 
4     my($self,@arg) = @_;
5     bless [@arg], $self;
6 }
7 sub continent { shift->[0] }
8 sub country { shift->[1] }
9 sub url { shift->[2] }
10
11 package CPAN::FirstTime;
12
13 use strict;
14 use ExtUtils::MakeMaker qw(prompt);
15 use FileHandle ();
16 use File::Basename ();
17 use File::Path ();
18 use vars qw($VERSION);
19 $VERSION = substr q$Revision: 1.36 $, 10;
20
21 =head1 NAME
22
23 CPAN::FirstTime - Utility for CPAN::Config file Initialization
24
25 =head1 SYNOPSIS
26
27 CPAN::FirstTime::init()
28
29 =head1 DESCRIPTION
30
31 The init routine asks a few questions and writes a CPAN::Config
32 file. Nothing special.
33
34 =cut
35
36
37 sub init {
38     my($configpm) = @_;
39     use Config;
40     unless ($CPAN::VERSION) {
41         require CPAN::Nox;
42     }
43     eval {require CPAN::Config;};
44     $CPAN::Config ||= {};
45     local($/) = "\n";
46     local($\) = "";
47     local($|) = 1;
48
49     my($ans,$default,$local,$cont,$url,$expected_size);
50
51     #
52     # Files, directories
53     #
54
55     print qq[
56
57 CPAN is the world-wide archive of perl resources. It consists of about
58 100 sites that all replicate the same contents all around the globe.
59 Many countries have at least one CPAN site already. The resources
60 found on CPAN are easily accessible with the CPAN.pm module. If you
61 want to use CPAN.pm, you have to configure it properly.
62
63 If you do not want to enter a dialog now, you can answer 'no' to this
64 question and I\'ll try to autoconfigure. (Note: you can revisit this
65 dialog anytime later by typing 'o conf init' at the cpan prompt.)
66
67 ];
68
69     my $manual_conf =
70         ExtUtils::MakeMaker::prompt("Are you ready for manual configuration?",
71                                     "yes");
72     my $fastread;
73     {
74       local $^W;
75       if ($manual_conf =~ /^\s*y/i) {
76         $fastread = 0;
77         *prompt = \&ExtUtils::MakeMaker::prompt;
78       } else {
79         $fastread = 1;
80         *prompt = sub {
81           my($q,$a) = @_;
82           my($ret) = defined $a ? $a : "";
83           printf qq{%s [%s]\n\n}, $q, $ret;
84           $ret;
85         };
86       }
87     }
88     print qq{
89
90 The following questions are intended to help you with the
91 configuration. The CPAN module needs a directory of its own to cache
92 important index files and maybe keep a temporary mirror of CPAN files.
93 This may be a site-wide directory or a personal directory.
94
95 };
96
97     my $cpan_home = $CPAN::Config->{cpan_home} || MM->catdir($ENV{HOME}, ".cpan");
98     if (-d $cpan_home) {
99         print qq{
100
101 I see you already have a  directory
102     $cpan_home
103 Shall we use it as the general CPAN build and cache directory?
104
105 };
106     } else {
107         print qq{
108
109 First of all, I\'d like to create this directory. Where?
110
111 };
112     }
113
114     $default = $cpan_home;
115     while ($ans = prompt("CPAN build and cache directory?",$default)) {
116       eval { File::Path::mkpath($ans); }; # dies if it can't
117       if ($@) {
118         warn "Couldn't create directory $ans.
119 Please retry.\n";
120         next;
121       }
122       if (-d $ans && -w _) {
123         last;
124       } else {
125         warn "Couldn't find directory $ans
126   or directory is not writable. Please retry.\n";
127       }
128     }
129     $CPAN::Config->{cpan_home} = $ans;
130
131     print qq{
132
133 If you want, I can keep the source files after a build in the cpan
134 home directory. If you choose so then future builds will take the
135 files from there. If you don\'t want to keep them, answer 0 to the
136 next question.
137
138 };
139
140     $CPAN::Config->{keep_source_where} = MM->catdir($CPAN::Config->{cpan_home},"sources");
141     $CPAN::Config->{build_dir} = MM->catdir($CPAN::Config->{cpan_home},"build");
142
143     #
144     # Cache size, Index expire
145     #
146
147     print qq{
148
149 How big should the disk cache be for keeping the build directories
150 with all the intermediate files?
151
152 };
153
154     $default = $CPAN::Config->{build_cache} || 10;
155     $ans = prompt("Cache size for build directory (in MB)?", $default);
156     $CPAN::Config->{build_cache} = $ans;
157
158     # XXX This the time when we refetch the index files (in days)
159     $CPAN::Config->{'index_expire'} = 1;
160
161     print qq{
162
163 By default, each time the CPAN module is started, cache scanning
164 is performed to keep the cache size in sync. To prevent from this,
165 disable the cache scanning with 'never'.
166
167 };
168
169     $default = $CPAN::Config->{scan_cache} || 'atstart';
170     do {
171         $ans = prompt("Perform cache scanning (atstart or never)?", $default);
172     } while ($ans ne 'atstart' && $ans ne 'never');
173     $CPAN::Config->{scan_cache} = $ans;
174
175     #
176     # prerequisites_policy
177     # Do we follow PREREQ_PM?
178     #
179     print qq{
180
181 The CPAN module can detect when a module that which you are trying to
182 build depends on prerequisites. If this happens, it can build the
183 prerequisites for you automatically ('follow'), ask you for
184 confirmation ('ask'), or just ignore them ('ignore'). Please set your
185 policy to one of the three values.
186
187 };
188
189     $default = $CPAN::Config->{prerequisites_policy} || 'follow';
190     do {
191       $ans =
192           prompt("Policy on building prerequisites (follow, ask or ignore)?",
193                  $default);
194     } while ($ans ne 'follow' && $ans ne 'ask' && $ans ne 'ignore');
195     $CPAN::Config->{prerequisites_policy} = $ans;
196
197     #
198     # External programs
199     #
200
201     print qq{
202
203 The CPAN module will need a few external programs to work
204 properly. Please correct me, if I guess the wrong path for a program.
205 Don\'t panic if you do not have some of them, just press ENTER for
206 those.
207
208 };
209
210     my $old_warn = $^W;
211     local $^W if $^O eq 'MacOS';
212     my(@path) = split /$Config{'path_sep'}/, $ENV{'PATH'};
213     local $^W = $old_warn;
214     my $progname;
215     for $progname (qw/gzip tar unzip make lynx ncftpget ncftp ftp/){
216       if ($^O eq 'MacOS') {
217           $CPAN::Config->{$progname} = 'not_here';
218           next;
219       }
220       my $progcall = $progname;
221       # we don't need ncftp if we have ncftpget
222       next if $progname eq "ncftp" && $CPAN::Config->{ncftpget} gt " ";
223       my $path = $CPAN::Config->{$progname} 
224           || $Config::Config{$progname}
225               || "";
226       if (MM->file_name_is_absolute($path)) {
227         # testing existence is not good enough, some have these exe
228         # extensions
229
230         # warn "Warning: configured $path does not exist\n" unless -e $path;
231         # $path = "";
232       } else {
233         $path = '';
234       }
235       unless ($path) {
236         # e.g. make -> nmake
237         $progcall = $Config::Config{$progname} if $Config::Config{$progname};
238       }
239
240       $path ||= find_exe($progcall,[@path]);
241       warn "Warning: $progcall not found in PATH\n" unless
242           $path; # not -e $path, because find_exe already checked that
243       $ans = prompt("Where is your $progname program?",$path) || $path;
244       $CPAN::Config->{$progname} = $ans;
245     }
246     my $path = $CPAN::Config->{'pager'} || 
247         $ENV{PAGER} || find_exe("less",[@path]) || 
248             find_exe("more",[@path]) || ($^O eq 'MacOS' ? $ENV{EDITOR} : 0 )
249             || "more";
250     $ans = prompt("What is your favorite pager program?",$path);
251     $CPAN::Config->{'pager'} = $ans;
252     $path = $CPAN::Config->{'shell'};
253     if (MM->file_name_is_absolute($path)) {
254         warn "Warning: configured $path does not exist\n" unless -e $path;
255         $path = "";
256     }
257     $path ||= $ENV{SHELL};
258     if ($^O eq 'MacOS') {
259         $CPAN::Config->{'shell'} = 'not_here';
260     } else {
261         $path =~ s,\\,/,g if $^O eq 'os2';      # Cosmetic only
262         $ans = prompt("What is your favorite shell?",$path);
263         $CPAN::Config->{'shell'} = $ans;
264     }
265
266     #
267     # Arguments to make etc.
268     #
269
270     print qq{
271
272 Every Makefile.PL is run by perl in a separate process. Likewise we
273 run \'make\' and \'make install\' in processes. If you have any parameters
274 \(e.g. PREFIX, INSTALLPRIVLIB, UNINST or the like\) you want to pass to
275 the calls, please specify them here.
276
277 If you don\'t understand this question, just press ENTER.
278
279 };
280
281     $default = $CPAN::Config->{makepl_arg} || "";
282     $CPAN::Config->{makepl_arg} =
283         prompt("Parameters for the 'perl Makefile.PL' command?",$default);
284     $default = $CPAN::Config->{make_arg} || "";
285     $CPAN::Config->{make_arg} = prompt("Parameters for the 'make' command?",$default);
286
287     $default = $CPAN::Config->{make_install_arg} || $CPAN::Config->{make_arg} || "";
288     $CPAN::Config->{make_install_arg} =
289         prompt("Parameters for the 'make install' command?",$default);
290
291     #
292     # Alarm period
293     #
294
295     print qq{
296
297 Sometimes you may wish to leave the processes run by CPAN alone
298 without caring about them. As sometimes the Makefile.PL contains
299 question you\'re expected to answer, you can set a timer that will
300 kill a 'perl Makefile.PL' process after the specified time in seconds.
301
302 If you set this value to 0, these processes will wait forever. This is
303 the default and recommended setting.
304
305 };
306
307     $default = $CPAN::Config->{inactivity_timeout} || 0;
308     $CPAN::Config->{inactivity_timeout} =
309         prompt("Timeout for inactivity during Makefile.PL?",$default);
310
311     # Proxies
312
313     print qq{
314
315 If you\'re accessing the net via proxies, you can specify them in the
316 CPAN configuration or via environment variables. The variable in
317 the \$CPAN::Config takes precedence.
318
319 };
320
321     for (qw/ftp_proxy http_proxy no_proxy/) {
322         $default = $CPAN::Config->{$_} || $ENV{$_};
323         $CPAN::Config->{$_} = prompt("Your $_?",$default);
324     }
325
326     #
327     # MIRRORED.BY
328     #
329
330     conf_sites() unless $fastread;
331
332     unless (@{$CPAN::Config->{'wait_list'}||[]}) {
333         print qq{
334
335 WAIT support is available as a Plugin. You need the CPAN::WAIT module
336 to actually use it.  But we need to know your favorite WAIT server. If
337 you don\'t know a WAIT server near you, just press ENTER.
338
339 };
340         $default = "wait://ls6.informatik.uni-dortmund.de:1404";
341         $ans = prompt("Your favorite WAIT server?\n  ",$default);
342         push @{$CPAN::Config->{'wait_list'}}, $ans;
343     }
344
345     # We don't ask that now, it will be noticed in time, won't it?
346     $CPAN::Config->{'inhibit_startup_message'} = 0;
347     $CPAN::Config->{'getcwd'} = 'cwd';
348
349     print "\n\n";
350     CPAN::Config->commit($configpm);
351 }
352
353 sub conf_sites {
354   my $m = 'MIRRORED.BY';
355   my $mby = MM->catfile($CPAN::Config->{keep_source_where},$m);
356   File::Path::mkpath(File::Basename::dirname($mby));
357   if (-f $mby && -f $m && -M $m < -M $mby) {
358     require File::Copy;
359     File::Copy::copy($m,$mby) or die "Could not update $mby: $!";
360   }
361   if ( ! -f $mby ){
362     print qq{You have no $mby
363   I\'m trying to fetch one
364 };
365     $mby = CPAN::FTP->localize($m,$mby,3);
366   } elsif (-M $mby > 30 ) {
367     print qq{Your $mby is older than 30 days,
368   I\'m trying to fetch one
369 };
370     $mby = CPAN::FTP->localize($m,$mby,3);
371   }
372   read_mirrored_by($mby);
373 }
374
375 sub find_exe {
376     my($exe,$path) = @_;
377     my($dir);
378     #warn "in find_exe exe[$exe] path[@$path]";
379     for $dir (@$path) {
380         my $abs = MM->catfile($dir,$exe);
381         if (($abs = MM->maybe_command($abs))) {
382             return $abs;
383         }
384     }
385 }
386
387 sub picklist {
388     my($items,$prompt,$default,$require_nonempty,$empty_warning)=@_;
389     $default ||= '';
390
391     my ($item, $i);
392     for $item (@$items) {
393         printf "(%d) %s\n", ++$i, $item;
394     }
395
396     my @nums;
397     while (1) {
398         my $num = prompt($prompt,$default);
399         @nums = split (' ', $num);
400         (warn "invalid items entered, try again\n"), next
401             if grep (/\D/ || $_ < 1 || $_ > $i, @nums);
402         if ($require_nonempty) {
403             (warn "$empty_warning\n"), next
404                 unless @nums;
405         }
406         last;
407     }
408     print "\n";
409     for (@nums) { $_-- }
410     @{$items}[@nums];
411 }
412
413 sub read_mirrored_by {
414     my($local) = @_;
415     my(%all,$url,$expected_size,$default,$ans,$host,$dst,$country,$continent,@location);
416     my $fh = FileHandle->new;
417     $fh->open($local) or die "Couldn't open $local: $!";
418     local $/ = "\012";
419     while (<$fh>) {
420         ($host) = /^([\w\.\-]+)/ unless defined $host;
421         next unless defined $host;
422         next unless /\s+dst_(dst|location)/;
423         /location\s+=\s+\"([^\"]+)/ and @location = (split /\s*,\s*/, $1) and
424             ($continent, $country) = @location[-1,-2];
425         $continent =~ s/\s\(.*//;
426         $continent =~ s/\W+$//; # if Jarkko doesn't know latitude/longitude
427         /dst_dst\s+=\s+\"([^\"]+)/  and $dst = $1;
428         next unless $host && $dst && $continent && $country;
429         $all{$continent}{$country}{$dst} = CPAN::Mirrored::By->new($continent,$country,$dst);
430         undef $host;
431         $dst=$continent=$country="";
432     }
433     $fh->close;
434     $CPAN::Config->{urllist} ||= [];
435     my(@previous_urls);
436     if (@previous_urls = @{$CPAN::Config->{urllist}}) {
437         $CPAN::Config->{urllist} = [];
438     }
439
440     print qq{
441
442 Now we need to know where your favorite CPAN sites are located. Push
443 a few sites onto the array (just in case the first on the array won\'t
444 work). If you are mirroring CPAN to your local workstation, specify a
445 file: URL.
446
447 First, pick a nearby continent and country (you can pick several of
448 each, separated by spaces, or none if you just want to keep your
449 existing selections). Then, you will be presented with a list of URLs
450 of CPAN mirrors in the countries you selected, along with previously
451 selected URLs. Select some of those URLs, or just keep the old list.
452 Finally, you will be prompted for any extra URLs -- file:, ftp:, or
453 http: -- that host a CPAN mirror.
454
455 };
456
457     my (@cont, $cont, %cont, @countries, @urls, %seen);
458     my $no_previous_warn = 
459        "Sorry! since you don't have any existing picks, you must make a\n" .
460        "geographic selection.";
461     @cont = picklist([sort keys %all],
462                      "Select your continent (or several nearby continents)",
463                      '',
464                      ! @previous_urls,
465                      $no_previous_warn);
466
467
468     foreach $cont (@cont) {
469         my @c = sort keys %{$all{$cont}};
470         @cont{@c} = map ($cont, 0..$#c);
471         @c = map ("$_ ($cont)", @c) if @cont > 1;
472         push (@countries, @c);
473     }
474
475     if (@countries) {
476         @countries = picklist (\@countries,
477                                "Select your country (or several nearby countries)",
478                                '',
479                                ! @previous_urls,
480                                $no_previous_warn);
481         %seen = map (($_ => 1), @previous_urls);
482         # hmmm, should take list of defaults from CPAN::Config->{'urllist'}...
483         foreach $country (@countries) {
484             (my $bare_country = $country) =~ s/ \(.*\)//;
485             my @u = sort keys %{$all{$cont{$bare_country}}{$bare_country}};
486             @u = grep (! $seen{$_}, @u);
487             @u = map ("$_ ($bare_country)", @u)
488                if @countries > 1;
489             push (@urls, @u);
490         }
491     }
492     push (@urls, map ("$_ (previous pick)", @previous_urls));
493     my $prompt = "Select as many URLs as you like";
494     if (@previous_urls) {
495        $default = join (' ', ((scalar @urls) - (scalar @previous_urls) + 1) ..
496                              (scalar @urls));
497        $prompt .= "\n(or just hit RETURN to keep your previous picks)";
498     }
499
500     @urls = picklist (\@urls, $prompt, $default);
501     foreach (@urls) { s/ \(.*\)//; }
502     %seen = map (($_ => 1), @urls);
503
504     do {
505         $ans = prompt ("Enter another URL or RETURN to quit:", "");
506
507         if ($ans) {
508             $ans =~ s|/?$|/|; # has to end with one slash
509             $ans = "file:$ans" unless $ans =~ /:/; # without a scheme is a file:
510             if ($ans =~ /^\w+:\/./) {
511                push @urls, $ans 
512                   unless $seen{$ans};
513             }
514             else {
515                 print qq{"$ans" doesn\'t look like an URL at first sight.
516 I\'ll ignore it for now.  You can add it to $INC{'CPAN/MyConfig.pm'}
517 later if you\'re sure it\'s right.\n};
518             }
519         }
520     } while $ans;
521
522     push @{$CPAN::Config->{urllist}}, @urls;
523     # xxx delete or comment these out when you're happy that it works
524     print "New set of picks:\n";
525     map { print "  $_\n" } @{$CPAN::Config->{urllist}};
526 }
527
528 1;