# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
package CPAN;
-$VERSION = '1.83';
+$VERSION = '1.83_55';
$VERSION = eval $VERSION;
use strict;
$Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
- my $oprompt = shift || "cpan> ";
+ my $oprompt = shift || CPAN::Prompt->new;
my $prompt = $oprompt;
my $commandline = shift || "";
+ $CPAN::CurrentCommandId ||= 1;
local($^W) = 1;
unless ($Suppress_readline) {
my $command = shift @line;
eval { CPAN::Shell->$command(@line) };
warn $@ if $@;
+ if ($command =~ /^(make|test|install|force|notest)$/) {
+ CPAN::Shell->failed($CPAN::CurrentCommandId,1);
+ }
soft_chdir_with_alternatives(\@cwd);
$CPAN::Frontend->myprint("\n");
$continuation = "";
+ $CPAN::CurrentCommandId++;
$prompt = $oprompt;
}
} continue {
".\nCannot continue.\n";
}
+package CPAN::Prompt; use overload '""' => "as_string";
+our $prompt = "cpan> ";
+$CPAN::CurrentCommandId ||= 0;
+sub as_randomly_capitalized_string {
+ # pure fun variant
+ substr($prompt,$_,1)=rand()<0.5 ?
+ uc(substr($prompt,$_,1)) :
+ lc(substr($prompt,$_,1)) for 0..3;
+ $prompt;
+}
+sub new {
+ bless {}, shift;
+}
+sub as_string {
+ if ($CPAN::Config->{commandnumber_in_prompt}) {
+ sprintf "cpan[%d]> ", $CPAN::CurrentCommandId;
+ } else {
+ "cpan> ";
+ }
+}
+
+package CPAN::Distrostatus;
+use overload '""' => "as_string",
+ fallback => 1;
+sub new {
+ my($class,$arg) = @_;
+ bless {
+ TEXT => $arg,
+ FAILED => substr($arg,0,2) eq "NO",
+ COMMANDID => $CPAN::CurrentCommandId,
+ }, $class;
+}
+sub commandid { shift->{COMMANDID} }
+sub failed { shift->{FAILED} }
+sub text {
+ my($self,$set) = @_;
+ if (defined $set) {
+ $self->{TEXT} = $set;
+ }
+ $self->{TEXT};
+}
+sub as_string {
+ my($self) = @_;
+ if (0) { # called from rematein during install?
+ require Carp;
+ Carp::cluck("HERE");
+ }
+ $self->{TEXT};
+}
+
package CPAN::Shell;
use strict;
use vars qw($AUTOLOAD @ISA $COLOR_REGISTERED $ADVANCED_QUERY $PRINT_ORNAMENTING);
my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
if (-f $lockfile && -M _ > 0) {
my $fh = FileHandle->new($lockfile) or
- $CPAN::Frontend->mydie("Could not open $lockfile: $!");
+ $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
my $otherpid = <$fh>;
my $otherhost = <$fh>;
$fh->close;
if (defined $otherhost && defined $thishost &&
$otherhost ne '' && $thishost ne '' &&
$otherhost ne $thishost) {
- $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
+ $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
"reports other host $otherhost and other process $otherpid.\n".
"Cannot proceed.\n"));
}
my($ans) =
ExtUtils::MakeMaker::prompt
(qq{Other job not responding. Shall I overwrite }.
- qq{the lockfile? (Y/N)},"y");
+ qq{the lockfile '$lockfile'? (Y/n)},"y");
$CPAN::Frontend->myexit("Ok, bye\n")
unless $ans =~ /^y/i;
} else {
Carp::croak(
- qq{Lockfile $lockfile not writeable by you. }.
+ qq{Lockfile '$lockfile' not writeable by you. }.
qq{Cannot proceed.\n}.
qq{ On UNIX try:\n}.
- qq{ rm $lockfile\n}.
+ qq{ rm '$lockfile'\n}.
qq{ and then rerun us.\n}
);
}
} else {
- $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile $lockfile\n".
+ $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
"reports other process with ID ".
"$otherpid. Cannot proceed.\n"));
}
if (defined $about) {
$CPAN::Frontend->myprint("Detailed help not yet implemented\n");
} else {
- $CPAN::Frontend->myprint(q{
-Display Information
+ my $filler = " " x (80 - 28 - length($CPAN::VERSION));
+ $CPAN::Frontend->myprint(qq{
+Display Information $filler (ver $CPAN::VERSION)
command argument description
a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules
i WORD or /REGEXP/ about any of the above
}
sub handle_ls {
- my($self,$pragma,$s) = @_;
+ my($self,$pragmas,$s) = @_;
# ls is really very different, but we had it once as an ordinary
# command in the Shell (upto rev. 321) and we could not handle
# force well then
}
$CPAN::Frontend->myprint($ad);
}
+ for my $pragma (@$pragmas) {
+ if ($author->can($pragma)) {
+ $author->$pragma();
+ }
+ }
$author->ls($pathglob,$silent); # silent if more than one author
+ for my $pragma (@$pragmas) {
+ my $meth = "un$pragma";
+ if ($author->can($meth)) {
+ $author->$meth();
+ }
+ }
}
}
# should have been called set and 'o debug' maybe 'set debug'
sub o {
my($self,$o_type,@o_what) = @_;
+ $DB::single = 1;
$o_type ||= "";
CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
if ($o_type eq 'conf') {
# XXX intentionally undocumented because not considered enough
#-> sub CPAN::Shell::failed ;
sub failed {
- my($self) = @_;
+ my($self,$only_id,$silent) = @_;
my $print = "";
DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
my $failed = "";
- for my $nosayer (qw(make make_test make_install)) {
+ for my $nosayer (qw(signature_verify make make_test install)) {
next unless exists $d->{$nosayer};
- next unless substr($d->{$nosayer},0,2) eq "NO";
+ next unless $d->{$nosayer}->failed;
$failed = $nosayer;
last;
}
next DIST unless $failed;
+ next DIST if $only_id && $only_id != $d->{$failed}->commandid;
my $id = $d->id;
$id =~ s|^./../||;
- $print .= sprintf " %-45s: %s %s\n", $id, $failed, $d->{$failed};
+ $print .= sprintf(
+ " %-45s: %s %s\n",
+ $id,
+ $failed,
+ $d->{$failed}->text,
+ );
}
+ my $scope = $only_id ? "command" : "session";
if ($print) {
- $CPAN::Frontend->myprint("Failed installations in this session:\n$print");
- } else {
- $CPAN::Frontend->myprint("No installations failed in this session\n");
+ $CPAN::Frontend->myprint("Failed installations in this $scope:\n$print");
+ } elsif (!$only_id || !$silent) {
+ $CPAN::Frontend->myprint("No installations failed in this $scope\n");
}
}
die "\n";
}
+sub mysleep {
+ my($self, $sleep) = @_;
+ sleep $sleep;
+}
+
sub setup_output {
return if -t STDOUT;
my $odef = select STDERR;
#-> sub CPAN::FTP::ftp_get ;
sub ftp_get {
- my($class,$host,$dir,$file,$target) = @_;
- $class->debug(
- qq[Going to fetch file [$file] from dir [$dir]
+ my($class,$host,$dir,$file,$target) = @_;
+ $class->debug(
+ qq[Going to fetch file [$file] from dir [$dir]
on host [$host] as local [$target]\n]
- ) if $CPAN::DEBUG;
- my $ftp = Net::FTP->new($host);
- return 0 unless defined $ftp;
- $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
- $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
- unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
- warn "Couldn't login on $host";
- return;
- }
- unless ( $ftp->cwd($dir) ){
- warn "Couldn't cwd $dir";
- return;
- }
- $ftp->binary;
- $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
- unless ( $ftp->get($file,$target) ){
- warn "Couldn't fetch $file from $host\n";
- return;
- }
- $ftp->quit; # it's ok if this fails
- return 1;
+ ) if $CPAN::DEBUG;
+ my $ftp = Net::FTP->new($host);
+ unless ($ftp) {
+ $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n");
+ return;
+ }
+ return 0 unless defined $ftp;
+ $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
+ $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
+ unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ){
+ my $msg = $ftp->message;
+ $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg");
+ return;
+ }
+ unless ( $ftp->cwd($dir) ){
+ my $msg = $ftp->message;
+ $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg");
+ return;
+ }
+ $ftp->binary;
+ $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
+ unless ( $ftp->get($file,$target) ){
+ my $msg = $ftp->message;
+ $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg");
+ return;
+ }
+ $ftp->quit; # it's ok if this fails
+ return 1;
}
# If more accuracy is wanted/needed, Chris Leach sent me this patch...
$last_updated);
$DATE_OF_02 = $last_updated;
+ my $age = time;
if ($CPAN::META->has_inst('HTTP::Date')) {
require HTTP::Date;
- my($age) = (time - HTTP::Date::str2time($last_updated))/3600/24;
- if ($age > 30) {
+ $age -= HTTP::Date::str2time($last_updated);
+ } else {
+ $CPAN::Frontend->myprint(" HTTP::Date not available\n");
+ require Time::Local;
+ my(@d) = $last_updated =~ / (\d+) (\w+) (\d+) (\d+):(\d+):(\d+) /;
+ $d[1] = index("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", $d[1])/4;
+ $age -= $d[1]>=0 ? Time::Local::timegm(@d[5,4,3,0,1,2]) : 0;
+ }
+ $age /= 3600*24;
+ if ($age > 30) {
- $CPAN::Frontend
- ->mywarn(sprintf
- qq{Warning: This index file is %d days old.
+ $CPAN::Frontend
+ ->mywarn(sprintf
+ qq{Warning: This index file is %d days old.
Please check the host you chose as your CPAN mirror for staleness.
I'll continue but problems seem likely to happen.\a\n},
- $age);
+ $age);
+
+ } elsif ($age < -1) {
+
+ $CPAN::Frontend
+ ->mywarn(sprintf
+ qq{Warning: Your system date is %d days behind this index file!
+ System time: %s
+ Timestamp index file: %s
+ Please fix your system time, problems with the make command expected.\n},
+ -$age,
+ scalar gmtime,
+ $DATE_OF_02,
+ );
- }
- } else {
- $CPAN::Frontend->myprint(" HTTP::Date not available\n");
}
}
package CPAN::Author;
use strict;
+#-> sub CPAN::Author::force
+sub force {
+ my $self = shift;
+ $self->{force}++;
+}
+
+#-> sub CPAN::Author::force
+sub unforce {
+ my $self = shift;
+ delete $self->{force};
+}
+
#-> sub CPAN::Author::id
sub id {
my $self = shift;
local($") = "/";
# connect "force" argument with "index_expire".
- my $force = 0;
+ my $force = $self->{force};
if (my @stat = stat $lc_want) {
- $force = $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
+ $force ||= $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
}
my $lc_file;
if ($may_ftp) {
);
my $wrap =
- sprintf(qq{I\'d recommend removing %s. Its signature
+ sprintf(qq{I'd recommend removing %s. Its signature
is invalid. Maybe you have configured your 'urllist' with
a bad URL. Please check this array with 'o conf urllist', and
retry. For more information, try opening a subshell with
look %s
and there run
- cpansign -v},
+ cpansign -v
+},
$self->{localfile},
$self->pretty_id,
);
- $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
+ $self->{signature_verify} = CPAN::Distrostatus->new("NO");
+ $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap));
+ $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep");
+ } else {
+ $self->{signature_verify} = CPAN::Distrostatus->new("YES");
}
} else {
$CPAN::Frontend->myprint(qq{Package came without SIGNATURE\n\n});
my $pwd = CPAN::anycwd();
$self->safe_chdir($dir);
$CPAN::Frontend->myprint(qq{Working directory is $dir\n});
- unless (system($CPAN::Config->{'shell'}) == 0) {
- my $code = $? >> 8;
- $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
+ {
+ local $ENV{CPAN_SHELL_LEVEL} = $ENV{CPAN_SHELL_LEVEL}||0;
+ $ENV{CPAN_SHELL_LEVEL} += 1;
+ unless (system($CPAN::Config->{'shell'}) == 0) {
+ my $code = $? >> 8;
+ $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
+ }
}
$self->safe_chdir($pwd);
}
)) {
delete $self->{$att};
}
- if ($method && $method eq "install") {
+ if ($method && $method =~ /make|test|install/) {
$self->{"force_update"}++; # name should probably have been force_install
}
}
"Is neither a tar nor a zip archive.";
!$self->{unwrapped} || $self->{unwrapped} eq "NO" and push @e,
- "had problems unarchiving. Please build manually";
+ "Had problems unarchiving. Please build manually";
+
+ unless ($self->{force_update}) {
+ exists $self->{signature_verify} and $self->{signature_verify}->failed
+ and push @e, "Did not pass the signature test.";
+ }
exists $self->{writemakefile} &&
$self->{writemakefile} =~ m/ ^ NO\s* ( .* ) /sx and push @e,
if ($self->{modulebuild}) {
$system = "./Build $CPAN::Config->{mbuild_arg}";
} else {
- $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg};
+ $system = join " ", _make_command(), $CPAN::Config->{make_arg};
}
if (system($system) == 0) {
$CPAN::Frontend->myprint(" $system -- OK\n");
- $self->{'make'} = "YES";
+ $self->{'make'} = CPAN::Distrostatus->new("YES");
} else {
$self->{writemakefile} ||= "YES";
- $self->{'make'} = "NO";
+ $self->{'make'} = CPAN::Distrostatus->new("NO");
$CPAN::Frontend->myprint(" $system -- NOT OK\n");
}
}
+sub _make_command {
+ return $CPAN::Config->{'make'} || $Config::Config{make} || 'make';
+}
+
sub follow_prereqs {
my($self) = shift;
my(@prereq) = grep {$_ ne "perl"} @_;
}
last;
}
+ } elsif (-f "Build") {
+ if ($CPAN::META->has_inst("Module::Build")) {
+ $req = Module::Build->current->requires();
+ }
}
}
$self->{prereq_pm_detected}++;
"Make had some problems, maybe interrupted? Won't test";
exists $self->{'make'} and
- $self->{'make'} eq 'NO' and
+ $self->{'make'}->failed and
push @e, "Can't test without successful make";
exists $self->{build_dir} or push @e, "Has no own directory";
if ($self->{modulebuild}) {
$system = "./Build test";
} else {
- $system = join " ", $CPAN::Config->{'make'}, "test";
+ $system = join " ", _make_command(), "test";
}
if (system($system) == 0) {
$CPAN::Frontend->myprint(" $system -- OK\n");
$CPAN::META->is_tested($self->{'build_dir'});
- $self->{make_test} = "YES";
+ $self->{make_test} = CPAN::Distrostatus->new("YES");
} else {
- $self->{make_test} = "NO";
+ $self->{make_test} = CPAN::Distrostatus->new("NO");
$self->{badtestcnt}++;
$CPAN::Frontend->myprint(" $system -- NOT OK\n");
}
if ($self->{modulebuild}) {
$system = "./Build clean";
} else {
- $system = join " ", $CPAN::Config->{'make'}, "clean";
+ $system = join " ", _make_command(), "clean";
}
if (system($system) == 0) {
$CPAN::Frontend->myprint(" $system -- OK\n");
"Make had some problems, maybe interrupted? Won't install";
exists $self->{'make'} and
- $self->{'make'} eq 'NO' and
+ $self->{'make'}->failed and
push @e, "make had returned bad status, install seems impossible";
- push @e, "make test had returned bad status, ".
- "won't install without force"
- if exists $self->{'make_test'} and
- $self->{'make_test'} eq 'NO' and
- ! $self->{'force_update'};
-
+ if (exists $self->{make_test} and
+ $self->{make_test}->failed){
+ if ($self->{force_update}) {
+ $self->{make_test}->text("FAILED but failure ignored because ".
+ "'force' in effect");
+ } else {
+ push @e, "make test had returned bad status, ".
+ "won't install without force"
+ }
+ }
exists $self->{'install'} and push @e,
- $self->{'install'} eq "YES" ?
+ $self->{'install'}->text eq "YES" ?
"Already done" : "Already tried without success";
exists $self->{later} and length($self->{later}) and
);
} else {
my($make_install_make_command) = $CPAN::Config->{'make_install_make_command'} ||
- $CPAN::Config->{'make'};
+ _make_command();
$system = join(" ",
$make_install_make_command,
"install",
if ($?==0) {
$CPAN::Frontend->myprint(" $system -- OK\n");
$CPAN::META->is_installed($self->{'build_dir'});
- return $self->{'install'} = "YES";
+ return $self->{'install'} = CPAN::Distrostatus->new("YES");
} else {
- $self->{'install'} = "NO";
+ $self->{'install'} = CPAN::Distrostatus->new("NO");
$CPAN::Frontend->myprint(" $system -- NOT OK\n");
if (
$makeout =~ /permission/s
return $ro->{userid} || $ro->{CPAN_USERID};
}
# sub CPAN::Module::description
-sub description { shift->ro->{description} }
+sub description {
+ my $self = shift;
+ my $ro = $self->ro or return "";
+ $ro->{description}
+}
sub undelay {
my $self = shift;
$stats{$ro->{stats}},
$statl{$ro->{statl}},
$stati{$ro->{stati}}
- ) if $ro->{statd};
+ ) if $ro && $ro->{statd};
my $local_file = $self->inst_file;
unless ($self->{MANPAGE}) {
if ($local_file) {
The last example is very slow and outputs extra progress indicators
that break the alignment of the result.
+=item failed
+
+The C<failed> command reports all distributions that failed on one of
+C<make>, C<test> or C<install> for some reason in the currently
+running shell session.
+
=item Signals
CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
for this is that the primary use is intended for the cpan shell or for
one-liners.
+=head1 ENVIRONMENT
+
+When the CPAN shell enters a subshell via the look command, it sets
+the environment CPAN_SHELL_LEVEL to 1 or increments it if it is
+already set.
+
=head1 POPULATE AN INSTALLATION WITH LOTS OF MODULES
Populating a freshly installed perl with my favorite modules is pretty
package CPAN::Mirrored::By;
use strict;
use vars qw($VERSION);
-$VERSION = sprintf "%.2f", substr(q$Rev: 338 $,4)/100;
+$VERSION = sprintf "%.2f", substr(q$Rev: 399 $,4)/100;
sub new {
my($self,@arg) = @_;
use File::Path ();
use File::Spec;
use vars qw($VERSION);
-$VERSION = sprintf "%.2f", substr(q$Rev: 338 $,4)/100;
+$VERSION = sprintf "%.2f", substr(q$Rev: 399 $,4)/100;
=head1 NAME
=cut
+use vars qw( %prompts );
+
sub init {
my($configpm, %args) = @_;
-
use Config;
+ # extra arg in 'o conf init make' selects only $item =~ /make/
+ my $matcher = $args{args} && @{$args{args}} ? $args{args}[0] : '';
unless ($CPAN::VERSION) {
require CPAN::Nox;
# Files, directories
#
- print qq[
+ # not just yet
+ # if (!@sections or grep /^(files|dirs)$/, @sections) {
-CPAN is the world-wide archive of perl resources. It consists of about
-100 sites that all replicate the same contents all around the globe.
-Many countries have at least one CPAN site already. The resources
-found on CPAN are easily accessible with the CPAN.pm module. If you
-want to use CPAN.pm, you have to configure it properly.
-
-If you do not want to enter a dialog now, you can answer 'no' to this
-question and I\'ll try to autoconfigure. (Note: you can revisit this
-dialog anytime later by typing 'o conf init' at the cpan prompt.)
-
-];
+ print $prompts{manual_config};
my $manual_conf;
};
}
}
- $CPAN::Frontend->myprint(qq{
+ # if ('config_intro' ~= $matcher) {
-The following questions are intended to help you with the
-configuration. The CPAN module needs a directory of its own to cache
-important index files and maybe keep a temporary mirror of CPAN files.
-This may be a site-wide directory or a personal directory.
+ $CPAN::Frontend->myprint($prompts{config_intro});
-});
+ #}
+
+
+ my $cpan_home = $CPAN::Config->{cpan_home}
+ || File::Spec->catdir($ENV{HOME}, ".cpan");
- my $cpan_home = $CPAN::Config->{cpan_home} || File::Spec->catdir($ENV{HOME}, ".cpan");
if (-d $cpan_home) {
$CPAN::Frontend->myprint(qq{
Shall we use it as the general CPAN build and cache directory?
});
- } else {
- $CPAN::Frontend->myprint(qq{
-
-First of all, I\'d like to create this directory. Where?
-});
+ } else {
+ $CPAN::Frontend->myprint($prompts{cpan_home_where});
}
$default = $cpan_home;
}
eval { File::Path::mkpath($ans); }; # dies if it can't
if ($@) {
- warn "Couldn't create directory $ans.
-Please retry.\n";
+ warn "Couldn't create directory $ans.\nPlease retry.\n";
next;
}
if (-d $ans && -w _) {
last;
} else {
- warn "Couldn't find directory $ans
- or directory is not writable. Please retry.\n";
+ warn "Couldn't find directory $ans\n"
+ . "or directory is not writable. Please retry.\n";
}
}
$CPAN::Config->{cpan_home} = $ans;
- $CPAN::Frontend->myprint( qq{
-
-If you like, I can cache the source files after I build them. Doing
-so means that, if you ever rebuild that module in the future, the
-files will be taken from the cache. The tradeoff is that it takes up
-space. How much space would you like to allocate to this cache? (If
-you don\'t want me to keep a cache, answer 0.)
+ $CPAN::Frontend->myprint($prompts{keep_source_where});
-});
+ $CPAN::Config->{keep_source_where}
+ = File::Spec->catdir($CPAN::Config->{cpan_home},"sources");
- $CPAN::Config->{keep_source_where} = File::Spec->catdir($CPAN::Config->{cpan_home},"sources");
- $CPAN::Config->{build_dir} = File::Spec->catdir($CPAN::Config->{cpan_home},"build");
+ $CPAN::Config->{build_dir}
+ = File::Spec->catdir($CPAN::Config->{cpan_home},"build");
#
# Cache size, Index expire
#
- $CPAN::Frontend->myprint( qq{
-
-How big should the disk cache be for keeping the build directories
-with all the intermediate files\?
-
-});
+ $CPAN::Frontend->myprint($prompts{build_cache_intro});
- $default = $CPAN::Config->{build_cache} || 100; # large enough to
- # build large
- # dists like Tk
- $ans = prompt("Cache size for build directory (in MB)?", $default);
- $CPAN::Config->{build_cache} = $ans;
+ # large enough to build large dists like Tk
+ my_dflt_prompt(build_cache => 100, $matcher);
# XXX This the time when we refetch the index files (in days)
$CPAN::Config->{'index_expire'} = 1;
- $CPAN::Frontend->myprint( qq{
-
-By default, each time the CPAN module is started, cache scanning is
-performed to keep the cache size in sync. To prevent this, answer
-'never'.
-
-});
-
- $default = $CPAN::Config->{scan_cache} || 'atstart';
- do {
- $ans = prompt("Perform cache scanning (atstart or never)?", $default);
- } while ($ans ne 'atstart' && $ans ne 'never');
- $CPAN::Config->{scan_cache} = $ans;
+ $CPAN::Frontend->myprint($prompts{scan_cache_intro});
+ my_prompt_loop(scan_cache => 'atstart', $matcher, 'atstart|never');
#
# cache_metadata
#
- $CPAN::Frontend->myprint( qq{
-To considerably speed up the initial CPAN shell startup, it is
-possible to use Storable to create a cache of metadata. If Storable
-is not available, the normal index mechanism will be used.
-
-});
+ $CPAN::Frontend->myprint($prompts{cache_metadata});
defined($default = $CPAN::Config->{cache_metadata}) or $default = 1;
do {
#
# term_is_latin
#
- $CPAN::Frontend->myprint( qq{
-The next option deals with the charset (aka character set) your
-terminal supports. In general, CPAN is English speaking territory, so
-the charset does not matter much, but some of the aliens out there who
-upload their software to CPAN bear names that are outside the ASCII
-range. If your terminal supports UTF-8, you should say no to the next
-question. If it supports ISO-8859-1 (also known as LATIN1) then you
-should say yes. If it supports neither, your answer does not matter
-because you will not be able to read the names of some authors
-anyway. If you answer no, names will be output in UTF-8.
-
-});
+ $CPAN::Frontend->myprint($prompts{term_is_latin});
defined($default = $CPAN::Config->{term_is_latin}) or $default = 1;
do {
#
# save history in file histfile
#
- $CPAN::Frontend->myprint( qq{
-If you have one of the readline packages (Term::ReadLine::Perl,
-Term::ReadLine::Gnu, possibly others) installed, the interactive CPAN
-shell will have history support. The next two questions deal with the
-filename of the history file and with its size. If you do not want to
-set this variable, please hit SPACE RETURN to the following question.
-
-});
+ $CPAN::Frontend->myprint($prompts{histfile});
defined($default = $CPAN::Config->{histfile}) or
$default = File::Spec->catfile($CPAN::Config->{cpan_home},"histfile");
#
# do an ls on the m or the d command
#
- $CPAN::Frontend->myprint( qq{
-
-The 'd' and the 'm' command normally only show you information they
-have in their in-memory database and thus will never connect to the
-internet. If you set the 'show_upload_date' variable to true, 'm' and
-'d' will additionally show you the upload date of the module or
-distribution. Per default this feature is off because it may require a
-net connection to get at the upload date.
-
-});
+ $CPAN::Frontend->myprint($prompts{show_upload_date_intro});
defined($default = $CPAN::Config->{show_upload_date}) or
- $default = 0;
- $ans = prompt("Always try to show upload date with 'd' and 'm' command?", $default);
- $CPAN::Config->{show_upload_date} = $ans;
+ $default = 'n';
+ $ans = prompt("Always try to show upload date with 'd' and 'm' command (yes/no)?",
+ ($default ? 'yes' : 'no'));
+ $CPAN::Config->{show_upload_date} = ($ans =~ /^[y1]/i ? 1 : 0);
+
+ #my_prompt_loop(show_upload_date => 'n', $matcher,
+ #'follow|ask|ignore');
#
# prerequisites_policy
# Do we follow PREREQ_PM?
#
- $CPAN::Frontend->myprint( qq{
-The CPAN module can detect when a module which you are trying to build
-depends on prerequisites. If this happens, it can build the
-prerequisites for you automatically ('follow'), ask you for
-confirmation ('ask'), or just ignore them ('ignore'). Please set your
-policy to one of the three values.
+ $CPAN::Frontend->myprint($prompts{prerequisites_policy_intro});
-});
+ my_prompt_loop(prerequisites_policy => 'ask', $matcher,
+ 'follow|ask|ignore');
- $default = $CPAN::Config->{prerequisites_policy} || 'ask';
- do {
- $ans =
- prompt("Policy on building prerequisites (follow, ask or ignore)?",
- $default);
- } while ($ans ne 'follow' && $ans ne 'ask' && $ans ne 'ignore');
- $CPAN::Config->{prerequisites_policy} = $ans;
#
# External programs
#
- $CPAN::Frontend->myprint(qq{
-
-The CPAN module will need a few external programs to work properly.
-Please correct me, if I guess the wrong path for a program. Don\'t
-panic if you do not have some of them, just press ENTER for those. To
-disable the use of a download program, you can type a space followed
-by ENTER.
-
-});
+ $CPAN::Frontend->myprint($prompts{external_progs});
my $old_warn = $^W;
local $^W if $^O eq 'MacOS';
$CPAN::Config->{$progname} = 'not_here';
next;
}
+ next if $matcher && $progname !~ /$matcher/;
+
my $progcall = $progname;
# we don't need ncftp if we have ncftpget
next if $progname eq "ncftp" && $CPAN::Config->{ncftpget} gt " ";
$path = "";
}
$path ||= $ENV{SHELL};
+ if (!$path && $^O eq 'MSWin32') {
+ $path = Win32::IsWinNT() ? "cmd.exe" : "command.com";
+ }
if ($^O eq 'MacOS') {
$CPAN::Config->{'shell'} = 'not_here';
} else {
# Arguments to make etc.
#
- $CPAN::Frontend->myprint( qq{
-
-When you have Module::Build installed and a module comes with both a
-Makefile.PL and a Build.PL, which shall have precedence? The two
-installer modules we have are the old and well established
-ExtUtils::MakeMaker (for short: EUMM) understands the Makefile.PL and
-the next generation installer Module::Build (MB) works with the
-Build.PL.
-
-});
-
- $default = $CPAN::Config->{prefer_installer} || "EUMM";
- do {
- $ans =
- prompt("In case you could choose, which installer would you prefer (EUMM or MB)?",
- $default);
- } while (uc $ans ne 'MB' && uc $ans ne 'EUMM');
- $CPAN::Config->{prefer_installer} = $ans;
-
- $CPAN::Frontend->myprint( qq{
-
-Every Makefile.PL is run by perl in a separate process. Likewise we
-run \'make\' and \'make install\' in separate processes. If you have
-any parameters \(e.g. PREFIX, LIB, UNINST or the like\) you want to
-pass to the calls, please specify them here.
-
-If you don\'t understand this question, just press ENTER.
-
-});
-
- $default = $CPAN::Config->{makepl_arg} || "";
- $CPAN::Config->{makepl_arg} =
- prompt("Parameters for the 'perl Makefile.PL' command?
-Typical frequently used settings:
-
- PREFIX=~/perl # non-root users (please see manual for more hints)
-
-Your choice: ",$default);
- $default = $CPAN::Config->{make_arg} || "";
- $CPAN::Config->{make_arg} = prompt("Parameters for the 'make' command?
-Typical frequently used setting:
-
- -j3 # dual processor system
-
-Your choice: ",$default);
-
- $default = $CPAN::Config->{make_install_make_command} || $CPAN::Config->{make} || "";
- $CPAN::Config->{make_install_make_command} =
- prompt("Do you want to use a different make command for 'make install'?
-Cautious people will probably prefer:
-
- su root -c make
-or
- sudo make
-or
- /path1/to/sudo -u admin_account /path2/to/make
-
-or some such. Your choice: ",$default);
-
- $default = $CPAN::Config->{make_install_arg} || $CPAN::Config->{make_arg} || "";
- $CPAN::Config->{make_install_arg} =
- prompt("Parameters for the 'make install' command?
-Typical frequently used setting:
-
- UNINST=1 # to always uninstall potentially conflicting files
-
-Your choice: ",$default);
-
- $CPAN::Frontend->myprint( qq{
-
-The next questions deal with Module::Build support.
-
-A Build.PL is run by perl in a separate process. Likewise we run
-'./Build' and './Build install' in separate processes. If you have any
-parameters you want to pass to the calls, please specify them here.
+ $CPAN::Frontend->myprint($prompts{prefer_installer_intro});
-});
+ my_prompt_loop(prefer_installer => 'EUMM', $matcher, 'MB|EUMM');
- $default = $CPAN::Config->{mbuildpl_arg} || "";
- $CPAN::Config->{mbuildpl_arg} =
- prompt("Parameters for the 'perl Build.PL' command?
-Typical frequently used settings:
- --install_base /home/xxx # different installation directory
+ $CPAN::Frontend->myprint($prompts{makepl_arg_intro});
-Your choice: ",$default);
- $default = $CPAN::Config->{mbuild_arg} || "";
- $CPAN::Config->{mbuild_arg} = prompt("Parameters for the './Build' command?
-Setting might be:
+ my_dflt_prompt(makepl_arg => "", $matcher);
- --extra_linker_flags -L/usr/foo/lib # non-standard library location
+ my_dflt_prompt(make_arg => "", $matcher);
-Your choice: ",$default);
+ my_dflt_prompt(make_install_make_command => $CPAN::Config->{make} || "",
+ $matcher);
- $default = $CPAN::Config->{mbuild_install_build_command} || "./Build";
- $CPAN::Config->{mbuild_install_build_command} =
- prompt("Do you want to use a different command for './Build install'?
-Sudo users will probably prefer:
+ my_dflt_prompt(make_install_arg => $CPAN::Config->{make_arg} || "",
+ $matcher);
- su root -c ./Build
-or
- sudo ./Build
-or
- /path1/to/sudo -u admin_account ./Build
+ $CPAN::Frontend->myprint($prompts{mbuildpl_arg_intro});
-or some such. Your choice: ",$default);
+ my_dflt_prompt(mbuildpl_arg => "", $matcher);
- $default = $CPAN::Config->{mbuild_install_arg} || "";
- $CPAN::Config->{mbuild_install_arg} =
- prompt("Parameters for the './Build install' command?
-Typical frequently used setting:
+ my_dflt_prompt(mbuild_arg => "", $matcher);
- --uninst 1 # uninstall conflicting files
+ my_dflt_prompt(mbuild_install_build_command => "./Build", $matcher);
-Your choice: ",$default);
+ my_dflt_prompt(mbuild_install_arg => "", $matcher);
#
# Alarm period
#
- $CPAN::Frontend->myprint( qq{
+ $CPAN::Frontend->myprint($prompts{inactivity_timeout_intro});
-Sometimes you may wish to leave the processes run by CPAN alone
-without caring about them. Because the Makefile.PL sometimes contains
-question you\'re expected to answer, you can set a timer that will
-kill a 'perl Makefile.PL' process after the specified time in seconds.
-
-If you set this value to 0, these processes will wait forever. This is
-the default and recommended setting.
-
-});
+ # my_dflt_prompt(inactivity_timeout => 0);
$default = $CPAN::Config->{inactivity_timeout} || 0;
$CPAN::Config->{inactivity_timeout} =
- prompt("Timeout for inactivity during {Makefile,Build}.PL?",$default);
+ prompt("Timeout for inactivity during {Makefile,Build}.PL?",$default);
# Proxies
- $CPAN::Frontend->myprint( qq{
-
-If you\'re accessing the net via proxies, you can specify them in the
-CPAN configuration or via environment variables. The variable in
-the \$CPAN::Config takes precedence.
-
-});
+ $CPAN::Frontend->myprint($prompts{proxies});
for (qw/ftp_proxy http_proxy no_proxy/) {
$default = $CPAN::Config->{$_} || $ENV{$_};
if ($CPAN::Config->{ftp_proxy} ||
$CPAN::Config->{http_proxy}) {
+
$default = $CPAN::Config->{proxy_user} || $CPAN::LWP::UserAgent::USER;
- $CPAN::Frontend->myprint( qq{
-If your proxy is an authenticating proxy, you can store your username
-permanently. If you do not want that, just press RETURN. You will then
-be asked for your username in every future session.
+ $CPAN::Frontend->myprint($prompts{proxy_user});
-});
if ($CPAN::Config->{proxy_user} = prompt("Your proxy user id?",$default)) {
- $CPAN::Frontend->myprint( qq{
-
-Your password for the authenticating proxy can also be stored
-permanently on disk. If this violates your security policy, just press
-RETURN. You will then be asked for the password in every future
-session.
-
-});
+ $CPAN::Frontend->myprint($prompts{proxy_pass});
if ($CPAN::META->has_inst("Term::ReadKey")) {
Term::ReadKey::ReadMode("noecho");
} else {
- $CPAN::Frontend->myprint( qq{
-
-Warning: Term::ReadKey seems not to be available, your password will
-be echoed to the terminal!
-
-});
+ $CPAN::Frontend->myprint($prompts{password_warn});
}
$CPAN::Config->{proxy_pass} = prompt_no_strip("Your proxy password?");
if ($CPAN::META->has_inst("Term::ReadKey")) {
CPAN::HandleConfig->commit($configpm);
}
+sub my_dflt_prompt {
+ my ($item, $dflt, $m) = @_;
+ my $default = $CPAN::Config->{$item} || $dflt;
+
+ $DB::single = 1;
+ if (!$m || $item =~ /$m/) {
+ $CPAN::Config->{$item} = prompt($prompts{$item}, $default);
+ } else {
+ $CPAN::Config->{$item} = $default;
+ }
+}
+
+sub my_prompt_loop {
+ my ($item, $dflt, $m, $ok) = @_;
+ my $default = $CPAN::Config->{$item} || $dflt;
+ my $ans;
+
+ $DB::single = 1;
+ if (!$m || $item =~ /$m/) {
+ do { $ans = prompt($prompts{$item}, $default);
+ } until $ans =~ /$ok/;
+ $CPAN::Config->{$item} = $ans;
+ } else {
+ $CPAN::Config->{$item} = $default;
+ }
+}
+
+
sub conf_sites {
my $m = 'MIRRORED.BY';
my $mby = File::Spec->catfile($CPAN::Config->{keep_source_where},$m);
}
while ($mby) {
if ($overwrite_local) {
- print qq{Trying to overwrite $mby
-};
+ print qq{Trying to overwrite $mby\n};
$mby = CPAN::FTP->localize($m,$mby,3);
$overwrite_local = 0;
} elsif ( ! -f $mby ){
- print qq{You have no $mby
- I\'m trying to fetch one
-};
+ print qq{You have no $mby\n I\'m trying to fetch one\n};
$mby = CPAN::FTP->localize($m,$mby,3);
} elsif (-M $mby > 60 && $loopcount == 0) {
- print qq{Your $mby is older than 60 days,
- I\'m trying to fetch one
-};
+ print qq{Your $mby is older than 60 days,\n I\'m trying to fetch one\n};
$mby = CPAN::FTP->localize($m,$mby,3);
$loopcount++;
} elsif (-s $mby == 0) {
- print qq{You have an empty $mby,
- I\'m trying to fetch one
-};
+ print qq{You have an empty $mby,\n I\'m trying to fetch one\n};
$mby = CPAN::FTP->localize($m,$mby,3);
} else {
last;
sub read_mirrored_by {
my $local = shift or return;
- my(%all,$url,$expected_size,$default,$ans,$host,$dst,$country,$continent,@location);
+ my(%all,$url,$expected_size,$default,$ans,$host,
+ $dst,$country,$continent,@location);
my $fh = FileHandle->new;
$fh->open($local) or die "Couldn't open $local: $!";
local $/ = "\012";
$CPAN::Config->{urllist} = [];
}
- print qq{
-
-Now we need to know where your favorite CPAN sites are located. Push
-a few sites onto the array (just in case the first on the array won\'t
-work). If you are mirroring CPAN to your local workstation, specify a
-file: URL.
-
-First, pick a nearby continent and country (you can pick several of
-each, separated by spaces, or none if you just want to keep your
-existing selections). Then, you will be presented with a list of URLs
-of CPAN mirrors in the countries you selected, along with previously
-selected URLs. Select some of those URLs, or just keep the old list.
-Finally, you will be prompted for any extra URLs -- file:, ftp:, or
-http: -- that host a CPAN mirror.
-
-};
+ print $prompts{urls_intro};
my (@cont, $cont, %cont, @countries, @urls, %seen);
my $no_previous_warn =
}
+BEGIN {
+
+my @prompts = (
+
+manual_config => qq[
+
+CPAN is the world-wide archive of perl resources. It consists of about
+100 sites that all replicate the same contents all around the globe.
+Many countries have at least one CPAN site already. The resources
+found on CPAN are easily accessible with the CPAN.pm module. If you
+want to use CPAN.pm, you have to configure it properly.
+
+If you do not want to enter a dialog now, you can answer 'no' to this
+question and I\'ll try to autoconfigure. (Note: you can revisit this
+dialog anytime later by typing 'o conf init' at the cpan prompt.)
+
+],
+
+config_intro => qq{
+
+The following questions are intended to help you with the
+configuration. The CPAN module needs a directory of its own to cache
+important index files and maybe keep a temporary mirror of CPAN files.
+This may be a site-wide directory or a personal directory.
+
+},
+
+# cpan_home => qq{ },
+
+cpan_home_where => qq{
+
+First of all, I\'d like to create this directory. Where?
+
+},
+
+keep_source_where => qq{
+
+If you like, I can cache the source files after I build them. Doing
+so means that, if you ever rebuild that module in the future, the
+files will be taken from the cache. The tradeoff is that it takes up
+space. How much space would you like to allocate to this cache? (If
+you don\'t want me to keep a cache, answer 0.)
+
+},
+
+build_cache_intro => qq{
+
+How big should the disk cache be for keeping the build directories
+with all the intermediate files\?
+
+},
+
+build_cache =>
+"Cache size for build directory (in MB)?",
+
+
+scan_cache_intro => qq{
+
+By default, each time the CPAN module is started, cache scanning is
+performed to keep the cache size in sync. To prevent this, answer
+'never'.
+
+},
+
+scan_cache => "Perform cache scanning (atstart or never)?",
+
+cache_metadata => qq{
+
+To considerably speed up the initial CPAN shell startup, it is
+possible to use Storable to create a cache of metadata. If Storable
+is not available, the normal index mechanism will be used.
+
+},
+
+term_is_latin => qq{
+
+The next option deals with the charset (aka character set) your
+terminal supports. In general, CPAN is English speaking territory, so
+the charset does not matter much, but some of the aliens out there who
+upload their software to CPAN bear names that are outside the ASCII
+range. If your terminal supports UTF-8, you should say no to the next
+question. If it supports ISO-8859-1 (also known as LATIN1) then you
+should say yes. If it supports neither, your answer does not matter
+because you will not be able to read the names of some authors
+anyway. If you answer no, names will be output in UTF-8.
+
+},
+
+histfile => qq{
+
+If you have one of the readline packages (Term::ReadLine::Perl,
+Term::ReadLine::Gnu, possibly others) installed, the interactive CPAN
+shell will have history support. The next two questions deal with the
+filename of the history file and with its size. If you do not want to
+set this variable, please hit SPACE RETURN to the following question.
+
+},
+
+show_upload_date_intro => qq{
+
+The 'd' and the 'm' command normally only show you information they
+have in their in-memory database and thus will never connect to the
+internet. If you set the 'show_upload_date' variable to true, 'm' and
+'d' will additionally show you the upload date of the module or
+distribution. Per default this feature is off because it may require a
+net connection to get at the upload date.
+
+},
+
+show_upload_date =>
+"Always try to show upload date with 'd' and 'm' command (yes/no)?",
+
+prerequisites_policy_intro => qq{
+
+The CPAN module can detect when a module which you are trying to build
+depends on prerequisites. If this happens, it can build the
+prerequisites for you automatically ('follow'), ask you for
+confirmation ('ask'), or just ignore them ('ignore'). Please set your
+policy to one of the three values.
+
+},
+
+prerequisites_policy =>
+ qq{Policy on building prerequisites (follow, ask or ignore)?},
+
+external_progs => qq{
+
+The CPAN module will need a few external programs to work properly.
+Please correct me, if I guess the wrong path for a program. Don\'t
+panic if you do not have some of them, just press ENTER for those. To
+disable the use of a download program, you can type a space followed
+by ENTER.
+
+},
+
+prefer_installer_intro => qq{
+
+When you have Module::Build installed and a module comes with both a
+Makefile.PL and a Build.PL, which shall have precedence? The two
+installer modules we have are the old and well established
+ExtUtils::MakeMaker (for short: EUMM) understands the Makefile.PL and
+the next generation installer Module::Build (MB) works with the
+Build.PL.
+
+},
+
+prefer_installer =>
+qq{In case you could choose, which installer would you prefer (EUMM or MB)?},
+
+makepl_arg_intro => qq{
+
+Every Makefile.PL is run by perl in a separate process. Likewise we
+run \'make\' and \'make install\' in separate processes. If you have
+any parameters \(e.g. PREFIX, LIB, UNINST or the like\) you want to
+pass to the calls, please specify them here.
+
+If you don\'t understand this question, just press ENTER.
+},
+
+makepl_arg => qq{
+Parameters for the 'perl Makefile.PL' command?
+Typical frequently used settings:
+
+ PREFIX=~/perl # non-root users (please see manual for more hints)
+
+Your choice: },
+
+make_arg => qq{Parameters for the 'make' command?
+Typical frequently used setting:
+
+ -j3 # dual processor system
+
+Your choice: },
+
+
+make_install_make_command => qq{Do you want to use a different make command for 'make install'?
+Cautious people will probably prefer:
+
+ su root -c make
+or
+ sudo make
+or
+ /path1/to/sudo -u admin_account /path2/to/make
+
+or some such. Your choice: },
+
+
+make_install_arg => qq{Parameters for the 'make install' command?
+Typical frequently used setting:
+
+ UNINST=1 # to always uninstall potentially conflicting files
+
+Your choice: },
+
+
+mbuildpl_arg_intro => qq{
+
+The next questions deal with Module::Build support.
+
+A Build.PL is run by perl in a separate process. Likewise we run
+'./Build' and './Build install' in separate processes. If you have any
+parameters you want to pass to the calls, please specify them here.
+
+},
+
+mbuildpl_arg => qq{Parameters for the 'perl Build.PL' command?
+Typical frequently used settings:
+
+ --install_base /home/xxx # different installation directory
+
+Your choice: },
+
+mbuild_arg => qq{Parameters for the './Build' command?
+Setting might be:
+
+ --extra_linker_flags -L/usr/foo/lib # non-standard library location
+
+Your choice: },
+
+
+mbuild_install_build_command => qq{Do you want to use a different command for './Build install'?
+Sudo users will probably prefer:
+
+ su root -c ./Build
+or
+ sudo ./Build
+or
+ /path1/to/sudo -u admin_account ./Build
+
+or some such. Your choice: },
+
+
+mbuild_install_arg => qq{Parameters for the './Build install' command?
+Typical frequently used setting:
+
+ --uninst 1 # uninstall conflicting files
+
+Your choice: },
+
+
+
+inactivity_timeout_intro => qq{
+
+Sometimes you may wish to leave the processes run by CPAN alone
+without caring about them. Because the Makefile.PL sometimes contains
+question you\'re expected to answer, you can set a timer that will
+kill a 'perl Makefile.PL' process after the specified time in seconds.
+
+If you set this value to 0, these processes will wait forever. This is
+the default and recommended setting.
+
+},
+
+inactivity_timeout =>
+qq{Timeout for inactivity during {Makefile,Build}.PL? },
+
+
+proxies => qq{
+
+If you\'re accessing the net via proxies, you can specify them in the
+CPAN configuration or via environment variables. The variable in
+the \$CPAN::Config takes precedence.
+
+},
+
+proxy_user => qq{
+
+If your proxy is an authenticating proxy, you can store your username
+permanently. If you do not want that, just press RETURN. You will then
+be asked for your username in every future session.
+
+},
+
+proxy_pass => qq{
+
+Your password for the authenticating proxy can also be stored
+permanently on disk. If this violates your security policy, just press
+RETURN. You will then be asked for the password in every future
+session.
+
+},
+
+urls_intro => qq{
+
+Now we need to know where your favorite CPAN sites are located. Push
+a few sites onto the array (just in case the first on the array won\'t
+work). If you are mirroring CPAN to your local workstation, specify a
+file: URL.
+
+First, pick a nearby continent and country (you can pick several of
+each, separated by spaces, or none if you just want to keep your
+existing selections). Then, you will be presented with a list of URLs
+of CPAN mirrors in the countries you selected, along with previously
+selected URLs. Select some of those URLs, or just keep the old list.
+Finally, you will be prompted for any extra URLs -- file:, ftp:, or
+http: -- that host a CPAN mirror.
+
+},
+
+password_warn => qq{
+
+Warning: Term::ReadKey seems not to be available, your password will
+be echoed to the terminal!
+
+},
+
+);
+
+die "Coding error in \@prompts declaration. Odd number of elements, above"
+ if (@prompts % 2);
+
+%prompts = @prompts;
+
+if (scalar(keys %prompts) != scalar(@prompts)/2) {
+
+ my %already;
+
+ for my $item (0..$#prompts) {
+ next if $item % 2;
+ die "$prompts[$item] is duplicated\n"
+ if $already{$prompts[$item]}++;
+ }
+
+}
+
+}
+
1;