-# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
package CPAN;
-$VERSION = '1.83_55';
+$VERSION = '1.83_58';
$VERSION = eval $VERSION;
use strict;
$otherhost ne '' && $thishost ne '' &&
$otherhost ne $thishost) {
$CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
- "reports other host $otherhost and other process $otherpid.\n".
+ "reports other host $otherhost and other ".
+ "process $otherpid.\n".
"Cannot proceed.\n"));
}
elsif (defined $otherpid && $otherpid) {
return if exists $self->{SIZE}{$dir};
return if $CPAN::Signal;
my($Du) = 0;
- unless (-x $dir) {
- unless (chmod 0755, $dir) {
- $CPAN::Frontend->mywarn("I have neither the -x permission nor the permission ".
- "to change the permission; cannot estimate disk usage ".
- "of '$dir'\n");
- sleep 5;
+ if (-e $dir) {
+ unless (-x $dir) {
+ unless (chmod 0755, $dir) {
+ $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
+ "permission to change the permission; cannot ".
+ "estimate disk usage of '$dir'\n");
+ $CPAN::Frontend->mysleep(5);
+ return;
+ }
+ }
+ } else {
+ $CPAN::Frontend->mywarn("Directory '$dir' has gone. Cannot continue.\n");
+ $CPAN::Frontend->mysleep(2);
return;
- }
}
find(
sub {
my $failed;
MFILE: for my $f (qw(CPAN.pm CPAN/HandleConfig.pm CPAN/FirstTime.pm CPAN/Tarzip.pm
CPAN/Debug.pm CPAN/Version.pm)) {
- next unless $INC{$f};
- my $pwd = CPAN::anycwd();
- CPAN->debug("reloading the whole '$f' from '$INC{$f}' while pwd='$pwd'")
- if $CPAN::DEBUG;
- my $read;
- for my $inc (@INC) {
- $read = File::Spec->catfile($inc,split /\//, $f);
- last if -f $read;
- }
- unless (-f $read) {
- $failed++;
- $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
- next MFILE;
- }
- my $fh = FileHandle->new($read) or
- $CPAN::Frontend->mydie("Could not open $read: $!");
- local($/);
- local $^W = 1;
local($SIG{__WARN__}) = paintdots_onreload(\$redef);
- my $eval = <$fh>;
- CPAN->debug(sprintf("evaling [%s...]\n",substr($eval,0,64)))
- if $CPAN::DEBUG;
- eval $eval;
- if ($@){
- $failed++;
- warn $@;
- }
+ $self->reload_this($f) or $failed++;
}
$CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
$failed++ unless $redef;
}
}
+sub reload_this {
+ my($self,$f) = @_;
+ return 1 unless $INC{$f};
+ my $pwd = CPAN::anycwd();
+ CPAN->debug("reloading the whole '$f' from '$INC{$f}' while pwd='$pwd'")
+ if $CPAN::DEBUG;
+ my $read;
+ for my $inc (@INC) {
+ $read = File::Spec->catfile($inc,split /\//, $f);
+ last if -f $read;
+ }
+ unless (-f $read) {
+ $read = $INC{$f};
+ }
+ unless (-f $read) {
+ $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
+ return;
+ }
+ my $fh = FileHandle->new($read) or
+ $CPAN::Frontend->mydie("Could not open $read: $!");
+ local($/);
+ local $^W = 1;
+ my $eval = <$fh>;
+ CPAN->debug(sprintf("evaling [%s...]\n",substr($eval,0,64)))
+ if $CPAN::DEBUG;
+ eval $eval;
+ if ($@){
+ warn $@;
+ return;
+ }
+ return 1;
+}
+
#-> sub CPAN::Shell::_binary_extensions ;
sub _binary_extensions {
my($self) = shift @_;
shift->_u_r_common("u",@_);
}
-# XXX intentionally undocumented because not considered enough
#-> sub CPAN::Shell::failed ;
sub failed {
my($self,$only_id,$silent) = @_;
- my $print = "";
+ my @failed;
DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
my $failed = "";
for my $nosayer (qw(signature_verify make make_test install)) {
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}->text,
- );
+ #$print .= sprintf(
+ # " %-45s: %s %s\n",
+ push @failed, [
+ $d->{$failed}->commandid,
+ $id,
+ $failed,
+ $d->{$failed}->text,
+ ];
}
my $scope = $only_id ? "command" : "session";
- if ($print) {
- $CPAN::Frontend->myprint("Failed installations in this $scope:\n$print");
+ if (@failed) {
+ my $print = join "",
+ map { sprintf " %-45s: %s %s\n", @$_[1,2,3] }
+ sort { $a->[0] <=> $b->[0] } @failed;
+ $CPAN::Frontend->myprint("Failed during this $scope:\n$print");
} elsif (!$only_id || !$silent) {
- $CPAN::Frontend->myprint("No installations failed in this $scope\n");
+ $CPAN::Frontend->myprint("Nothing failed in this $scope\n");
}
}
-# XXX intentionally undocumented because not considered enough
+# XXX intentionally undocumented because completely bogus, unportable,
+# useless, etc.
+
#-> sub CPAN::Shell::status ;
sub status {
my($self) = @_;
die "\n";
}
+# use this only for unrecoverable errors!
+sub unrecoverable_error {
+ my($self,$what) = @_;
+ my @lines = split /\n/, $what;
+ my $longest = 0;
+ for my $l (@lines) {
+ $longest = length $l if length $l > $longest;
+ }
+ $longest = 62 if $longest > 62;
+ for my $l (@lines) {
+ if ($l =~ /^\s*$/){
+ $l = "\n";
+ next;
+ }
+ $l = "==> $l";
+ if (length $l < 66) {
+ $l = pack "A66 A*", $l, "<==";
+ }
+ $l .= "\n";
+ }
+ unshift @lines, "\n";
+ $self->mydie(join "", @lines);
+ die "\n";
+}
+
sub mysleep {
my($self, $sleep) = @_;
sleep $sleep;
$ro->{CPAN_COMMENT}
}
+# CPAN::Distribution::undelay
sub undelay {
my $self = shift;
delete $self->{later};
$self->debug(sprintf "changed directory to %s", CPAN::anycwd())
if $CPAN::DEBUG;
} else {
- unless (-x $todir) {
- unless (chmod 0755, $todir) {
- my $cwd = CPAN::anycwd();
- $CPAN::Frontend->mywarn("I have neither the -x permission nor the permission ".
- "to change the permission; cannot chdir ".
- "to '$todir'\n");
- sleep 5;
- $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
- qq{to todir[$todir]: $!});
- }
+ if (-e $todir) {
+ unless (-x $todir) {
+ unless (chmod 0755, $todir) {
+ my $cwd = CPAN::anycwd();
+ $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
+ "permission to change the permission; cannot ".
+ "chdir to '$todir'\n");
+ $CPAN::Frontend->mysleep(5);
+ $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
+ qq{to todir[$todir]: $!});
+ }
+ }
+ } else {
+ $CPAN::Frontend->mydie("Directory '$todir' has gone. Cannot continue.\n");
}
if (chdir $todir) {
$self->debug(sprintf "changed directory to %s", CPAN::anycwd())
$self->safe_chdir($builddir);
$self->debug("Removing tmp") if $CPAN::DEBUG;
File::Path::rmtree("tmp");
- mkdir "tmp", 0755 or Carp::croak "Couldn't mkdir tmp: $!";
+ unless (mkdir "tmp", 0755) {
+ $CPAN::Frontend->unrecoverable_error(<<EOF);
+Couldn't mkdir '$builddir/tmp': $!
+
+Cannot continue: Please find the reason why I cannot make the
+directory
+$builddir/tmp
+and fix the problem, then retry.
+
+EOF
+ }
if ($CPAN::Signal){
$self->safe_chdir($sub_wd);
return;
-d $packagedir and $CPAN::Frontend->myprint("Removing previously used ".
"$packagedir\n");
File::Path::rmtree($packagedir);
- File::Copy::move($distdir,$packagedir) or
- Carp::confess("Couldn't move $distdir to $packagedir: $!");
+ unless (File::Copy::move($distdir,$packagedir)) {
+ $CPAN::Frontend->unrecoverable_error(<<EOF);
+Couldn't move '$distdir' to '$packagedir': $!
+
+Cannot continue: Please find the reason why I cannot move
+$builddir/tmp/$distdir
+to
+$packagedir
+and fix the problem, then retry
+
+EOF
+ }
$self->debug(sprintf("moved distdir[%s] to packagedir[%s] -e[%s]-d[%s]",
$distdir,
$packagedir,
}
}
if (lc($prefer_installer) eq "mb") {
- $self->{modulebuild} = "YES";
+ $self->{modulebuild} = 1;
} elsif (! $mpl_exists) {
$self->debug(sprintf("makefilepl[%s]anycwd[%s]",
$mpl,
defined $self->{'make'} and push @e,
"Has already been processed within this session";
- exists $self->{later} and length($self->{later}) and
- push @e, $self->{later};
+ if (exists $self->{later} and length($self->{later})) {
+ if ($self->unsat_prereq) {
+ push @e, $self->{later};
+ } else {
+ delete $self->{later};
+ }
+ }
$CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
}
} else {
$ret = system($system);
if ($ret != 0) {
- $self->{writemakefile} = "NO Makefile.PL returned status $ret";
+ $self->{writemakefile} = "NO '$system' returned status $ret";
return;
}
}
delete $self->{make_clean}; # if cleaned before, enable next
} else {
$self->{writemakefile} =
- qq{NO Makefile.PL refused to write a Makefile.};
+ qq{NO -- Unknown reason.};
# It's probably worth it to record the reason, so let's retry
# local $/;
# my $fh = IO::File->new("$system |"); # STDERR? STDIN?
return $CPAN::Config->{'make'} || $Config::Config{make} || 'make';
}
+#-> sub CPAN::Distribution::follow_prereqs ;
sub follow_prereqs {
my($self) = shift;
my(@prereq) = grep {$_ ne "perl"} @_;
exists $self->{prereq_pm_detected} && $self->{prereq_pm_detected};
return unless $self->{writemakefile} # no need to have succeeded
# but we must have run it
- || $self->{mudulebuild};
+ || $self->{modulebuild};
my $req;
if (my $yaml = $self->read_yaml) {
$req = $yaml->{requires};
}
}
}
+ if (-f "Build.PL" && ! -f "Makefile.PL" && ! exists $req->{"Module::Build"}) {
+ $CPAN::Frontend->mywarn(" Warning: CPAN.pm discovered Module::Build as ".
+ "undeclared prerequisite.\n".
+ " Adding it now as a prerequisite.\n"
+ );
+ $CPAN::Frontend->mysleep(5);
+ $req->{"Module::Build"} = 0;
+ delete $self->{writemakefile};
+ }
$self->{prereq_pm_detected}++;
return $self->{prereq_pm} = $req;
}
$ro->{description}
}
+sub distribution {
+ my($self) = @_;
+ CPAN::Shell->expand("Distribution",$self->cpan_file);
+}
+
+# sub CPAN::Module::undelay
sub undelay {
my $self = shift;
delete $self->{later};
$color_on = Term::ANSIColor::color("green");
$color_off = Term::ANSIColor::color("reset");
}
- push @m, sprintf("%-15s %s%-15s%s (%s)\n",
+ push @m, sprintf("%-8s %s%-22s%s (%s)\n",
$class,
$color_on,
$self->id,
$color_off,
- $self->cpan_file);
+ $self->distribution->pretty_id,
+ );
join "", @m;
}
close $fh;
last if @result;
}
+ for (@result) {
+ s/^\s+//;
+ s/\s+$//;
+ }
join " ", @result;
}
use CPAN;
- autobundle, clean, install, make, recompile, test
+ # modules:
+
+ $mod = "Acme::Meta";
+ install $mod;
+ CPAN::Shell->install($mod); # same thing
+ CPAN::Shell->expandany($mod)->install; # same thing
+ CPAN::Shell->expand("Module",$mod)->install; # same thing
+ CPAN::Shell->expand("Module",$mod)
+ ->distribution->install; # same thing
+
+ # distributions:
+
+ $distro = "NWCLARK/Acme-Meta-0.01.tar.gz";
+ install $distro; # same thing
+ CPAN::Shell->install($distro); # same thing
+ CPAN::Shell->expandany($distro)->install; # same thing
+ CPAN::Shell->expand("Module",$distro)->install; # same thing
=head1 STATUS
=head1 DESCRIPTION
The CPAN module is designed to automate the make and install of perl
-modules and extensions. It includes some primitive searching capabilities and
-knows how to use Net::FTP or LWP (or lynx or an external ftp client)
-to fetch the raw data from the net.
+modules and extensions. It includes some primitive searching
+capabilities and knows how to use Net::FTP or LWP (or some external
+download clients) to fetch the raw data from the net.
Modules are fetched from one or more of the mirrored CPAN
(Comprehensive Perl Archive Network) sites and unpacked in a dedicated
the make processes and deletes excess space according to a simple FIFO
mechanism.
-For extended searching capabilities there's a plugin for CPAN available,
-L<C<CPAN::WAIT>|CPAN::WAIT>. C<CPAN::WAIT> is a full-text search engine
-that indexes all documents available in CPAN authors directories. If
-C<CPAN::WAIT> is installed on your system, the interactive shell of
-CPAN.pm will enable the C<wq>, C<wr>, C<wd>, C<wl>, and C<wh> commands
-which send queries to the WAIT server that has been configured for your
-installation.
-
-All other methods provided are accessible in a programmer style and in an
+All methods provided are accessible in a programmer style and in an
interactive shell style.
=head2 Interactive Mode
item is displayed. If the search finds one item, the result is
displayed with the rather verbose method C<as_string>, but if we find
more than one, we display each object with the terse method
-<as_glimpse>.
+C<as_glimpse>.
=item make, test, install, clean modules or distributions
a module, CPAN determines the distribution file in which this module
is included and processes that, following any dependencies named in
the module's META.yml or Makefile.PL (this behavior is controlled by
-I<prerequisites_policy>.)
+the configuration parameter C<prerequisites_policy>.)
Any C<make> or C<test> are run unconditionally. An
and doesn't try to build a package a second time regardless if it
succeeded or not. The C<force> pragma may precede another command
(currently: C<make>, C<test>, or C<install>) and executes the
-command from scratch.
+command from scratch and tries to continue in case of some errors.
Example:
C<make>, C<test> or C<install> for some reason in the currently
running shell session.
+=item Lockfile
+
+Interactive sessions maintain a lockfile, per default C<~/.cpan/.lock>
+(but the directory can be configured via the C<cpan_home> config
+variable). The shell is a bit picky if you try to start another CPAN
+session. It dies immediately if there is a lockfile and the lock seems
+to belong to a running process. In case you want to run a second shell
+session, it is probably safest to maintain another directory, say
+C<~/.cpan-for-X/> and a C<~/.cpan-for-X/CPAN/MyConfig.pm> that
+contains the configuration options. Then you can start the second
+shell with
+
+ perl -I ~/.cpan-for-X -MCPAN::MyConfig -MCPAN -e shell
+
=item Signals
CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
=cut
# Local Variables:
+# coding: utf-8;
# mode: cperl
# cperl-indent-level: 4
# End: