# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
use strict;
package CPAN;
-$CPAN::VERSION = '1.88_53';
+$CPAN::VERSION = '1.88_57';
$CPAN::VERSION = eval $CPAN::VERSION;
use CPAN::HandleConfig;
$CPAN::Defaultrecent ||= "http://search.cpan.org/recent";
-use vars qw($VERSION @EXPORT $AUTOLOAD
- $DEBUG $META $HAS_USABLE $term
- $GOTOSHELL
- $Signal $Suppress_readline $Frontend
- @Defaultsites $Have_warned $Defaultdocs $Defaultrecent
+use vars qw(
+ $AUTOLOAD
$Be_Silent
+ $CONFIG_DIRTY
+ $DEBUG
+ $Defaultdocs
+ $Defaultrecent
+ $Frontend
+ $GOTOSHELL
+ $HAS_USABLE
+ $Have_warned
+ $META
+ $Signal
+ $Suppress_readline
+ $VERSION
$autoload_recursion
+ $term
+ @Defaultsites
+ @EXPORT
);
@CPAN::ISA = qw(CPAN::Debug Exporter);
readme
recent
recompile
+ report
shell
test
upgrade
$CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
my $command = shift @line;
eval { CPAN::Shell->$command(@line) };
- warn $@ if $@;
- if ($command =~ /^(make|test|install|force|notest|clean|upgrade)$/) {
+ if ($@){
+ require Carp;
+ Carp::cluck($@);
+ }
+ if ($command =~ /^(make|test|install|force|notest|clean|report|upgrade)$/) {
CPAN::Shell->failed($CPAN::CurrentCommandId,1);
}
soft_chdir_with_alternatives(\@cwd);
}
}
}
- if ($CPAN::DEBUG && $CPAN::DEBUG & $CPAN::DEBUG{CPAN}) {
- # debugging 'incommandcolor': should always be off at the end of a command
- # (incommandcolor is used to detect recursive dependencies)
- for my $class (qw(Module Distribution)) {
- for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
- next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
- CPAN->debug("BUG: $class '$dm' was in command state, resetting");
- delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
- }
+ for my $class (qw(Module Distribution)) {
+ # again unsafe meta access?
+ for my $dm (keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
+ next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
+ CPAN->debug("BUG: $class '$dm' was in command state, resetting");
+ delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
}
}
if ($GOTOSHELL) {
}
}
+# CPAN::_yaml_loadfile
+sub _yaml_loadfile {
+ my($self,$local_file) = @_;
+ my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
+ if ($CPAN::META->has_inst($yaml_module)) {
+ my $code = UNIVERSAL::can($yaml_module, "LoadFile");
+ my @yaml;
+ eval { @yaml = $code->($local_file); };
+ if ($@) {
+ $CPAN::Frontend->mydie("Alert: While trying to parse YAML file\n".
+ " $local_file\n".
+ "with $yaml_module the following error was encountered:\n".
+ " $@\n"
+ );
+ }
+ return \@yaml;
+ } else {
+ $CPAN::Frontend->mywarn("'$yaml_module' not installed, cannot parse '$local_file'\n");
+ }
+ return +[];
+}
+
package CPAN::CacheMgr;
use strict;
@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
recent
recompile
reload
+ report
scripts
test
upgrade
],
'File::HomeDir' => [
sub {require File::HomeDir;
- unless (File::HomeDir->VERSION >= 0.52){
+ unless (File::HomeDir::->VERSION >= 0.52){
for ("Will not use File::HomeDir, need 0.52\n") {
$CPAN::Frontend->mywarn($_);
die $_;
unlink $META->{LOCK};
# require Carp;
# Carp::cluck("DEBUGGING");
+ if ( $CPAN::CONFIG_DIRTY ) {
+ $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
+ }
$CPAN::Frontend->myprint("Lockfile removed.\n");
}
close $fh;
}
+#-> sub CPAN::is_tested
sub is_tested {
my($self,$what) = @_;
$self->{is_tested}{$what} = 1;
}
+#-> sub CPAN::is_installed
# unsets the is_tested flag: as soon as the thing is installed, it is
# not needed in set_perl5lib anymore
sub is_installed {
delete $self->{is_tested}{$what};
}
+#-> sub CPAN::set_perl5lib
sub set_perl5lib {
- my($self) = @_;
+ my($self,$for) = @_;
+ unless ($for) {
+ (undef,undef,undef,$for) = caller(1);
+ $for =~ s/.*://;
+ }
$self->{is_tested} ||= {};
return unless %{$self->{is_tested}};
my $env = $ENV{PERL5LIB};
$env = $ENV{PERLLIB} unless defined $env;
my @env;
push @env, $env if defined $env and length $env;
- my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
- $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+ #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
+ #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+ my @dirs = map {("$_/blib/arch", "$_/blib/lib")} sort keys %{$self->{is_tested}};
+ if (@dirs < 15) {
+ $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB for $for\n");
+ } else {
+ my @d = map {s/^\Q$CPAN::Config->{'build_dir'}/%BUILDDIR%/; $_ }
+ sort keys %{$self->{is_tested}};
+ $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib subdirs of ".
+ "@d to PERL5LIB; ".
+ "%BUILDDIR%=$CPAN::Config->{'build_dir'} ".
+ "for $for\n"
+ );
+ }
+
$ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
}
# 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
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') {
unless ($file && -f $file) {
# this thingie is not in the INC path, maybe CPAN/MyConfig.pm?
$file = $INC{$f};
- @inc = substr($file,0,-length($f)); # bring in back to me!
+ unless (CPAN->has_inst("File::Basename")) {
+ @inc = File::Basename::dirname($file);
+ } else {
+ # do we ever need this?
+ @inc = substr($file,0,-length($f)-1); # bring in back to me!
+ }
}
CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
unless (-f $file) {
}
}
+#-> sub CPAN::Shell::report ;
+sub report {
+ my($self,@args) = @_;
+ unless ($CPAN::META->has_inst("CPAN::Reporter")) {
+ $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
+ }
+ local $CPAN::Config->{test_report} = 1;
+ $self->force("test",@args); # force is there so that the test be
+ # re-run (as documented)
+}
+
#-> sub CPAN::Shell::upgrade ;
sub upgrade {
my($self,@args) = @_;
}
my $color_on = "";
my $color_off = "";
- # $GLOBAL_AUTOLOAD_RECURSION = 12;
if (
$COLOR_REGISTERED
&&
DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
my $failed = "";
NAY: for my $nosayer (
+ "unwrapped",
"writemakefile",
"signature_verify",
"make",
sub expandany {
my($self,$s) = @_;
CPAN->debug("s[$s]") if $CPAN::DEBUG;
- if ($s =~ m|/|) { # looks like a file
+ if ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
$s = CPAN::Distribution->normalize($s);
return $CPAN::META->instance('CPAN::Distribution',$s);
# Distributions spring into existence, not expand
$obj = $s;
} elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
} elsif ($s =~ m|^/|) { # looks like a regexp
- $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
- "not supported.\nRejecting argument '$s'\n");
- $CPAN::Frontend->mysleep(2);
- next;
+ if (substr($s,-1,1) eq ".") {
+ $obj = CPAN::Shell->expandany($s);
+ } else {
+ $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
+ "not supported.\nRejecting argument '$s'\n");
+ $CPAN::Frontend->mysleep(2);
+ next;
+ }
} elsif ($meth eq "ls") {
$self->globls($s,\@pragma);
next STHING;
}
for my $obj (@qcopy) {
$obj->color_cmd_tmps(0,0);
- delete $obj->{incommandcolor};
}
}
my($aslocal_dir) = File::Basename::dirname($aslocal);
File::Path::mkpath($aslocal_dir);
my $ftpbin = $CPAN::Config->{ftp};
- unless (length $ftpbin && MM->maybe_command($ftpbin)) {
+ unless ($ftpbin && length $ftpbin && MM->maybe_command($ftpbin)) {
$CPAN::Frontend->myprint("No external ftp command available\n\n");
return;
}
local($_);
push @lines, split /\012/ while <FH>;
my $i = 0;
- my $modulus = int(@lines/75) || 1;
+ my $modulus = int($#lines/75) || 1;
+ CPAN->debug(sprintf "modulus[%d]lines[%s]", $modulus, scalar @lines) if $CPAN::DEBUG;
foreach (@lines) {
my($userid,$fullname,$email) =
- m/alias\s+(\S+)\s+\"([^\"\<]+)\s+\<([^\>]+)\>\"/;
- next unless $userid && $fullname && $email;
-
- # instantiate an author object
- my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
- $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
+ m/alias\s+(\S+)\s+\"([^\"\<]*)\s+\<(.*)\>\"/;
+ $fullname ||= $email;
+ if ($userid && $fullname && $email){
+ my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
+ $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
+ } else {
+ CPAN->debug(sprintf "line[%s]", $_) if $CPAN::DEBUG;
+ }
$CPAN::Frontend->myprint(".") unless $i++ % $modulus;
return if $CPAN::Signal;
}
CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
my(%exists);
my $i = 0;
- my $modulus = int(@lines/75) || 1;
+ my $modulus = int($#lines/75) || 1;
foreach (@lines) {
# before 1.56 we split into 3 and discarded the rest. From
# 1.57 we assign remaining text to $comment thus allowing to
Carp::confess($@) if $@;
return if $CPAN::Signal;
my $i = 0;
- my $until = keys %$ret;
+ my $until = keys(%$ret) - 1;
my $modulus = int($until/75) || 1;
CPAN->debug(sprintf "until[%d]", $until) if $CPAN::DEBUG;
for (keys %$ret) {
exists $self->{RO} and return $self->{RO};
}
+#-> sub CPAN::InfoObj::cpan_userid
sub cpan_userid {
my $self = shift;
- my $ro = $self->ro or return "N/A"; # N/A for bundles found locally
- return $ro->{CPAN_USERID} || "N/A";
+ my $ro = $self->ro;
+ if ($ro) {
+ return $ro->{CPAN_USERID} || "N/A";
+ } else {
+ $self->debug("ID[$self->{ID}]");
+ # N/A for bundles found locally
+ return "N/A";
+ }
}
sub id { shift->{ID}; }
push @m, $class, " id = $self->{ID}\n";
my $ro;
unless ($ro = $self->ro) {
- $CPAN::Frontend->mydie("Unknown object $self->{ID}");
+ if (substr($self->{ID},-1,1) eq ".") { # directory
+ $ro = +{};
+ } else {
+ $CPAN::Frontend->mydie("Unknown object $self->{ID}");
+ }
}
for (sort keys %$ro) {
# next if m/^(ID|RO)$/;
next unless defined $ro->{$_};
push @m, sprintf " %-12s %s%s\n", $_, $ro->{$_}, $extra;
}
- for (sort keys %$self) {
+ KEY: for (sort keys %$self) {
next if m/^(ID|RO)$/;
+ unless (defined $self->{$_}) {
+ delete $self->{$_};
+ next KEY;
+ }
if (ref($self->{$_}) eq "ARRAY") {
push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}";
} elsif (ref($self->{$_}) eq "HASH") {
+ my $value;
+ if (/^CONTAINSMODS$/) {
+ $value = join(" ",sort keys %{$self->{$_}});
+ } elsif (/^prereq_pm$/) {
+ my @value;
+ my $v = $self->{$_};
+ for my $x (sort keys %$v) {
+ my @svalue;
+ for my $y (sort keys %{$v->{$x}}) {
+ push @svalue, "$y=>$v->{$x}{$y}";
+ }
+ push @value, "$x\:" . join ",", @svalue;
+ }
+ $value = join ";", @value;
+ } else {
+ $value = $self->{$_};
+ }
push @m, sprintf(
" %-12s %s\n",
$_,
- join(" ",sort keys %{$self->{$_}}),
+ $value,
);
} else {
push @m, sprintf " %-12s %s\n", $_, $self->{$_};
sub normalize {
my($self,$s) = @_;
$s = $self->id unless defined $s;
- if (
+ if (substr($s,-1,1) eq ".") {
+ if ($s eq ".") {
+ $s = "$CPAN::iCwd/.";
+ } elsif (File::Spec->file_name_is_absolute($s)) {
+ } elsif (File::Spec->can("rel2abs")) {
+ $s = File::Spec->rel2abs($s);
+ } else {
+ $CPAN::Frontend->mydie("Your File::Spec is too old, please upgrade File::Spec");
+ }
+ CPAN->debug("s[$s]") if $CPAN::DEBUG;
+ unless ($CPAN::META->exists("CPAN::Distribution", $s)) {
+ for ($CPAN::META->instance("CPAN::Distribution", $s)) {
+ $_->{build_dir} = $s;
+ $_->{archived} = "local_directory";
+ $_->{unwrapped} = CPAN::Distrostatus->new("YES -- local_directory");
+ }
+ }
+ } elsif (
$s =~ tr|/|| == 1
or
$s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/|
#-> sub CPAN::Distribution::author ;
sub author {
my($self) = @_;
- my($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
+ my($authorid);
+ if (substr($self->id,-1,1) eq ".") {
+ $authorid = "LOCAL";
+ } else {
+ ($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
+ }
CPAN::Shell->expand("Author",$authorid);
}
$local_wanted)) {
$CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n");
}
- if ($CPAN::META->has_inst("YAML")) {
- my $yaml = YAML::LoadFile($local_file);
- return $yaml;
- } else {
- $CPAN::Frontend->mydie("Yaml not installed, cannot parse '$local_file'\n");
+ my $yaml = CPAN->_yaml_loadfile($local_file)->[0];
+}
+
+#-> sub CPAN::Distribution::cpan_userid
+sub cpan_userid {
+ my $self = shift;
+ if ($self->{ID} =~ m{[A-Z]/[A-Z\-]{2}/([A-Z\-]+)/}) {
+ return $1;
}
+ return $self->SUPER::cpan_userid;
}
#-> sub CPAN::Distribution::pretty_id
#-> sub CPAN::Distribution::get ;
sub get {
my($self) = @_;
+ local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+ ? $ENV{PERL5LIB}
+ : ($ENV{PERLLIB} || "");
+
+ $CPAN::META->set_perl5lib;
+ local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
EXCUSE: {
my @e;
- exists $self->{'build_dir'} and push @e,
- "Is already unwrapped into directory $self->{'build_dir'}";
- $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e;
+ exists $self->{build_dir} and push @e,
+ "Is already unwrapped into directory $self->{build_dir}";
+
+ exists $self->{unwrapped} and (
+ $self->{unwrapped}->can("failed") ?
+ $self->{unwrapped}->failed :
+ $self->{unwrapped} =~ /^NO/
+ )
+ and push @e, "Unwrapping had some problem, won't try again without force";
+
+ $CPAN::Frontend->mywarn(join "", map {" $_\n"} @e) and return if @e;
}
my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible
}
$CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
}
- $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
+
+ $self->debug("local_wanted[$local_wanted]local_file[$local_file]") if $CPAN::DEBUG;
$self->{localfile} = $local_file;
return if $CPAN::Signal;
#
# Unpack the goods
#
- $self->debug("local_file[$local_file]") if $CPAN::DEBUG;
my $ct = CPAN::Tarzip->new($local_file);
if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i){
$self->{was_uncompressed}++ unless $ct->gtest();
$self->unzip_me($ct);
} else {
$self->{was_uncompressed}++ unless $ct->gtest();
- $self->debug("calling pm2dir for local_file[$local_file]")
- if $CPAN::DEBUG;
$local_file = $self->handle_singlefile($local_file);
# } else {
# $self->{archived} = "NO";
)) if $CPAN::DEBUG;
} else {
my $userid = $self->cpan_userid;
- unless ($userid) {
- CPAN->debug("no userid? self[$self]");
+ CPAN->debug("userid[$userid]");
+ if (!$userid or $userid eq "N/A") {
$userid = "anon";
}
my $pragmatic_dir = $userid . '000';
File::Path::rmtree("tmp");
$self->safe_chdir($packagedir);
- if ($CPAN::Config->{check_sigs}) {
- if ($CPAN::META->has_inst("Module::Signature")) {
- if (-f "SIGNATURE") {
- $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
- my $rv = Module::Signature::verify();
- if ($rv != Module::Signature::SIGNATURE_OK() and
- $rv != Module::Signature::SIGNATURE_MISSING()) {
- $CPAN::Frontend->myprint(
- qq{\nSignature invalid for }.
- qq{distribution file. }.
- qq{Please investigate.\n\n}.
- $self->as_string,
- $CPAN::META->instance(
- 'CPAN::Author',
- $self->cpan_userid,
- )->as_string
- );
-
- my $wrap =
- 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
-},
- $self->{localfile},
- $self->pretty_id,
- );
- $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");
- $self->debug("Module::Signature has verified") if $CPAN::DEBUG;
- }
- } else {
- $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n});
- }
- } else {
- $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
- }
- }
+ $self->_signature_business();
$self->safe_chdir($builddir);
return if $CPAN::Signal;
my $prefer_installer = "eumm"; # eumm|mb
if (-f File::Spec->catfile($packagedir,"Build.PL")) {
if ($mpl_exists) { # they *can* choose
- if ($CPAN::META->has_inst("Module::Build")) {
- $prefer_installer = $CPAN::Config->{prefer_installer};
- }
+ $prefer_installer = CPAN::HandleConfig->prefs_lookup($self,
+ q{prefer_installer});
} else {
$prefer_installer = "mb";
}
}
+ return unless $self->patch;
if (lc($prefer_installer) eq "mb") {
$self->{modulebuild} = 1;
} elsif (! $mpl_exists) {
- $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
- $mpl,
- CPAN::anycwd(),
- )) if $CPAN::DEBUG;
- my($configure) = File::Spec->catfile($packagedir,"Configure");
- if (-f $configure) {
- # do we have anything to do?
- $self->{'configure'} = $configure;
- } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
- $CPAN::Frontend->mywarn(qq{
+ $self->_edge_cases($mpl,$packagedir,$local_file);
+ }
+
+ return $self;
+}
+
+#-> CPAN::Distribution::patch
+sub try_download {
+ my($self,$patch) = @_;
+ my $norm = $self->normalize($patch);
+ my($local_wanted) =
+ File::Spec->catfile(
+ $CPAN::Config->{keep_source_where},
+ "authors",
+ "id",
+ split(/\//,$norm),
+ );
+ $self->debug("Doing localize") if $CPAN::DEBUG;
+ return CPAN::FTP->localize("authors/id/$norm",
+ $local_wanted);
+}
+
+#-> CPAN::Distribution::patch
+sub patch {
+ my($self) = @_;
+ if (my $patches = $self->prefs->{patches}) {
+ return unless @$patches;
+ $self->safe_chdir($self->{build_dir});
+ CPAN->debug("patches[$patches]");
+ my $patchbin = $CPAN::Config->{patch};
+ unless ($patchbin && length $patchbin) {
+ $CPAN::Frontend->mydie("No external patch command configured\n\n".
+ "Please run 'o conf init /patch/'\n\n");
+ }
+ unless (MM->maybe_command($patchbin)) {
+ $CPAN::Frontend->mydie("No external patch command available\n\n".
+ "Please run 'o conf init /patch/'\n\n");
+ }
+ $patchbin = CPAN::HandleConfig->safe_quote($patchbin);
+ my $args = "-b -g0 -p1 -N --fuzz=3";
+ my $countedpatches = @$patches == 1 ? "1 patch" : (scalar @$patches . " patches");
+ $CPAN::Frontend->myprint("Going to apply $countedpatches:\n");
+ for my $patch (@$patches) {
+ unless (-f $patch) {
+ if (my $trydl = $self->try_download($patch)) {
+ $patch = $trydl;
+ } else {
+ my $fail = "Could not find patch '$patch'";
+ $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+ delete $self->{build_dir};
+ return;
+ }
+ }
+ $CPAN::Frontend->myprint(" $patch\n");
+ my $readfh = CPAN::Tarzip->TIEHANDLE($patch);
+ my $writefh = FileHandle->new;
+ unless (open $writefh, "|$patchbin $args") {
+ my $fail = "Could not fork '$patchbin $args'";
+ $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+ delete $self->{build_dir};
+ return;
+ }
+ while (my $x = $readfh->READLINE) {
+ print $writefh $x;
+ }
+ unless (close $writefh) {
+ my $fail = "Could not apply patch '$patch'";
+ $CPAN::Frontend->mywarn("$fail; cannot continue\n");
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
+ delete $self->{build_dir};
+ return;
+ }
+ }
+ $self->{patched}++;
+ }
+ return 1;
+}
+
+#-> sub CPAN::Distribution::_edge_cases
+# with "configure" or "Makefile" or single file scripts
+sub _edge_cases {
+ my($self,$mpl,$packagedir,$local_file) = @_;
+ $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
+ $mpl,
+ CPAN::anycwd(),
+ )) if $CPAN::DEBUG;
+ my($configure) = File::Spec->catfile($packagedir,"Configure");
+ if (-f $configure) {
+ # do we have anything to do?
+ $self->{configure} = $configure;
+ } elsif (-f File::Spec->catfile($packagedir,"Makefile")) {
+ $CPAN::Frontend->mywarn(qq{
Package comes with a Makefile and without a Makefile.PL.
We\'ll try to build it with that Makefile then.
});
- $self->{writemakefile} = CPAN::Distrostatus->new("YES");
- $CPAN::Frontend->mysleep(2);
- } else {
- my $cf = $self->called_for || "unknown";
- if ($cf =~ m|/|) {
- $cf =~ s|.*/||;
- $cf =~ s|\W.*||;
- }
- $cf =~ s|[/\\:]||g; # risk of filesystem damage
- $cf = "unknown" unless length($cf);
- $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL.
+ $self->{writemakefile} = CPAN::Distrostatus->new("YES");
+ $CPAN::Frontend->mysleep(2);
+ } else {
+ my $cf = $self->called_for || "unknown";
+ if ($cf =~ m|/|) {
+ $cf =~ s|.*/||;
+ $cf =~ s|\W.*||;
+ }
+ $cf =~ s|[/\\:]||g; # risk of filesystem damage
+ $cf = "unknown" unless length($cf);
+ $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL.
(The test -f "$mpl" returned false.)
Writing one on our own (setting NAME to $cf)\a\n});
- $self->{had_no_makefile_pl}++;
- $CPAN::Frontend->mysleep(3);
-
- # Writing our own Makefile.PL
-
- my $script = "";
- if ($self->{archived} eq "maybe_pl"){
- my $fh = FileHandle->new;
- my $script_file = File::Spec->catfile($packagedir,$local_file);
- $fh->open($script_file)
- or Carp::croak("Could not open $script_file: $!");
- local $/ = "\n";
- # name parsen und prereq
- my($state) = "poddir";
- my($name, $prereq) = ("", "");
- while (<$fh>){
- if ($state eq "poddir" && /^=head\d\s+(\S+)/) {
- if ($1 eq 'NAME') {
- $state = "name";
- } elsif ($1 eq 'PREREQUISITES') {
- $state = "prereq";
- }
- } elsif ($state =~ m{^(name|prereq)$}) {
- if (/^=/) {
- $state = "poddir";
- } elsif (/^\s*$/) {
- # nop
- } elsif ($state eq "name") {
- if ($name eq "") {
- ($name) = /^(\S+)/;
- $state = "poddir";
- }
- } elsif ($state eq "prereq") {
- $prereq .= $_;
- }
- } elsif (/^=cut\b/) {
- last;
- }
- }
- $fh->close;
+ $self->{had_no_makefile_pl}++;
+ $CPAN::Frontend->mysleep(3);
- for ($name) {
- s{.*<}{}; # strip X<...>
- s{>.*}{};
- }
- chomp $prereq;
- $prereq = join " ", split /\s+/, $prereq;
- my($PREREQ_PM) = join("\n", map {
- s{.*<}{}; # strip X<...>
- s{>.*}{};
- if (/[\s\'\"]/) { # prose?
- } else {
- s/[^\w:]$//; # period?
- " "x28 . "'$_' => 0,";
+ # Writing our own Makefile.PL
+
+ my $script = "";
+ if ($self->{archived} eq "maybe_pl") {
+ my $fh = FileHandle->new;
+ my $script_file = File::Spec->catfile($packagedir,$local_file);
+ $fh->open($script_file)
+ or Carp::croak("Could not open $script_file: $!");
+ local $/ = "\n";
+ # name parsen und prereq
+ my($state) = "poddir";
+ my($name, $prereq) = ("", "");
+ while (<$fh>) {
+ if ($state eq "poddir" && /^=head\d\s+(\S+)/) {
+ if ($1 eq 'NAME') {
+ $state = "name";
+ } elsif ($1 eq 'PREREQUISITES') {
+ $state = "prereq";
}
- } split /\s*,\s*/, $prereq);
+ } elsif ($state =~ m{^(name|prereq)$}) {
+ if (/^=/) {
+ $state = "poddir";
+ } elsif (/^\s*$/) {
+ # nop
+ } elsif ($state eq "name") {
+ if ($name eq "") {
+ ($name) = /^(\S+)/;
+ $state = "poddir";
+ }
+ } elsif ($state eq "prereq") {
+ $prereq .= $_;
+ }
+ } elsif (/^=cut\b/) {
+ last;
+ }
+ }
+ $fh->close;
+
+ for ($name) {
+ s{.*<}{}; # strip X<...>
+ s{>.*}{};
+ }
+ chomp $prereq;
+ $prereq = join " ", split /\s+/, $prereq;
+ my($PREREQ_PM) = join("\n", map {
+ s{.*<}{}; # strip X<...>
+ s{>.*}{};
+ if (/[\s\'\"]/) { # prose?
+ } else {
+ s/[^\w:]$//; # period?
+ " "x28 . "'$_' => 0,";
+ }
+ } split /\s*,\s*/, $prereq);
- $script = "
+ $script = "
EXE_FILES => ['$name'],
PREREQ_PM => {
$PREREQ_PM
},
";
+ if ($name) {
+ my $to_file = File::Spec->catfile($packagedir, $name);
+ rename $script_file, $to_file
+ or die "Can't rename $script_file to $to_file: $!";
+ }
+ }
- my $to_file = File::Spec->catfile($packagedir, $name);
- rename $script_file, $to_file
- or die "Can't rename $script_file to $to_file: $!";
- }
-
- my $fh = FileHandle->new;
- $fh->open(">$mpl")
- or Carp::croak("Could not open >$mpl: $!");
- $fh->print(
-qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
+ my $fh = FileHandle->new;
+ $fh->open(">$mpl")
+ or Carp::croak("Could not open >$mpl: $!");
+ $fh->print(
+ qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
# because there was no Makefile.PL supplied.
# Autogenerated on: }.scalar localtime().qq{
NAME => q[$cf],$script
);
});
- $fh->close;
- }
+ $fh->close;
}
+}
- return $self;
+#-> CPAN::Distribution::_signature_business
+sub _signature_business {
+ my($self) = @_;
+ if ($CPAN::Config->{check_sigs}) {
+ if ($CPAN::META->has_inst("Module::Signature")) {
+ if (-f "SIGNATURE") {
+ $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
+ my $rv = Module::Signature::verify();
+ if ($rv != Module::Signature::SIGNATURE_OK() and
+ $rv != Module::Signature::SIGNATURE_MISSING()) {
+ $CPAN::Frontend->myprint(
+ qq{\nSignature invalid for }.
+ qq{distribution file. }.
+ qq{Please investigate.\n\n}.
+ $self->as_string,
+ $CPAN::META->instance(
+ 'CPAN::Author',
+ $self->cpan_userid,
+ )->as_string
+ );
+
+ my $wrap =
+ 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
+},
+ $self->{localfile},
+ $self->pretty_id,
+ );
+ $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");
+ $self->debug("Module::Signature has verified") if $CPAN::DEBUG;
+ }
+ } else {
+ $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n});
+ }
+ } else {
+ $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
+ }
+ }
}
-# CPAN::Distribution::untar_me ;
+#-> CPAN::Distribution::untar_me ;
sub untar_me {
my($self,$ct) = @_;
$self->{archived} = "tar";
if ($ct->untar()) {
- $self->{unwrapped} = "YES";
+ $self->{unwrapped} = CPAN::Distrostatus->new("YES");
} else {
- $self->{unwrapped} = "NO";
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- untar failed");
}
}
my($self,$ct) = @_;
$self->{archived} = "zip";
if ($ct->unzip()) {
- $self->{unwrapped} = "YES";
+ $self->{unwrapped} = CPAN::Distrostatus->new("YES");
} else {
- $self->{unwrapped} = "NO";
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- unzip failed");
}
return;
}
my $to = File::Basename::basename($local_file);
if ($to =~ s/\.(gz|Z)(?!\n)\Z//) {
if (CPAN::Tarzip->new($local_file)->gunzip($to)) {
- $self->{unwrapped} = "YES";
+ $self->{unwrapped} = CPAN::Distrostatus->new("YES");
} else {
- $self->{unwrapped} = "NO";
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- uncompressing failed");
}
} else {
File::Copy::cp($local_file,".");
- $self->{unwrapped} = "YES";
+ $self->{unwrapped} = CPAN::Distrostatus->new("NO -- copying failed");
}
return $to;
}
$sloppy ||= 0;
$self->debug("chk_file[$chk_file]sloppy[$sloppy]") if $CPAN::DEBUG;
if ($CPAN::Config->{check_sigs}) {
- if ($CPAN::META->has_inst("Module::Signature") and Module::Signature->VERSION >= 0.26) {
+ if ($CPAN::META->has_inst("Module::Signature")) {
$self->debug("Module::Signature is installed, verifying");
$self->SIG_check_file($chk_file);
} else {
sub force {
my($self, $method) = @_;
for my $att (qw(
- CHECKSUM_STATUS archived build_dir localfile make install unwrapped
- writemakefile modulebuild make_test signature_verify
+ CHECKSUM_STATUS
+ archived
+ build_dir
+ install
+ localfile
+ make
+ make_test
+ modulebuild
+ prefs
+ prefs_file
+ prereq_pm
+ prereq_pm_detected
+ reqtype
+ signature_verify
+ unwrapped
+ writemakefile
+ yaml_content
)) {
delete $self->{$att};
+ CPAN->debug(sprintf "att[%s]", $att) if $CPAN::DEBUG;
}
if ($method && $method =~ /make|test|install/) {
$self->{"force_update"}++; # name should probably have been force_install
}
$CPAN::Frontend->myprint(sprintf "Running %s for %s\n", $make, $self->id);
$self->get;
+ local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+ ? $ENV{PERL5LIB}
+ : ($ENV{PERLLIB} || "");
+
+ $CPAN::META->set_perl5lib;
+ local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
if ($CPAN::Signal){
delete $self->{force_update};
return;
}
EXCUSE: {
my @e;
- !$self->{archived} || $self->{archived} eq "NO" and push @e,
- "Is neither a tar nor a zip archive.";
+ if (!$self->{archived} || $self->{archived} eq "NO") {
+ push @e, "Is neither a tar nor a zip archive.";
+ }
- !$self->{unwrapped} || $self->{unwrapped} eq "NO" and push @e,
- "Had problems unarchiving. Please build manually";
+ if (!$self->{unwrapped}
+ || (
+ $self->{unwrapped}->can("failed") ?
+ $self->{unwrapped}->failed :
+ $self->{unwrapped} =~ /^NO/
+ )) {
+ push @e, "Had problems unarchiving. Please build manually";
+ }
unless ($self->{force_update}) {
exists $self->{signature_verify} and (
# $switch = "-MExtUtils::MakeMaker ".
# "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
# if $] > 5.00310;
+ my $makepl_arg = $self->make_x_arg("pl");
$system = sprintf("%s%s Makefile.PL%s",
$perl,
$switch ? " $switch" : "",
- $CPAN::Config->{makepl_arg} ? " $CPAN::Config->{makepl_arg}" : "",
+ $makepl_arg ? " $makepl_arg" : "",
);
}
- unless (exists $self->{writemakefile}) {
+ my %env;
+ while (my($k,$v) = each %ENV) {
+ next unless defined $v;
+ $env{$k} = $v;
+ }
+ local %ENV = %env;
+ if (my $env = $self->prefs->{pl}{env}) {
+ for my $e (keys %$env) {
+ $ENV{$e} = $env->{$e};
+ }
+ }
+ if (exists $self->{writemakefile}) {
+ } else {
local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
my($ret,$pid);
$@ = "";
return;
}
} else {
- $ret = system($system);
- if ($ret != 0) {
- $self->{writemakefile} = CPAN::Distrostatus
- ->new("NO '$system' returned status $ret");
- $CPAN::Frontend->mywarn("Warning: No success on command[$system]\n");
- return;
- }
+ if (my $expect = $self->prefs->{pl}{expect}) {
+ $ret = $self->_run_via_expect($system,$expect);
+ } else {
+ $ret = system($system);
+ }
+ if ($ret != 0) {
+ $self->{writemakefile} = CPAN::Distrostatus
+ ->new("NO '$system' returned status $ret");
+ $CPAN::Frontend->mywarn("Warning: No success on command[$system]\n");
+ return;
+ }
}
if (-f "Makefile" || -f "Build") {
$self->{writemakefile} = CPAN::Distrostatus->new("YES");
return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
}
}
+ if ($CPAN::Signal){
+ delete $self->{force_update};
+ return;
+ }
if ($self->{modulebuild}) {
unless (-f "Build") {
my $cwd = Cwd::cwd;
} else {
$system = join " ", $self->_make_command(), $CPAN::Config->{make_arg};
}
+ my $make_arg = $self->make_x_arg("make");
+ $system = sprintf("%s%s",
+ $system,
+ $make_arg ? " $make_arg" : "",
+ );
+ if (my $env = $self->prefs->{make}{env}) { # overriding the local
+ # ENV of PL, not the
+ # outer ENV, but
+ # unlikely to be a risk
+ for my $e (keys %$env) {
+ $ENV{$e} = $env->{$e};
+ }
+ }
if (system($system) == 0) {
$CPAN::Frontend->myprint(" $system -- OK\n");
$self->{make} = CPAN::Distrostatus->new("YES");
}
}
+# CPAN::Distribution::_run_via_expect
+sub _run_via_expect {
+ my($self,$system,$expect) = @_;
+ CPAN->debug("system[$system]expect[$expect]") if $CPAN::DEBUG;
+ if ($CPAN::META->has_inst("Expect")) {
+ my $expo = Expect->new;
+ $expo->spawn($system);
+ EXPECT: for (my $i = 0; $i < $#$expect; $i+=2) {
+ my $next = $expect->[$i];
+ my($timeout,$re);
+ if (ref $next) {
+ $timeout = $next->{timeout};
+ $re = $next->{expect};
+ } else {
+ $timeout = 15;
+ $re = $next;
+ }
+ my $regex = eval "qr{$re}";
+ my $send = $expect->[$i+1];
+ $expo->expect($timeout,
+ [ eof => sub {
+ my $but = $expo->clear_accum;
+ $CPAN::Frontend->mywarn("EOF (maybe harmless) system[$system]
+expected[$regex]\nbut[$but]\n\n");
+ last EXPECT;
+ } ],
+ [ timeout => sub {
+ my $but = $expo->clear_accum;
+ $CPAN::Frontend->mydie("TIMEOUT system[$system]
+expected[$regex]\nbut[$but]\n\n");
+ } ],
+ -re => $regex);
+ $expo->send($send);
+ }
+ $expo->soft_close;
+ return $expo->exitstatus();
+ } else {
+ $CPAN::Frontend->mywarn("Expect not installed, falling back to system()\n");
+ return system($system);
+ }
+}
+
+# CPAN::Distribution::_find_prefs
+sub _find_prefs {
+ my($self) = @_;
+ my $distroid = $self->pretty_id;
+ CPAN->debug("distroid[$distroid]") if $CPAN::DEBUG;
+ my $prefs_dir = $CPAN::Config->{prefs_dir};
+ eval { File::Path::mkpath($prefs_dir); };
+ if ($@) {
+ $CPAN::Frontend->mydie("Cannot create directory $prefs_dir");
+ }
+ my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
+ if ($CPAN::META->has_inst($yaml_module)) {
+ my $dh = DirHandle->new($prefs_dir)
+ or die Carp::croak("Couldn't open '$prefs_dir': $!");
+ DIRENT: for (sort $dh->read) {
+ next if $_ eq "." || $_ eq "..";
+ next unless /\.yml$/;
+ my $abs = File::Spec->catfile($prefs_dir, $_);
+ if (-f $abs) {
+ CPAN->debug(sprintf "abs[%s]", $abs) if $CPAN::DEBUG;
+ my @yaml = @{CPAN->_yaml_loadfile($abs)};
+ # $DB::single=1;
+ ELEMENT: for my $y (0..$#yaml) {
+ my $yaml = $yaml[$y];
+ my $match = $yaml->{match};
+ unless ($match) {
+ CPAN->debug("no 'match' in abs[$abs], skipping");
+ next ELEMENT;
+ }
+ my $ok = 1;
+ for my $sub_attribute (keys %$match) {
+ my $qr = eval "qr{$yaml->{match}{$sub_attribute}}";
+ if ($sub_attribute eq "module") {
+ my $okm = 0;
+ CPAN->debug(sprintf "abs[%s]yaml[%d]", $abs, scalar @yaml) if $CPAN::DEBUG;
+ my @modules = $self->containsmods;
+ CPAN->debug(sprintf "abs[%s]yaml[%d]modules[%s]", $abs, scalar @yaml, join(",",@modules)) if $CPAN::DEBUG;
+ MODULE: for my $module (@modules) {
+ $okm ||= $module =~ /$qr/;
+ last MODULE if $okm;
+ }
+ $ok &&= $okm;
+ } elsif ($sub_attribute eq "distribution") {
+ my $okd = $distroid =~ /$qr/;
+ $ok &&= $okd;
+ } elsif ($sub_attribute eq "perl") {
+ my $okp = $^X =~ /$qr/;
+ $ok &&= $okp;
+ } else {
+ $CPAN::Frontend->mydie("Nonconforming YAML file '$abs': ".
+ "unknown sub_attribut '$sub_attribute'. ".
+ "Please ".
+ "remove, cannot continue.");
+ }
+ }
+ CPAN->debug(sprintf "abs[%s]yaml[%d]ok[%d]", $abs, scalar @yaml, $ok) if $CPAN::DEBUG;
+ if ($ok) {
+ return {
+ prefs => $yaml,
+ prefs_file => $abs,
+ prefs_file_section => $y,
+ };
+ }
+
+ }
+ }
+ }
+ } else {
+ unless ($self->{have_complained_about_missing_yaml}++) {
+ $CPAN::Frontend->mywarn("'$yaml_module' not installed, cannot read prefs '$prefs_dir'\n");
+ }
+ }
+ return;
+}
+
+# CPAN::Distribution::prefs
+sub prefs {
+ my($self) = @_;
+ if (exists $self->{prefs}) {
+ return $self->{prefs}; # XXX comment out during debugging
+ }
+ if ($CPAN::Config->{prefs_dir}) {
+ CPAN->debug("prefs_dir[$CPAN::Config->{prefs_dir}]") if $CPAN::DEBUG;
+ my $prefs = $self->_find_prefs();
+ if ($prefs) {
+ for my $x (qw(prefs prefs_file prefs_file_section)) {
+ $self->{$x} = $prefs->{$x};
+ }
+ my $bs = sprintf(
+ "%s[%s]",
+ File::Basename::basename($self->{prefs_file}),
+ $self->{prefs_file_section},
+ );
+ my $filler1 = "_" x 22;
+ my $filler2 = int(66 - length($bs))/2;
+ $filler2 = 0 if $filler2 < 0;
+ $filler2 = " " x $filler2;
+ $CPAN::Frontend->myprint("
+$filler1 D i s t r o P r e f s $filler1
+$filler2 $bs $filler2
+");
+ $CPAN::Frontend->mysleep(1);
+ return $self->{prefs};
+ }
+ }
+ return +{};
+}
+
+# CPAN::Distribution::make_x_arg
+sub make_x_arg {
+ my($self, $whixh) = @_;
+ my $make_x_arg;
+ my $prefs = $self->prefs;
+ if (
+ $prefs
+ && exists $prefs->{$whixh}
+ && exists $prefs->{$whixh}{args}
+ && $prefs->{$whixh}{args}
+ ) {
+ $make_x_arg = join(" ",
+ map {CPAN::HandleConfig
+ ->safe_quote($_)} @{$prefs->{$whixh}{args}},
+ );
+ }
+ my $what = sprintf "make%s_arg", $whixh eq "make" ? "" : $whixh;
+ $make_x_arg ||= $CPAN::Config->{$what};
+ return $make_x_arg;
+}
+
+# CPAN::Distribution::_make_command
sub _make_command {
my ($self) = @_;
if ($self) {
return
- CPAN::HandleConfig
+ CPAN::HandleConfig
->safe_quote(
- $CPAN::Config->{make} || $Config::Config{make} || 'make'
+ CPAN::HandleConfig->prefs_lookup($self,
+ q{make})
+ || $Config::Config{make}
+ || 'make'
);
} else {
# Old style call, without object. Deprecated
Carp::confess("CPAN::_make_command() used as function. Don't Do That.");
return
- safe_quote(undef, $CPAN::Config->{make} || $Config::Config{make} || 'make');
+ safe_quote(undef,
+ CPAN::HandleConfig->prefs_lookup($self,q{make})
+ || $CPAN::Config->{make}
+ || $Config::Config{make}
+ || 'make');
}
}
my(@prereq_tuples) = grep {$_->[0] ne "perl"} @_;
return unless @prereq_tuples;
my @prereq = map { $_->[0] } @prereq_tuples;
- my $id = $self->id;
+ my $pretty_id = $self->pretty_id;
my %map = (
b => "build_requires",
r => "requires",
c => "commandline",
);
+ my($filler1,$filler2,$filler3,$filler4);
+ my $unsat = "Unsatisfied dependencies detected during";
+ my $w = length($unsat) > length($pretty_id) ? length($unsat) : length($pretty_id);
+ {
+ my $r = int(($w - length($unsat))/2);
+ my $l = $w - length($unsat) - $r;
+ $filler1 = "-"x4 . " "x$l;
+ $filler2 = " "x$r . "-"x4 . "\n";
+ }
+ {
+ my $r = int(($w - length($pretty_id))/2);
+ my $l = $w - length($pretty_id) - $r;
+ $filler3 = "-"x4 . " "x$l;
+ $filler4 = " "x$r . "-"x4 . "\n";
+ }
$CPAN::Frontend->
- myprint("---- Unsatisfied dependencies detected during\n".
- "---- $id\n".
+ myprint("$filler1 $unsat $filler2".
+ "$filler3 $pretty_id $filler4".
join("", map {" $_->[0] \[$map{$_->[1]}]\n"} @prereq_tuples),
);
my $follow = 0;
myprint(" Ignoring dependencies on modules @prereq\n");
}
if ($follow) {
+ my $id = $self->id;
# color them as dirty
for my $p (@prereq) {
# warn "calling color_cmd_tmps(0,1)";
my $yaml = File::Spec->catfile($build_dir,"META.yml");
$self->debug("yaml[$yaml]") if $CPAN::DEBUG;
return unless -f $yaml;
- if ($CPAN::META->has_inst("YAML")) {
- eval { $self->{yaml_content} = YAML::LoadFile($yaml); };
- if ($@) {
- $CPAN::Frontend->mywarn("Error while parsing META.yml: $@");
- return;
- }
- if (not exists $self->{yaml_content}{dynamic_config}
- or $self->{yaml_content}{dynamic_config}
- ) {
- $self->{yaml_content} = undef;
- }
+ eval { $self->{yaml_content} = CPAN->_yaml_loadfile($yaml)->[0]; };
+ if ($@) {
+ return; # if we die, then we cannot read YAML's own META.yml
+ }
+ if (not exists $self->{yaml_content}{dynamic_config}
+ or $self->{yaml_content}{dynamic_config}
+ ) {
+ $self->{yaml_content} = undef;
}
$self->debug(sprintf "yaml_content[%s]", $self->{yaml_content} || "UNDEF")
if $CPAN::DEBUG;
$req = Module::Build->current->requires();
$breq = Module::Build->current->build_requires();
};
+ # this failed for example for HTML::Mason and for
+ # Error.pm because they are subclassing Module::Build
+ # in their Build.PL in such a way that Module::Build
+ # cannot read the _build directory. We DO need a dump
+ # command for that.
if ($@) {
- # HTML::Mason prompted for this with bleadperl@28900 or so
$CPAN::Frontend
->mywarn(
sprintf("Warning: while trying to determine ".
"prerequisites for %s with the help of ".
"Module::Build the following error ".
- "occurred: '%s'\n\nCannot care for prerequisites\n",
+ "occurred: '%s'\n\nFalling back to META.yml ".
+ "for prerequisites\n",
$self->id,
$@
));
- $self->{prereq_pm_detected}++;
- return $self->{prereq_pm} = {requires=>{},build_requires=>{}};
+ my $build_dir = $self->{build_dir};
+ my $yaml = File::Spec->catfile($build_dir,"META.yml");
+ if ($yaml = CPAN->_yaml_loadfile($yaml)->[0]) {
+ $req = $yaml->{requires} || {};
+ $breq = $yaml->{build_requires} || {};
+ }
}
}
}
}
my $make = $self->{modulebuild} ? "Build" : "make";
+
+ local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
+ ? $ENV{PERL5LIB}
+ : ($ENV{PERLLIB} || "");
+
+ $CPAN::META->set_perl5lib;
+ local $ENV{MAKEFLAGS}; # protect us from outer make calls
+
$CPAN::Frontend->myprint("Running $make test\n");
if (my @prereq = $self->unsat_prereq){
unless ($prereq[0][0] eq "perl") {
} else {
$system = join " ", $self->_make_command(), "test";
}
- my $tests_ok;
- if ( $CPAN::Config->{test_report} &&
- $CPAN::META->has_inst("CPAN::Reporter") ) {
+ my($tests_ok);
+ my %env;
+ while (my($k,$v) = each %ENV) {
+ next unless defined $v;
+ $env{$k} = $v;
+ }
+ local %ENV = %env;
+ if (my $env = $self->prefs->{test}{env}) {
+ for my $e (keys %$env) {
+ $ENV{$e} = $env->{$e};
+ }
+ }
+ my $expect = $self->prefs->{test}{expect};
+ my $can_expect = $CPAN::META->has_inst("Expect");
+ my $want_expect = 0;
+ if ( $expect && @$expect ) {
+ if ($can_expect) {
+ $want_expect = 1;
+ } else {
+ $CPAN::Frontend->mywarn("Expect not installed, falling back to ".
+ "testing without\n");
+ }
+ }
+ my $test_report = CPAN::HandleConfig->prefs_lookup($self,
+ q{test_report});
+ my $can_report = $CPAN::META->has_inst("CPAN::Reporter");
+ my $want_report = $test_report && $can_report;
+ my $ready_to_report = $want_report;
+ if ($ready_to_report
+ && (
+ substr($self->id,-1,1) eq "."
+ ||
+ $self->author->id eq "LOCAL"
+ )
+ ) {
+ $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
+ "for for local directories\n");
+ $ready_to_report = 0;
+ }
+ if ($ready_to_report
+ &&
+ $self->prefs->{patches}
+ &&
+ @{$self->prefs->{patches}}
+ &&
+ $self->{patched}
+ ) {
+ $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
+ "when the source has been patched\n");
+ $ready_to_report = 0;
+ }
+ if ($want_expect) {
+ if ($ready_to_report) {
+ $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is currently ".
+ "not supported when distroprefs specify ".
+ "an interactive test\n");
+ }
+ $tests_ok = $self->_run_via_expect($system,$expect) == 0;
+ } elsif ( $ready_to_report ) {
$tests_ok = CPAN::Reporter::test($self, $system);
} else {
$tests_ok = system($system) == 0;
my @prereq;
for my $m (keys %{$self->{sponsored_mods}}) {
my $m_obj = CPAN::Shell->expand("Module",$m);
- if (!$m_obj->distribution->{make_test}
- ||
- $m_obj->distribution->{make_test}->failed){
- #$m_obj->dump;
- push @prereq, $m;
+ my $d_obj = $m_obj->distribution;
+ if ($d_obj) {
+ if (!$d_obj->{make_test}
+ ||
+ $d_obj->{make_test}->failed){
+ #$m_obj->dump;
+ push @prereq, $m;
+ }
}
}
if (@prereq){
my $verb = $cnt == 1 ? "one dependency not OK ($which)" :
"$cnt dependencies missing ($which)";
$CPAN::Frontend->mywarn("Tests succeeded but $verb\n");
- $self->{make_test} = CPAN::Distrostatus->new("NO -- $verb");
+ $self->{make_test} = CPAN::Distrostatus->new("NO $verb");
return;
}
}
$CPAN::Config->{mbuild_install_arg},
);
} else {
- my($make_install_make_command) = $CPAN::Config->{make_install_make_command} ||
- $self->_make_command();
+ my($make_install_make_command) =
+ CPAN::HandleConfig->prefs_lookup($self,
+ q{make_install_make_command})
+ || $self->_make_command();
$system = sprintf("%s install %s",
$make_install_make_command,
$CPAN::Config->{make_install_arg},
}
my($stderr) = $^O eq "MSWin32" ? "" : " 2>&1 ";
- $CPAN::Config->{build_requires_install_policy}||="ask/yes";
+ my $brip = CPAN::HandleConfig->prefs_lookup($self,
+ q{build_requires_install_policy});
+ $brip ||="ask/yes";
my $id = $self->id;
my $reqtype = $self->{reqtype} ||= "c"; # in doubt it was a command
my $want_install = "yes";
if ($reqtype eq "b") {
- if ($CPAN::Config->{build_requires_install_policy} eq "no") {
+ if ($brip eq "no") {
$want_install = "no";
- } elsif ($CPAN::Config->{build_requires_install_policy} =~ m|^ask/(.+)|) {
+ } elsif ($brip =~ m|^ask/(.+)|) {
my $default = $1;
$default = "yes" unless $default =~ /^(y|n)/i;
$want_install =
} else {
$self->{install} = CPAN::Distrostatus->new("NO");
$CPAN::Frontend->mywarn(" $system -- NOT OK\n");
+ my $mimc =
+ CPAN::HandleConfig->prefs_lookup($self,
+ q{make_install_make_command});
if (
$makeout =~ /permission/s
&& $> > 0
&& (
- ! $CPAN::Config->{make_install_make_command}
- || $CPAN::Config->{make_install_make_command} eq $CPAN::Config->{make}
+ ! $mimc
+ || $mimc eq (CPAN::HandleConfig->prefs_lookup($self,
+ q{make}))
)
) {
$CPAN::Frontend->myprint(
if ($type eq 'CPAN::Distribution') {
$CPAN::Frontend->mywarn(qq{
The Bundle }.$self->id.qq{ contains
-explicitly a file $s.
+explicitly a file '$s'.
+Going to $meth that.
});
- $CPAN::Frontend->mysleep(3);
+ $CPAN::Frontend->mysleep(5);
}
# possibly noisy action:
$self->debug("type[$type] s[$s]") if $CPAN::DEBUG;
# Note: also inherited by CPAN::Bundle
sub cpan_file {
my $self = shift;
- CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
+ # CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
unless ($self->ro) {
CPAN::Index->reload;
}
use CPAN;
- # modules:
+ # Modules:
+
+ cpan> install Acme::Meta # in the shell
+
+ CPAN::Shell->install("Acme::Meta"); # in perl
+
+ # Distributions:
+
+ cpan> install NWCLARK/Acme-Meta-0.02.tar.gz # in the shell
- $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
+ CPAN::Shell->
+ install("NWCLARK/Acme-Meta-0.02.tar.gz"); # in perl
- # distributions:
+ # module objects:
- $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("Distribution",$distro)->install; # same thing
+ $mo = CPAN::Shell->expandany($mod);
+ $mo = CPAN::Shell->expand("Module",$mod); # same thing
+
+ # distribution objects:
+
+ $do = CPAN::Shell->expand("Module",$mod)->distribution;
+ $do = CPAN::Shell->expandany($distro); # same thing
+ $do = CPAN::Shell->expand("Distribution",
+ $distro); # same thing
=head1 STATUS
is in turn depending on binary compatibility (so you cannot run CPAN
commands), then you should try the CPAN::Nox module for recovery.
+=head2 report Bundle|Distribution|Module
+
+The C<report> command temporarily turns on the C<test_report> config
+variable, then runs the C<force test> command with the given
+arguments. The C<force> pragma is used to re-run the tests and repeat
+every step that might have failed before.
+
=head2 upgrade [Module|/Regex/]...
The C<upgrade> command first runs an C<r> command with the given
to the most recent official release. Developers may mark their releases
as unstable development versions (by inserting an underbar into the
module version number which will also be reflected in the distribution
-name when you run 'make dist'), so the really hottest and newest
-distribution is not always the default. If a module Foo circulates
-on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
+name when you run 'make dist'), so the really hottest and newest
+distribution is not always the default. If a module Foo circulates
+on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
way to install version 1.23 by saying
install Foo
The first example will be driven by an object of the class
CPAN::Module, the second by an object of class CPAN::Distribution.
+=head2 Integrating local directories
+
+Distribution objects are normally distributions from the CPAN, but
+there is a slightly degenerate case for Distribution objects, too,
+normally only needed by developers. If a distribution object ends with
+a dot or is a dot by itself, then it represents a local directory and
+all actions such as C<make>, C<test>, and C<install> are applied
+directly to that directory. This gives the command C<cpan .> an
+interesting touch: while the normal mantra of installing a CPAN module
+without CPAN.pm is one of
+
+ perl Makefile.PL perl Build.PL
+ ( go and get prerequisites )
+ make ./Build
+ make test ./Build test
+ make install ./Build install
+
+the command C<cpan .> does all of this at once. It figures out which
+of the two mantras is appropriate, fetches and installs all
+prerequisites, cares for them recursively and finally finishes the
+installation of the module in the current directory, be it a CPAN
+module or not.
+
=head1 PROGRAMMER'S INTERFACE
If you do not enter the shell, the available shell commands are both
# install my favorite programs if necessary:
for $mod (qw(Net::FTP Digest::SHA Data::Dumper)){
- my $obj = CPAN::Shell->expand('Module',$mod);
- $obj->install;
+ CPAN::Shell->install($mod);
}
# list all modules on my disk that have no VERSION number
cancellation can be avoided by letting C<force> run the C<install> for
you.
+This install method has only the power to install the distribution if
+there are no dependencies in the way. To install an object and all of
+its dependencies, use CPAN::Shell->install.
+
Note that install() gives no meaningful return value. See uptodate().
=item CPAN::Distribution::isa_perl()
command html2text and runs it through the pager specified
in C<$CPAN::Config->{pager}>
+=item CPAN::Distribution::prefs()
+
+Returns the hash reference from the first matching YAML file that the
+user has deposited in the C<prefs_dir/> directory. The first
+succeeding match wins. The files in the C<prefs_dir/> are processed
+alphabetically and the canonical distroname (e.g.
+AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
+stored in the $root->{match}{distribution} attribute value.
+Additionally all module names contained in a distribution are matched
+agains the regular expressions in the $root->{match}{module} attribute
+value. The two match values are ANDed together. Each of the two
+attributes are optional.
+
=item CPAN::Distribution::prereq_pm()
Returns the hash reference that has been announced by a distribution
Returns the content of the META.yml of this distro as a hashref. Note:
works only after an attempt has been made to C<make> the distribution.
-Returns undef otherwise.
+Returns undef otherwise. Also returns undef if the content of META.yml
+is dynamic.
=item CPAN::Distribution::test()
no_proxy don't proxy to these hosts/domains (comma separated list)
pager location of external program more (or any pager)
password your password if you CPAN server wants one
+ patch path to external prg
prefer_installer legal values are MB and EUMM: if a module comes
with both a Makefile.PL and a Build.PL, use the
former (EUMM) or the latter (MB); if the module
prerequisites_policy
what to do if you are missing module prerequisites
('follow' automatically, 'ask' me, or 'ignore')
+ prefs_dir local directory to store per-distro build options
proxy_user username for accessing an authenticating proxy
proxy_pass password for accessing an authenticating proxy
scan_cache controls scanning of cache ('atstart' or 'never')
username your username if you CPAN server wants one
wait_list arrayref to a wait server to try (See CPAN::WAIT)
wget path to external prg
+ yaml_module which module to use to read/write YAML files
You can set and query each of these options interactively in the cpan
shell with the command set defined within the C<o conf> command:
a site for the next transfer, it must be explicitly removed from
urllist.
+=head2 prefs_dir for avoiding interactive questions (ALPHA)
+
+(B<Note:> This feature has been introduced in CPAN.pm 1.8854 and is
+still considered experimental and may still be changed)
+
+The files in the directory specified in C<prefs_dir> are YAML files
+that specify how CPAN.pm shall treat distributions that deviate from
+the normal non-interactive model of building and installing CPAN
+modules.
+
+Some modules try to get some data from the user interactively thus
+disturbing the installation of large bundles like Phalanx100 or
+modules like Plagger.
+
+CPAN.pm can use YAML files to either pass additional arguments to one
+of the four commands, set environment variables or instantiate an
+Expect object that reads from the console and enters answers on your
+behalf (latter option requires Expect.pm installed). A further option
+is to apply patches from the local disk or from CPAN.
+
+CPAN.pm comes with a couple of such YAML files. The structure is
+currently not documented because in flux. Please see the distroprefs
+directory of the CPAN distribution for examples and follow the README
+in there.
+
+Please note that setting the environment variable PERL_MM_USE_DEFAULT
+to a true value can also get you a long way if you want to always pick
+the default answers. But this only works if the author of a package
+used the prompt function provided by ExtUtils::MakeMaker and if the
+defaults are OK for you.
+
=head1 SECURITY
There's no strong security layer in CPAN.pm. CPAN.pm helps you to