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