This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix prototype mismatch (from Hans Mulder <hansm@xs4all.nl>)
[perl5.git] / lib / CPAN / FirstTime.pm
CommitLineData
5f05dabc 1package CPAN::Mirrored::By;
2
3sub new {
4 my($self,@arg) = @_;
5 bless [@arg], $self;
6}
da199366
A
7sub continent { shift->[0] }
8sub country { shift->[1] }
5f05dabc 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);
36263cb3 19$VERSION = substr q$Revision: 1.37 $, 10;
5f05dabc 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 43 eval {require CPAN::Config;};
44 $CPAN::Config ||= {};
da199366
A
45 local($/) = "\n";
46 local($\) = "";
13bc20ff 47 local($|) = 1;
da199366 48
5f05dabc 49 my($ans,$default,$local,$cont,$url,$expected_size);
f610777f 50
da199366
A
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 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 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
A
145 #
146 # Cache size, Index expire
147 #
148
5f05dabc 149 print qq{
150
151How big should the disk cache be for keeping the build directories
152with all the intermediate files?
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
191 $default = $CPAN::Config->{prerequisites_policy} || 'follow';
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
A
199 #
200 # External programs
201 #
202
5f05dabc 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
A
207Don\'t panic if you do not have some of them, just press ENTER for
208those.
5f05dabc 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 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
A
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
A
267
268 #
269 # Arguments to make etc.
270 #
271
5f05dabc 272 print qq{
273
da199366 274Every Makefile.PL is run by perl in a separate process. Likewise we
5f05dabc 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
A
279If you don\'t understand this question, just press ENTER.
280
5f05dabc 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
A
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
A
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 326 }
327
09d9d230
A
328 #
329 # MIRRORED.BY
330 #
331
332 conf_sites() unless $fastread;
333
d4fd5c69
A
334 unless (@{$CPAN::Config->{'wait_list'}||[]}) {
335 print qq{
da199366 336
05454584
A
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
A
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 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 }
36263cb3
GS
363 while () {
364 if ( ! -f $mby ){
365 print qq{You have no $mby
09d9d230
A
366 I\'m trying to fetch one
367};
36263cb3
GS
368 $mby = CPAN::FTP->localize($m,$mby,3);
369 } elsif (-M $mby > 30 ) {
370 print qq{Your $mby is older than 30 days,
09d9d230
A
371 I\'m trying to fetch one
372};
36263cb3
GS
373 $mby = CPAN::FTP->localize($m,$mby,3);
374 } elsif (-s $mby == 0) {
375 print qq{You have an empty $mby,
376 I\'m trying to fetch one
377};
378 $mby = CPAN::FTP->localize($m,$mby,3);
379 } else {
380 last;
381 }
09d9d230
A
382 }
383 read_mirrored_by($mby);
384}
385
5f05dabc 386sub find_exe {
387 my($exe,$path) = @_;
55e314ee
A
388 my($dir);
389 #warn "in find_exe exe[$exe] path[@$path]";
5f05dabc 390 for $dir (@$path) {
55e314ee 391 my $abs = MM->catfile($dir,$exe);
13bc20ff 392 if (($abs = MM->maybe_command($abs))) {
5f05dabc 393 return $abs;
394 }
395 }
396}
397
f610777f
A
398sub picklist {
399 my($items,$prompt,$default,$require_nonempty,$empty_warning)=@_;
400 $default ||= '';
401
402 my ($item, $i);
403 for $item (@$items) {
404 printf "(%d) %s\n", ++$i, $item;
405 }
406
407 my @nums;
408 while (1) {
409 my $num = prompt($prompt,$default);
410 @nums = split (' ', $num);
411 (warn "invalid items entered, try again\n"), next
412 if grep (/\D/ || $_ < 1 || $_ > $i, @nums);
413 if ($require_nonempty) {
414 (warn "$empty_warning\n"), next
415 unless @nums;
416 }
417 last;
418 }
419 print "\n";
420 for (@nums) { $_-- }
421 @{$items}[@nums];
422}
423
5f05dabc 424sub read_mirrored_by {
425 my($local) = @_;
426 my(%all,$url,$expected_size,$default,$ans,$host,$dst,$country,$continent,@location);
05454584
A
427 my $fh = FileHandle->new;
428 $fh->open($local) or die "Couldn't open $local: $!";
f14b5cec 429 local $/ = "\012";
05454584 430 while (<$fh>) {
5f05dabc 431 ($host) = /^([\w\.\-]+)/ unless defined $host;
432 next unless defined $host;
433 next unless /\s+dst_(dst|location)/;
434 /location\s+=\s+\"([^\"]+)/ and @location = (split /\s*,\s*/, $1) and
435 ($continent, $country) = @location[-1,-2];
436 $continent =~ s/\s\(.*//;
f610777f 437 $continent =~ s/\W+$//; # if Jarkko doesn't know latitude/longitude
5f05dabc 438 /dst_dst\s+=\s+\"([^\"]+)/ and $dst = $1;
439 next unless $host && $dst && $continent && $country;
440 $all{$continent}{$country}{$dst} = CPAN::Mirrored::By->new($continent,$country,$dst);
441 undef $host;
442 $dst=$continent=$country="";
443 }
05454584 444 $fh->close;
5f05dabc 445 $CPAN::Config->{urllist} ||= [];
f610777f
A
446 my(@previous_urls);
447 if (@previous_urls = @{$CPAN::Config->{urllist}}) {
5f05dabc 448 $CPAN::Config->{urllist} = [];
5f05dabc 449 }
f610777f 450
5f05dabc 451 print qq{
452
f610777f 453Now we need to know where your favorite CPAN sites are located. Push
5f05dabc 454a few sites onto the array (just in case the first on the array won\'t
455work). If you are mirroring CPAN to your local workstation, specify a
456file: URL.
457
f610777f
A
458First, pick a nearby continent and country (you can pick several of
459each, separated by spaces, or none if you just want to keep your
460existing selections). Then, you will be presented with a list of URLs
461of CPAN mirrors in the countries you selected, along with previously
462selected URLs. Select some of those URLs, or just keep the old list.
463Finally, you will be prompted for any extra URLs -- file:, ftp:, or
464http: -- that host a CPAN mirror.
5f05dabc 465
466};
467
f610777f
A
468 my (@cont, $cont, %cont, @countries, @urls, %seen);
469 my $no_previous_warn =
470 "Sorry! since you don't have any existing picks, you must make a\n" .
471 "geographic selection.";
472 @cont = picklist([sort keys %all],
473 "Select your continent (or several nearby continents)",
474 '',
475 ! @previous_urls,
476 $no_previous_warn);
477
478
479 foreach $cont (@cont) {
480 my @c = sort keys %{$all{$cont}};
481 @cont{@c} = map ($cont, 0..$#c);
482 @c = map ("$_ ($cont)", @c) if @cont > 1;
483 push (@countries, @c);
5f05dabc 484 }
f610777f
A
485
486 if (@countries) {
487 @countries = picklist (\@countries,
488 "Select your country (or several nearby countries)",
489 '',
490 ! @previous_urls,
491 $no_previous_warn);
492 %seen = map (($_ => 1), @previous_urls);
493 # hmmm, should take list of defaults from CPAN::Config->{'urllist'}...
494 foreach $country (@countries) {
495 (my $bare_country = $country) =~ s/ \(.*\)//;
496 my @u = sort keys %{$all{$cont{$bare_country}}{$bare_country}};
497 @u = grep (! $seen{$_}, @u);
498 @u = map ("$_ ($bare_country)", @u)
499 if @countries > 1;
500 push (@urls, @u);
501 }
502 }
503 push (@urls, map ("$_ (previous pick)", @previous_urls));
504 my $prompt = "Select as many URLs as you like";
505 if (@previous_urls) {
506 $default = join (' ', ((scalar @urls) - (scalar @previous_urls) + 1) ..
507 (scalar @urls));
508 $prompt .= "\n(or just hit RETURN to keep your previous picks)";
509 }
510
511 @urls = picklist (\@urls, $prompt, $default);
512 foreach (@urls) { s/ \(.*\)//; }
513 %seen = map (($_ => 1), @urls);
514
515 do {
516 $ans = prompt ("Enter another URL or RETURN to quit:", "");
517
518 if ($ans) {
519 $ans =~ s|/?$|/|; # has to end with one slash
520 $ans = "file:$ans" unless $ans =~ /:/; # without a scheme is a file:
521 if ($ans =~ /^\w+:\/./) {
522 push @urls, $ans
523 unless $seen{$ans};
524 }
525 else {
526 print qq{"$ans" doesn\'t look like an URL at first sight.
527I\'ll ignore it for now. You can add it to $INC{'CPAN/MyConfig.pm'}
528later if you\'re sure it\'s right.\n};
529 }
530 }
531 } while $ans;
532
533 push @{$CPAN::Config->{urllist}}, @urls;
534 # xxx delete or comment these out when you're happy that it works
535 print "New set of picks:\n";
536 map { print " $_\n" } @{$CPAN::Config->{urllist}};
5f05dabc 537}
538
5391;