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