},
'CPAN' => {
- 'DISTRIBUTION' => 'ANDK/CPAN-2.03-TRIAL.tar.gz',
+ 'DISTRIBUTION' => 'ANDK/CPAN-2.04-TRIAL.tar.gz',
'FILES' => q[cpan/CPAN],
'EXCLUDED' => [
qr{^distroprefs/},
use if $] < 5.008 => "IO::Scalar";
-$VERSION = '1.61';
+$VERSION = '1.62';
=head1 NAME
my $fh = $args->[0] || \*STDOUT;
+ local $Data::Dumper::Sortkeys = 1;
my $dd = Data::Dumper->new(
[$CPAN::Config],
['$CPAN::Config']
# vim: ts=4 sts=4 sw=4:
use strict;
package CPAN;
-$CPAN::VERSION = '2.03';
+$CPAN::VERSION = '2.04';
$CPAN::VERSION =~ s/_//;
# we need to run chdir all over and we would get at wrong libraries
CPAN::Reporter history)
unzip location of external program unzip
urllist arrayref to nearby CPAN sites (or equivalent locations)
+ use_prompt_default set PERL_MM_USE_DEFAULT for configure/make/test/install
use_sqlite use CPAN::SQLite for metadata storage (fast and lean)
username your username if you CPAN server wants one
version_timeout stops version parsing after this many seconds.
use vars qw(
$VERSION
);
-$VERSION = "5.5";
+$VERSION = "5.5001";
sub look {
my $self = shift;
my $obj = $CPAN::META->instance($type,$s);
$obj->{reqtype} = $self->{reqtype};
# $obj->$meth();
- CPAN::Queue->queue_item(qmod => $obj->id, reqtype => $self->{reqtype});
+ # XXX should optional be based on whether bundle was optional? -- xdg, 2012-04-01
+ # A: Sure, what could demand otherwise? --andk, 2013-11-25
+ CPAN::Queue->queue_item(qmod => $obj->id, reqtype => $self->{reqtype}, optional => !$self->{mandatory});
}
}
use strict;
@CPAN::Complete::ISA = qw(CPAN::Debug);
# Q: where is the "How do I add a new command" HOWTO?
-# A: svn diff -r 1048:1049 where andk added the report command
+# A: git log -p -1 355c44e9caaec857e4b12f51afb96498833c3e36 where andk added the report command
@CPAN::Complete::COMMANDS = sort qw(
? ! a b d h i m o q r u
autobundle
use vars qw(
$VERSION
);
-$VERSION = "5.5";
+$VERSION = "5.5001";
package CPAN::Complete;
use strict;
use strict;
use Cwd qw(chdir);
use CPAN::Distroprefs;
+use CPAN::Meta::Requirements 2;
use CPAN::InfoObj;
use File::Path ();
@CPAN::Distribution::ISA = qw(CPAN::InfoObj);
use vars qw($VERSION);
-$VERSION = "2.00";
+$VERSION = "2.01";
# Accessors
sub cpan_comment {
my $prereq_pm = $self->prereq_pm;
if (defined $prereq_pm) {
# XXX also optional_req & optional_breq? -- xdg, 2012-04-01
- PREREQ: for my $pre (keys %{$prereq_pm->{requires}||{}},
- keys %{$prereq_pm->{build_requires}||{}}) {
+ PREREQ: for my $pre (
+ keys %{$prereq_pm->{requires}||{}},
+ keys %{$prereq_pm->{build_requires}||{}},
+ keys %{$prereq_pm->{opt_requires}||{}},
+ keys %{$prereq_pm->{opt_build_requires}||{}}
+ ) {
next PREREQ if $pre eq "perl";
my $premo;
unless ($premo = CPAN::Shell->expand("Module",$pre)) {
}
local $ENV{PERL} = $ENV{PERL};
local $ENV{PERL5_CPAN_IS_EXECUTING} = $ENV{PERL5_CPAN_IS_EXECUTING};
+ local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
+ local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
if ($pl_commandline) {
$system = $pl_commandline;
$ENV{PERL} = $^X;
$make_commandline = $self->prefs->{make}{commandline};
}
local $ENV{PERL} = $ENV{PERL};
+ local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
+ local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
if ($make_commandline) {
$system = $make_commandline;
$ENV{PERL} = CPAN::find_perl();
return $mimc;
}
+#-> sub CPAN::Distribution::is_locally_optional
+sub is_locally_optional {
+ my($self, $prereq_pm, $prereq) = @_;
+ $prereq_pm ||= $self->{prereq_pm};
+ exists $prereq_pm->{opt_requires}{$prereq}
+ ||
+ exists $prereq_pm->{opt_build_requires}{$prereq};
+}
+
#-> sub CPAN::Distribution::follow_prereqs ;
sub follow_prereqs {
my($self) = shift;
return unless @prereq_tuples;
my(@good_prereq_tuples);
for my $p (@prereq_tuples) {
+ # e.g. $p = ['Devel::PartialDump', 'r', 1]
# promote if possible
if ($p->[1] =~ /^(r|c)$/) {
push @good_prereq_tuples, $p;
} elsif ($p->[1] =~ /^(b)$/) {
my $reqtype = CPAN::Queue->reqtype_of($p->[0]);
if ($reqtype =~ /^(r|c)$/) {
- push @good_prereq_tuples, [$p->[0], $reqtype];
+ push @good_prereq_tuples, [$p->[0], $reqtype, $p->[2]];
} else {
push @good_prereq_tuples, $p;
}
$CPAN::Frontend->
myprint("$filler1 $unsat $filler2".
"$filler3 $pretty_id $filler4".
- join("", map {" $_->[0] \[$map{$_->[1]}]\n"} @good_prereq_tuples),
+ join("", map {sprintf " %s \[%s%s]\n", $_->[0], $map{$_->[1]}, $self->is_locally_optional(undef,$_->[0]) ? ",optional" : ""} @good_prereq_tuples),
);
my $follow = 0;
if ($CPAN::Config->{prerequisites_policy} eq "follow") {
}
if ($follow) {
my $id = $self->id;
- # color them as dirty
+ my(@to_queue_mand,@to_queue_opt);
for my $gp (@good_prereq_tuples) {
- # warn "calling color_cmd_tmps(0,1)";
- my $p = $gp->[0];
- my $any = CPAN::Shell->expandany($p);
- $self->{$slot . "_for"}{$any->id}++;
- if ($any) {
- $any->color_cmd_tmps(0,2);
+ my($prereq,$reqtype,$optional) = @$gp;
+ my $qthing = +{qmod=>$prereq,reqtype=>$reqtype,optional=>$optional};
+ if ($optional &&
+ $self->is_locally_optional(undef,$prereq)
+ ){
+ # Since we do not depend on this one, we do not need
+ # this in a mandatory arrangement:
+ push @to_queue_opt, $qthing;
} else {
- $CPAN::Frontend->mywarn("Warning (maybe a bug): Cannot expand prereq '$p'\n");
- $CPAN::Frontend->mysleep(2);
+ my $any = CPAN::Shell->expandany($prereq);
+ $self->{$slot . "_for"}{$any->id}++;
+ if ($any) {
+ unless ($optional) {
+ # No recursion check in an optional area of the tree
+ $any->color_cmd_tmps(0,2);
+ }
+ } else {
+ $CPAN::Frontend->mywarn("Warning (maybe a bug): Cannot expand prereq '$prereq'\n");
+ $CPAN::Frontend->mysleep(2);
+ }
+ # order everything that is not locally_optional just
+ # like mandatory items: this keeps leaves before
+ # branches
+ unshift @to_queue_mand, $qthing;
}
}
- # queue them and re-queue yourself
- CPAN::Queue->jumpqueue({qmod => $id, reqtype => $self->{reqtype}},
- map {+{qmod=>$_->[0],reqtype=>$_->[1]}} reverse @good_prereq_tuples);
- $self->{$slot} = "Delayed until after prerequisites";
- return 1; # signal we need dependencies
+ if (@to_queue_mand) {
+ unshift @to_queue_mand, {qmod => $id, reqtype => $self->{reqtype}, optional=> !$self->{mandatory}};
+ CPAN::Queue->jumpqueue(@to_queue_opt,@to_queue_mand);
+ $self->{$slot} = "Delayed until after prerequisites";
+ return 1; # signal we need dependencies
+ } elsif (@to_queue_opt) {
+ CPAN::Queue->jumpqueue(@to_queue_opt);
+ }
}
return;
}
sub prereqs_for_slot {
my($self,$slot) = @_;
- my(%merged,$prereq_pm);
+ my($prereq_pm);
+ my $merged = CPAN::Meta::Requirements->new;
my $prefs_depends = $self->prefs->{depends}||{};
my $feature_depends = $self->_feature_depends();
if ($slot eq "configure_requires_later") {
- my $meta_configure_requires = $self->configure_requires();
- %merged = (
- %{$meta_configure_requires||{}},
- %{$prefs_depends->{configure_requires}||{}},
- %{$feature_depends->{configure_requires}||{}},
- );
- if (-f File::Spec->catfile($self->{build_dir},"Build.PL")
+ for my $hash ( $self->configure_requires,
+ $prefs_depends->{configure_requires},
+ $feature_depends->{configure_requires},
+ ) {
+ $merged->add_requirements(
+ CPAN::Meta::Requirements->from_string_hash($hash)
+ );
+ }
+ if (-f "Build.PL"
&& ! -f File::Spec->catfile($self->{build_dir},"Makefile.PL")
- && ! exists $merged{"Module::Build"}
+ && ! $merged->requirements_for_module("Module::Build")
&& ! $CPAN::META->has_inst("Module::Build")
) {
$CPAN::Frontend->mywarn(
" Adding it now as such.\n"
);
$CPAN::Frontend->mysleep(5);
- $merged{"Module::Build"} = 0;
+ $merged->add_minimum( "Module::Build" => 0 );
delete $self->{writemakefile};
}
$prereq_pm = {}; # configure_requires defined as "b"
} elsif ($slot eq "later") {
my $prereq_pm_0 = $self->prereq_pm || {};
- for my $reqtype (qw(requires build_requires)) {
+ for my $reqtype (qw(requires build_requires opt_requires opt_build_requires)) {
$prereq_pm->{$reqtype} = {%{$prereq_pm_0->{$reqtype}||{}}}; # copy to not pollute it
for my $dep ($prefs_depends,$feature_depends) {
for my $k (keys %{$dep->{$reqtype}||{}}) {
}
}
}
- %merged = (%{$prereq_pm->{requires}||{}},%{$prereq_pm->{build_requires}||{}});
# XXX what about optional_req|breq? -- xdg, 2012-04-01
+ for my $hash (
+ $prereq_pm->{requires},
+ $prereq_pm->{build_requires},
+ $prereq_pm->{opt_requires},
+ $prereq_pm->{opt_build_requires},
+
+ ) {
+ $merged->add_requirements(
+ CPAN::Meta::Requirements->from_string_hash($hash)
+ );
+ }
} else {
die "Panic: illegal slot '$slot'";
}
- return (\%merged, $prereq_pm);
+ return ($merged->as_string_hash, $prereq_pm);
}
#-> sub CPAN::Distribution::unsat_prereq ;
# (sorry for the inconsistency, it was an accident)
sub unsat_prereq {
my($self,$slot) = @_;
- my($merged,$prereq_pm) = $self->prereqs_for_slot($slot);
+ my($merged_hash,$prereq_pm) = $self->prereqs_for_slot($slot);
my(@need);
- my @merged = my %merged = %$merged;
+ my $merged = CPAN::Meta::Requirements->from_string_hash($merged_hash);
+ my @merged = $merged->required_modules;
CPAN->debug("all merged_prereqs[@merged]") if $CPAN::DEBUG;
- NEED: while (my($need_module, $need_version) = each %merged) {
+ NEED: for my $need_module ( @merged ) {
+ my $need_version = $merged->requirements_for_module($need_module);
my($available_version,$inst_file,$available_file,$nmo);
if ($need_module eq "perl") {
$available_version = $];
$available_version,
$need_version,
);
- if (0) {
- } elsif ( $inst_file
+ if ( $inst_file
&& $available_file eq $inst_file
&& $nmo->inst_deprecated
) {
# loop CPANPLUS => CPANPLUS::Dist::Build RT#83042)
next NEED;
}
- } elsif ($self->{reqtype} =~ /^(r|c)$/ && exists $prereq_pm->{requires}{$need_module} && $nmo && !$inst_file) {
+ } elsif (
+ $self->{reqtype} =~ /^(r|c)$/
+ && (exists $prereq_pm->{requires}{$need_module} || exists $prereq_pm->{opt_requires} )
+ && $nmo
+ && !$inst_file
+ ) {
# continue installing as a prereq; this may be a
# distro we already used when it was a build_requires
# so we did not install it. But suddenly somebody
);
next NEED;
}
- ### XXX here do next NEED if needed module is recommends/suggests
- ### so we don't complain about missing optional deps -- xdg, 2012-04-01
NOSAYER: for my $nosayer (
"unwrapped",
"writemakefile",
) {
next NOSAYER;
}
- $CPAN::Frontend->mywarn("Warning: Prerequisite ".
- "'$need_module => $need_version' ".
- "for '$selfid' failed when ".
- "processing '$did' with ".
- "'$nosayer => $do->{$nosayer}'. Continuing, ".
- "but chances to succeed are limited.\n"
- );
- $CPAN::Frontend->mysleep($sponsoring/10);
+ ### XXX don't complain about missing optional deps -- xdg, 2012-04-01
+ if ($self->is_locally_optional($prereq_pm, $need_module)) {
+ # don't complain about failing optional prereqs
+ }
+ else {
+ $CPAN::Frontend->mywarn("Warning: Prerequisite ".
+ "'$need_module => $need_version' ".
+ "for '$selfid' failed when ".
+ "processing '$did' with ".
+ "'$nosayer => $do->{$nosayer}'. Continuing, ".
+ "but chances to succeed are limited.\n"
+ );
+ $CPAN::Frontend->mysleep($sponsoring/10);
+ }
next NEED;
} else { # the other guy succeeded
if ($nosayer =~ /^(install|make_test)$/) {
}
}
my $needed_as;
- # XXX here need to flag as optional somehow for recommends/suggests
- # -- xdg, 2012-04-01
if (0) {
- } elsif (exists $prereq_pm->{requires}{$need_module}) {
+ } elsif (exists $prereq_pm->{requires}{$need_module}
+ || exists $prereq_pm->{opt_requires}{$need_module}
+ ) {
$needed_as = "r";
} elsif ($slot eq "configure_requires_later") {
# in ae872487d5 we said: C< we have not yet run the
} else {
$needed_as = "b";
}
- push @need, [$need_module,$needed_as];
+ # here need to flag as optional for recommends/suggests
+ # -- xdg, 2012-04-01
+ my $optional = !$self->{mandatory}
+ || $self->is_locally_optional($prereq_pm, $need_module);
+ push @need, [$need_module,$needed_as,$optional];
}
my @unfolded = map { "[".join(",",@$_)."]" } @need;
CPAN->debug("returning from unsat_prereq[@unfolded]") if $CPAN::DEBUG;
$self->{writemakefile}||"",
$self->{modulebuild}||"",
) if $CPAN::DEBUG;
- my($req,$breq);
+ my($req,$breq, $opt_req, $opt_breq);
my $meta_obj = $self->read_meta;
# META/MYMETA is only authoritative if dynamic_config is false
if ($meta_obj && ! $meta_obj->dynamic_config) {
my $requires = $prereqs->requirements_for(qw/runtime requires/);
my $build_requires = $prereqs->requirements_for(qw/build requires/);
my $test_requires = $prereqs->requirements_for(qw/test requires/);
- # XXX assemble optional_req && optional_breq from recommends/suggests
- # depending on corresponding policies -- xdg, 2012-04-01
# XXX we don't yet distinguish build vs test, so merge them for now
$build_requires->add_requirements($test_requires);
$req = $requires->as_string_hash;
$breq = $build_requires->as_string_hash;
+
+ # XXX assemble optional_req && optional_breq from recommends/suggests
+ # depending on corresponding policies -- xdg, 2012-04-01
+ my $opt_runtime = CPAN::Meta::Requirements->new;
+ my $opt_build = CPAN::Meta::Requirements->new;
+ if ( $CPAN::Config->{recommends_policy} ) {
+ $opt_runtime->add_requirements( $prereqs->requirements_for(qw/runtime recommends/));
+ $opt_build->add_requirements( $prereqs->requirements_for(qw/build recommends/));
+ $opt_build->add_requirements( $prereqs->requirements_for(qw/test recommends/));
+
+ }
+ if ( $CPAN::Config->{suggests_policy} ) {
+ $opt_runtime->add_requirements( $prereqs->requirements_for(qw/runtime suggests/));
+ $opt_build->add_requirements( $prereqs->requirements_for(qw/build suggests/));
+ $opt_build->add_requirements( $prereqs->requirements_for(qw/test suggests/));
+ }
+ $opt_req = $opt_runtime->as_string_hash;
+ $opt_breq = $opt_build->as_string_hash;
}
elsif (my $yaml = $self->read_yaml) { # often dynamic_config prevents a result here
$req = $yaml->{requires} || {};
$breq = $yaml->{build_requires} || {};
+ if ( $CPAN::Config->{recommends_policy} ) {
+ $opt_req = $yaml->{recommends} || {};
+ }
undef $req unless ref $req eq "HASH" && %$req;
if ($req) {
if ($yaml->{generated_by} &&
}
}
}
- # XXX needs to be adapted for optional_req & optional_breq
- if ($req || $breq) {
- return $self->{prereq_pm} = { requires => $req, build_requires => $breq };
+ # XXX needs to be adapted for optional_req & optional_breq -- xdg, 2012-04-01
+ if ($req || $breq || $opt_req || $opt_breq ) {
+ return $self->{prereq_pm} = {
+ requires => $req,
+ build_requires => $breq,
+ opt_requires => $opt_req,
+ opt_build_requires => $opt_breq,
+ };
}
}
return undef; # no shortcut
}
+#-> sub CPAN::Distribution::_exe_files ;
+sub _exe_files {
+ my($self) = @_;
+ return unless $self->{writemakefile} # no need to have succeeded
+ # but we must have run it
+ || $self->{modulebuild};
+ unless ($self->{build_dir}) {
+ return;
+ }
+ CPAN->debug(sprintf "writemakefile[%s]modulebuild[%s]",
+ $self->{writemakefile}||"",
+ $self->{modulebuild}||"",
+ ) if $CPAN::DEBUG;
+ my $build_dir;
+ unless ( $build_dir = $self->{build_dir} ) {
+ return;
+ }
+ my $makefile = File::Spec->catfile($build_dir,"Makefile");
+ my $fh;
+ my @exe_files;
+ if (-f $makefile
+ and
+ $fh = FileHandle->new("<$makefile\0")) {
+ CPAN->debug("Getting exefiles from Makefile") if $CPAN::DEBUG;
+ local($/) = "\n";
+ while (<$fh>) {
+ last if /MakeMaker post_initialize section/;
+ my($p) = m{^[\#]
+ \s+EXE_FILES\s+=>\s+\[(.+)\]
+ }x;
+ next unless $p;
+ # warn "Found exefiles expr[$p]";
+ my @p = split /,\s*/, $p;
+ for my $p2 (@p) {
+ if ($p2 =~ /^q\[(.+)\]/) {
+ push @exe_files, $1;
+ }
+ }
+ }
+ }
+ return \@exe_files if @exe_files;
+ my $buildparams = File::Spec->catfile($build_dir,"_build","build_params");
+ if (-f $buildparams) {
+ CPAN->debug("Found '$buildparams'") if $CPAN::DEBUG;
+ my $x = do $buildparams;
+ for my $sf (@{$x->[2]{script_files} || []}) {
+ push @exe_files, $sf;
+ }
+ }
+ return \@exe_files;
+}
+
#-> sub CPAN::Distribution::test ;
sub test {
my($self) = @_;
local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
$CPAN::META->set_perl5lib;
local $ENV{MAKEFLAGS}; # protect us from outer make calls
+ local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
+ local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
$CPAN::Frontend->myprint("Running $make test\n");
$but .= "; additionally test harness failed";
$CPAN::Frontend->mywarn("$but\n");
$self->{make_test} = CPAN::Distrostatus->new("NO $but");
+ } elsif ( $self->{force_update} ) {
+ $self->{make_test} = CPAN::Distrostatus->new(
+ "NO but failure ignored because 'force' in effect"
+ );
} else {
$self->{make_test} = CPAN::Distrostatus->new("NO");
}
$self->pretty_id));
}
$self->store_persistent_state;
- return !! $tests_ok;
+
+ return $self->{force_update} ? 1 : !! $tests_ok;
}
sub _make_test_illuminate_prereqs {
CPAN->debug("m[$m] have available_file[$available_file]")
if $CPAN::DEBUG;
} else {
- push @prereq, $m;
+ push @prereq, $m
+ if $m_obj->{mandatory};
}
}
my $but;
local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
$CPAN::META->set_perl5lib;
+ local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
+ local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
+
my($pipe) = FileHandle->new("$system $stderr |") || Carp::croak
("Can't execute $system: $!");
my($makeout) = "";
package CPAN::Distroprefs;
use vars qw($VERSION);
-$VERSION = '6';
+$VERSION = '6.0001';
package CPAN::Distroprefs::Result;
while (my $fn = readdir $dh) {
next if $fn eq '.' || $fn eq '..';
if (-d "$dir/$fn") {
- next if $fn eq '.svn' || $fn eq '.git' || $fn eq '.hg' || $fn eq '_darcs';
+ next if $fn =~ /^[._]/; # prune .svn, .git, .hg, _darcs and what the user wants to hide
push @list, _build_file_list("$dir/$fn", "$dir1$fn/", $ext_re);
} else {
if ($fn =~ $ext_re) {
while (my $result = $finder->next) { ... }
-Build an iterator which finds distroprefs files in the given directory.
+Build an iterator which finds distroprefs files in the tree below the
+given directory. Within the tree directories matching C<m/^[._]/> are
+pruned.
C<%ext_map> is a hashref whose keys are file extensions and whose values are
modules used to load matching files:
use File::Spec ();
use CPAN::Mirrors ();
use vars qw($VERSION $auto_config);
-$VERSION = "5.5304";
+$VERSION = "5.5305";
=head1 NAME
installed. Set your favorite colors after some experimenting with the
Term::ANSIColor module.
+Please note that on Windows platforms colorized output also requires
+the Win32::Console::ANSI module.
+
Do you want to turn on colored output?
=item colorize_print
Normally, CPAN.pm continues processing the full list of targets and
dependencies, even if one of them fails. However, you can specify
-that CPAN should halt after the first failure.
+that CPAN should halt after the first failure. (Note that optional
+recommended or suggested modules that fail will not cause a halt.)
Do you want to halt on failure (yes/no)?
Do you want to rely on the test report history (yes/no)?
+=item use_prompt_default
+
+When this is true, CPAN will set PERL_MM_USE_DEFAULT to a true
+value. This causes ExtUtils::MakeMaker (and compatible) prompts
+to use default values instead of stopping to prompt you to answer
+questions. It also sets NONINTERACTIVE_TESTING to a true value to
+signal more generally that distributions should not try to
+interact with you.
+
+Do you want to use prompt defaults (yes/no)?
+
=item use_sqlite
CPAN::SQLite is a layer between the index files that are downloaded
my_dflt_prompt(mbuild_install_arg => "", $matcher);
#
+ #== use_prompt_default
+ #
+ my_yn_prompt(use_prompt_default => 0, $matcher);
+
+ #
#= Alarm period
#
"trust_test_report_history",
"unzip",
"urllist",
+ "use_prompt_default",
"use_sqlite",
"username",
"version_timeout",
use strict;
use vars qw($AUTOLOAD $VERSION);
- $VERSION = "5.5001";
+ $VERSION = "5.5002";
# formerly CPAN::HandleConfig was known as CPAN::Config
sub AUTOLOAD { ## no critic
$self->{reqtype};
}
+sub optional {
+ my($self) = @_;
+ $self->{optional};
+}
+
package CPAN::Queue;
# One use of the queue is to determine if we should or shouldn't
# in CPAN::Distribution::rematein.
use vars qw{ @All $VERSION };
-$VERSION = "5.5001";
+$VERSION = "5.5002";
# CPAN::Queue::queue_item ;
sub queue_item {
my($class,$obj) = @_;
push @All, $obj;
CPAN->debug(sprintf("in new All[%s]",
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All),
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All),
)) if $CPAN::DEBUG;
}
}
CPAN->debug(sprintf("after delete_first mod[%s] All[%s]",
$what,
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All)
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
)) if $CPAN::DEBUG;
}
my $class = shift;
my @what = @_;
CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All),
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @what),
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All),
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @what),
)) if $CPAN::DEBUG;
unless (defined $what[0]{reqtype}) {
# apparently it was not the Shell that sent us this enquiry,
}
my $inherit_reqtype = $what[0]{reqtype} =~ /^(c|r)$/ ? "r" : "b";
WHAT: for my $what_tuple (@what) {
- my($qmod,$reqtype) = @$what_tuple{qw(qmod reqtype)};
+ my($qmod,$reqtype,$optional) = @$what_tuple{qw(qmod reqtype optional)};
if ($reqtype eq "r"
&&
$inherit_reqtype eq "b"
CPAN->debug("qmod[$qmod]jumped[$jumped]") if $CPAN::DEBUG;
my $obj = "$class\::Item"->new(
qmod => $qmod,
- reqtype => $reqtype
+ reqtype => $reqtype,
+ optional => !! $optional,
);
unshift @All, $obj;
}
CPAN->debug(sprintf("after jumpqueue All[%s]",
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All)
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
)) if $CPAN::DEBUG;
}
@All = grep { $_->{qmod} ne $mod } @All;
CPAN->debug(sprintf("after delete mod[%s] All[%s]",
$mod,
- join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All)
+ join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
)) if $CPAN::DEBUG;
}
"CPAN/Tarzip.pm",
"CPAN/Version.pm",
);
-$VERSION = "5.5002";
+$VERSION = "5.5003";
# record the initial timestamp for reload.
$reload = { map {$INC{$_} ? ($_,(stat $INC{$_})[9]) : ()} @relo };
@CPAN::Shell::ISA = qw(CPAN::Debug);
}
}
+sub _guess_manpage {
+ my($self,$d,$contains,$dist) = @_;
+ $dist =~ s/-/::/g;
+ my $module;
+ if (exists $contains->{$dist}) {
+ $module = $dist;
+ } elsif (1 == keys %$contains) {
+ ($module) = keys %$contains;
+ }
+ my $manpage;
+ if ($module) {
+ my $m = $self->expand("Module",$module);
+ $m->as_string; # called for side-effects, shame
+ $manpage = $m->{MANPAGE};
+ } else {
+ $manpage = "unknown";
+ }
+ return $manpage;
+}
+
+#-> sub CPAN::Shell::_specfile ;
+sub _specfile {
+ my $self = shift;
+ my $distribution = shift;
+ unless ($CPAN::META->has_inst("CPAN::DistnameInfo")){
+ $CPAN::Frontend->mydie("CPAN::DistnameInfo not installed; cannot continue");
+ }
+ my $d = CPAN::Shell->expand("Distribution",$distribution)
+ or $CPAN::Frontend->mydie("Unknowns distribution '$distribution'\n");
+ my $build_dir = $d->{build_dir} or $CPAN::Frontend->mydie("Distribution has not been built yet, cannot proceed");
+ my %contains = map {($_ => undef)} $d->containsmods;
+ my @m;
+ my $width = 16;
+ my $header = sub {
+ my($header,$value) = @_;
+ push @m, sprintf("%-s:%*s%s\n", $header, $width-length($header), "", $value);
+ };
+ my $dni = CPAN::DistnameInfo->new($distribution);
+ my $dist = $dni->dist;
+ my $summary = $self->_guess_manpage($d,\%contains,$dist);
+ $header->("Name", "perl-$dist");
+ my $version = $dni->version;
+ $header->("Version", $version);
+ $header->("Release", "1%{?dist}");
+#Summary: Template processing system
+#Group: Development/Libraries
+#License: GPL+ or Artistic
+#URL: http://www.template-toolkit.org/
+#Source0: http://search.cpan.org/CPAN/authors/id/A/AB/ABW/Template-Toolkit-%{version}.tar.gz
+#Patch0: Template-2.22-SREZIC-01.patch
+#BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+ for my $h_tuple
+ ([Summary => $summary],
+ [Group => "Development/Libraries"],
+ [License =>],
+ [URL =>],
+ [BuildRoot => "%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)"],
+ [Requires => "perl(:MODULE_COMPAT_%(eval \"`%{__perl} -V:version`\"; echo \$version))"],
+ ) {
+ my($h,$v) = @$h_tuple;
+ $v = "unknown" unless defined $v;
+ $header->($h, $v);
+ }
+ $header->("Source0", sprintf(
+ "http://search.cpan.org/CPAN/authors/id/%s/%s/%s",
+ substr($distribution,0,1),
+ substr($distribution,0,2),
+ $distribution
+ ));
+ require POSIX;
+ my @xs = glob "$build_dir/*.xs"; # quick try
+ unless (@xs) {
+ require ExtUtils::Manifest;
+ my $manifest_file = "$build_dir/MANIFEST";
+ my $manifest = ExtUtils::Manifest::maniread($manifest_file);
+ @xs = grep /\.xs$/, keys %$manifest;
+ }
+ if (! @xs) {
+ $header->('BuildArch', 'noarch');
+ }
+ for my $k (sort keys %contains) {
+ my $m = CPAN::Shell->expand("Module",$k);
+ my $v = $contains{$k} = $m->cpan_version;
+ my $vspec = $v eq "undef" ? "" : " = $v";
+ $header->("Provides", "perl($k)$vspec");
+ }
+ if (my $prereq_pm = $d->{prereq_pm}) {
+ my %req;
+ for my $reqkey (keys %$prereq_pm) {
+ while (my($k,$v) = each %{$prereq_pm->{$reqkey}}) {
+ $req{$k} = $v;
+ }
+ }
+ if (-e "$build_dir/Build.PL" && ! exists $req{"Module::Build"}) {
+ $req{"Module::Build"} = 0;
+ }
+ for my $k (sort keys %req) {
+ next if $k eq "perl";
+ my $v = $req{$k};
+ my $vspec = defined $v && length $v && $v > 0 ? " >= $v" : "";
+ $header->(BuildRequires => "perl($k)$vspec");
+ next if $k =~ /^(Module::Build)$/; # MB is always only a
+ # BuildRequires; if we
+ # turn it into a
+ # Requires, then we
+ # would have to make it
+ # a BuildRequires
+ # everywhere we depend
+ # on *one* MB built
+ # module.
+ $header->(Requires => "perl($k)$vspec");
+ }
+ }
+ push @m, "\n%define _use_internal_dependency_generator 0
+%define __find_requires %{nil}
+%define __find_provides %{nil}
+";
+ push @m, "\n%description\n%{summary}.\n";
+ push @m, "\n%prep\n%setup -q -n $dist-%{version}\n";
+ if (-e "$build_dir/Build.PL") {
+ # see http://www.redhat.com/archives/rpm-list/2002-July/msg00110.html about RPM_BUILD_ROOT vs %{buildroot}
+ push @m, <<'EOF';
+
+%build
+%{__perl} Build.PL --installdirs=vendor --libdoc installvendorman3dir
+./Build
+
+%install
+rm -rf $RPM_BUILD_ROOT
+./Build install destdir=$RPM_BUILD_ROOT create_packlist=0
+find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \;
+%{_fixperms} $RPM_BUILD_ROOT/*
+
+%check
+./Build test
+EOF
+ } elsif (-e "$build_dir/Makefile.PL") {
+ push @m, <<'EOF';
+
+%build
+%{__perl} Makefile.PL INSTALLDIRS=vendor
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make pure_install DESTDIR=$RPM_BUILD_ROOT
+find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';'
+find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null ';'
+%{_fixperms} $RPM_BUILD_ROOT/*
+
+%check
+make test
+EOF
+ } else {
+ $CPAN::Frontend->mydie("'$distribution' has neither a Build.PL nor a Makefile.PL\n");
+ }
+ push @m, "\n%clean\nrm -rf \$RPM_BUILD_ROOT\n";
+ my $vendorlib = @xs ? "vendorarch" : "vendorlib";
+ my $date = POSIX::strftime("%a %b %d %Y", gmtime);
+ my @doc = grep { -e "$build_dir/$_" } qw(README Changes);
+ my $exe_stanza = "\n";
+ if (my $exe_files = $d->_exe_files) {
+ if (@$exe_files) {
+ $exe_stanza = "%{_mandir}/man1/*.1*\n";
+ for my $e (@$exe_files) {
+ unless (CPAN->has_inst("File::Basename")) {
+ $CPAN::Frontend->mydie("File::Basename not installed, cannot continue");
+ }
+ my $basename = File::Basename::basename($e);
+ $exe_stanza .= "/usr/bin/$basename\n";
+ }
+ }
+ }
+ push @m, <<EOF;
+
+%files
+%defattr(-,root,root,-)
+%doc @doc
+%{perl_$vendorlib}/*
+%{_mandir}/man3/*.3*
+$exe_stanza
+%changelog
+* $date <akoenig\@specfile.cpan.org> - $version-1
+- autogenerated by _specfile() in CPAN.pm
+
+EOF
+
+ my $ret = join "", @m;
+ $CPAN::Frontend->myprint($ret);
+ open my $specout, ">", "perl-$dist.spec" or die;
+ print $specout $ret;
+ $CPAN::Frontend->myprint("Wrote perl-$dist.spec");
+ $ret;
+}
+
#-> sub CPAN::Shell::report ;
sub report {
my($self,@args) = @_;
#-> sub CPAN::Shell::failed ;
sub failed {
my($self,$only_id,$silent) = @_;
+ my @failed = $self->find_failed($only_id);
+ my $scope;
+ if ($only_id) {
+ $scope = "this command";
+ } elsif ($CPAN::Index::HAVE_REANIMATED) {
+ $scope = "this or a previous session";
+ # it might be nice to have a section for previous session and
+ # a second for this
+ } else {
+ $scope = "this session";
+ }
+ if (@failed) {
+ my $print;
+ my $debug = 0;
+ if ($debug) {
+ $print = join "",
+ map { sprintf "%5d %-45s: %s %s\n", @$_ }
+ sort { $a->[0] <=> $b->[0] } @failed;
+ } else {
+ $print = join "",
+ map { sprintf " %-45s: %s %s\n", @$_[1..3] }
+ sort {
+ $a->[0] <=> $b->[0]
+ ||
+ $a->[4] <=> $b->[4]
+ } @failed;
+ }
+ $CPAN::Frontend->myprint("Failed during $scope:\n$print");
+ } elsif (!$only_id || !$silent) {
+ $CPAN::Frontend->myprint("Nothing failed in $scope\n");
+ }
+}
+
+sub find_failed {
+ my($self,$only_id) = @_;
my @failed;
DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) {
my $failed = "";
next DIST unless $failed;
my $id = $d->id;
$id =~ s|^./../||;
+ ### XXX need to flag optional modules as '(optional)' if they are
+ # from recommends/suggests -- i.e. *show* failure, but make it clear
+ # it was failure of optional module -- xdg, 2012-04-01
+ $id = "(optional) $id" if ! $d->{mandatory};
#$print .= sprintf(
# " %-45s: %s %s\n",
push @failed,
$failed,
$d->{$failed}->text,
$d->{$failed}{TIME}||0,
+ !! $d->{mandatory},
] :
[
1,
$failed,
$d->{$failed},
0,
+ !! $d->{mandatory},
]
);
}
- my $scope;
- if ($only_id) {
- $scope = "this command";
- } elsif ($CPAN::Index::HAVE_REANIMATED) {
- $scope = "this or a previous session";
- # it might be nice to have a section for previous session and
- # a second for this
- } else {
- $scope = "this session";
- }
- ### XXX need to flag optional modules as '(optional)' if they are
- # from recommends/suggests -- i.e. *show* failure, but make it clear
- # it was failure of optional module -- xdg, 2012-04-01
- if (@failed) {
- my $print;
- my $debug = 0;
- if ($debug) {
- $print = join "",
- map { sprintf "%5d %-45s: %s %s\n", @$_ }
- sort { $a->[0] <=> $b->[0] } @failed;
- } else {
- $print = join "",
- map { sprintf " %-45s: %s %s\n", @$_[1..3] }
- sort {
- $a->[0] <=> $b->[0]
- ||
- $a->[4] <=> $b->[4]
- } @failed;
- }
- $CPAN::Frontend->myprint("Failed during $scope:\n$print");
- } elsif (!$only_id || !$silent) {
- $CPAN::Frontend->myprint("Nothing failed in $scope\n");
- }
+ return @failed;
+}
+
+sub mandatory_dist_failed {
+ my ($self) = @_;
+ return grep { $_->[5] } $self->find_failed($CPAN::CurrentCommandID);
}
# XXX intentionally undocumented because completely bogus, unportable,
my $print_ornamented_have_warned = 0;
sub colorize_output {
my $colorize_output = $CPAN::Config->{colorize_output};
+ if ($colorize_output && $^O eq 'MSWin32' && !$CPAN::META->has_inst("Win32::Console::ANSI")) {
+ unless ($print_ornamented_have_warned++) {
+ # no myprint/mywarn within myprint/mywarn!
+ warn "Colorize_output is set to true but Win32::Console::ANSI is not
+installed. To activate colorized output, please install Win32::Console::ANSI.\n\n";
+ }
+ $colorize_output = 0;
+ }
if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
unless ($print_ornamented_have_warned++) {
# no myprint/mywarn within myprint/mywarn!
}
}
}
- CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c");
+ CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c", optional => '');
push @qcopy, $obj;
} elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
$obj = $CPAN::META->instance('CPAN::Author',uc($s));
my $obj;
my $s = $q->as_string;
my $reqtype = $q->reqtype || "";
+ my $optional = $q->optional || "";
$obj = CPAN::Shell->expandany($s);
unless ($obj) {
# don't know how this can happen, maybe we should panic,
next QITEM;
}
$obj->{reqtype} ||= "";
+ my $type = ref $obj;
+ if ( $type eq 'CPAN::Distribution' || $type eq 'CPAN::Bundle' ) {
+ $obj->{mandatory} ||= ! $optional; # once mandatory, always mandatory
+ }
+ elsif ( $type eq 'CPAN::Module' ) {
+ $obj->{mandatory} ||= ! $optional; # once mandatory, always mandatory
+ if (my $d = $obj->distribution) {
+ $d->{mandatory} ||= ! $optional; # once mandatory, always mandatory
+ } elsif ($optional) {
+ # the queue object does not know who was recommending/suggesting us:(
+ # So we only vaguely write "optional".
+ $CPAN::Frontend->mywarn("Warning: optional module '$s' ".
+ "not known. Skipping.\n");
+ CPAN::Queue->delete_first($s);
+ next QITEM;
+ }
+ }
{
# force debugging because CPAN::SQLite somehow delivers us
# an empty object;
$obj->$unpragma();
}
}
- if ($CPAN::Config->{halt_on_failure}
- &&
- CPAN::Distrostatus::something_has_just_failed()
- ) {
+ # if any failures occurred and the current object is mandatory, we
+ # still don't know if *it* failed or if it was another (optional)
+ # module, so we have to check that explicitly (and expensively)
+ if ( $CPAN::Config->{halt_on_failure}
+ && $obj->{mandatory}
+ && CPAN::Distrostatus::something_has_just_failed()
+ && $self->mandatory_dist_failed()
+ ) {
$CPAN::Frontend->mywarn("Stopping: '$meth' failed for '$s'.\n");
CPAN::Queue->nullify_queue;
last QITEM;
use vars qw($VERSION @ISA $BUGHUNTING);
use CPAN::Debug;
use File::Basename qw(basename);
-$VERSION = "5.5011";
+$VERSION = "5.5012";
# module is internal to CPAN.pm
@ISA = qw(CPAN::Debug); ## no critic
return 1;
} else {
my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
- system(qq{$command -dc "$read" > "$write"})==0;
+ system(qq{$command -d -c "$read" > "$write"})==0;
}
}
$class->debug("via Compress::Zlib");
} else {
my $gzip = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
- my $pipe = "$gzip -dc $file |";
+ my $pipe = "$gzip -d -c $file |";
my $fh = FileHandle->new($pipe) or $CPAN::Frontend->mydie("Could not pipe[$pipe]: $!");
binmode $fh;
$self->{FH} = $fh;
my $tarcommand = CPAN::HandleConfig->safe_quote($exttar);
if ($is_compressed) {
my $command = CPAN::HandleConfig->safe_quote($extgzip);
- $system = qq{$command -dc }.
+ $system = qq{$command -d -c }.
qq{< "$file" | $tarcommand x${tar_verb}f -};
} else {
$system = qq{$tarcommand x${tar_verb}f "$file"};
use strict;
use vars qw($VERSION);
-$VERSION = "5.5001";
+$VERSION = "5.5003";
# CPAN::Version::vcmp courtesy Jost Krieger
sub vcmp {
local($^W) = 0;
CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;
+ # treat undef as zero
+ $l = 0 if $l eq 'undef';
+ $r = 0 if $r eq 'undef';
+
return 0 if $l eq $r; # short circuit for quicker success
for ($l,$r) {