Dist-Zilla-Plugin-OptionalFeature
view release on metacpan or search on metacpan
lib/Dist/Zilla/Plugin/OptionalFeature.pm view on Meta::CPAN
use MooseX::Types::Common::String 'NonEmptySimpleStr';
use Carp 'confess';
use Module::Runtime 'use_module';
use namespace::autoclean;
has name => (
is => 'ro', isa => NonEmptySimpleStr,
required => 1,
);
has description => (
is => 'ro', isa => NonEmptySimpleStr,
required => 1,
);
has always_recommend => (
is => 'ro', isa => Bool,
default => 0,
);
has always_suggest => (
is => 'ro', isa => Bool,
lazy => 1,
default => sub { shift->always_recommend ? 0 : 1 },
);
has require_develop => (
is => 'ro', isa => Bool,
default => 1,
);
has prompt => (
is => 'ro', isa => Bool,
lazy => 1,
default => sub { shift->_prereq_type eq 'requires' ? 1 : 0 },
);
has default => (
is => 'ro', isa => Bool,
predicate => '_has_default',
# NO DEFAULT
);
has check_prereqs => (
is => 'ro', isa => Bool,
default => 1,
);
has _prereq_phase => (
is => 'ro', isa => NonEmptySimpleStr,
lazy => 1,
default => 'runtime',
);
has _prereq_type => (
is => 'ro', isa => NonEmptySimpleStr,
lazy => 1,
default => 'requires',
);
has _prereqs => (
is => 'ro', isa => HashRef[NonEmptySimpleStr],
lazy => 1,
default => sub { {} },
traits => ['Hash'],
handles => { _prereq_modules => 'keys', _prereq_version => 'get' },
);
sub mvp_aliases { +{ -relationship => '-type', -load_prereqs => '-check_prereqs' } }
around BUILDARGS => sub
{
my $orig = shift;
my $class = shift;
my $args = $class->$orig(@_);
my @private = grep { /^_/ } keys %$args;
confess "Invalid options: @private" if @private;
# pull these out so they don't become part of our prereq list
my ($zilla, $plugin_name) = delete @{$args}{qw(zilla plugin_name)};
my %opts = (
map { exists $args->{$_} ? ( substr($_, 1) => delete($args->{$_}) ) : () }
qw(-name -description -always_recommend -always_suggest -require_develop -prompt -default -check_prereqs -phase -type));
$opts{type} //= delete $args->{'-relationship'} if defined $args->{'-relationship'};
my @other_options = grep { /^-/ } keys %$args;
delete @{$args}{@other_options};
warn "[OptionalFeature] warning: unrecognized option(s): @other_options" if @other_options;
# handle magic plugin names
if ((not $opts{name} or not $opts{phase} or not $opts{type})
# plugin comes from a bundle
and $plugin_name !~ m! (?: \A | / ) OptionalFeature \z !x)
{
$opts{name} ||= $plugin_name;
if ($opts{name} =~ / -
(Build|Test|Runtime|Configure|Develop)
(Requires|Recommends|Suggests|Conflicts)?
\z/xp)
{
$opts{name} = ${^PREMATCH};
$opts{phase} ||= lc($1) if $1;
$opts{type} = lc($2) if $2;
}
}
confess 'optional features may not use the configure phase'
if $opts{phase} and $opts{phase} eq 'configure';
$opts{_prereq_phase} = delete $opts{phase} if exists $opts{phase};
$opts{_prereq_type} = delete $opts{type} if exists $opts{type};
return {
zilla => $zilla,
plugin_name => $plugin_name,
%opts,
_prereqs => $args,
};
};
has _dynamicprereqs_prompt => (
is => 'ro', isa => 'ArrayRef[Str]',
lazy => 1,
default => sub {
my $self = shift;
my $phase = $self->_prereq_phase;
my $function = $phase eq 'runtime' ? 'requires'
: $phase eq 'test' ? 'test_requires'
: $phase eq 'build' ? 'build_requires'
: $self->log_fatal("illegal phase $phase");
$self->log_fatal('prompts are only used for the \'requires\' type')
if $self->_prereq_type ne 'requires';
(my $description = $self->description) =~ s/'/\\'/g;
my $prompt = "prompt('install $description? "
. ($self->default ? "[Y/n]', 'Y'" : "[y/N]', 'N'" )
. ') =~ /^y/i';
my @directives = map {
my $version = $self->_prereq_version($_);
$function . "('$_'" . ($version ? ", '$version'" : '') . ')'
} sort $self->_prereq_modules;
my $require_clause = !$self->check_prereqs ? ''
: (join(' && ', map {
my $version = $self->_prereq_version($_);
"has_module('$_'" . ($version ? ", '$version'" : '') . ')'
} sort $self->_prereq_modules
) . "\n || ");
[
@directives > 1
? (
'if (' . $require_clause . $prompt . ') {', # to mollify vim
(map { ' ' . $_ . ';' } @directives),
'}',
)
: ( @directives , ' if ' . $require_clause . $prompt . ';' )
];
},
);
# package-scoped singleton to track the OptionalFeature instance that manages all the dynamic prereqs
my $master_plugin;
sub __clear_master_plugin { undef $master_plugin } # for testing
sub before_build
{
my $self = shift;
if ($self->prompt and not $master_plugin)
{
# because [DynamicPrereqs] inserts Makefile.PL content in reverse
# order to when it was called, we make just one [OptionalFeature]
# plugin will create and add all DynamicPrereqs plugins, so the order
# of the prompts is in the same order as the dist.ini declarations and
# the corresponding metadata.
$master_plugin = $self;
my $plugin = use_module('Dist::Zilla::Plugin::DynamicPrereqs')->new(
( run in 1.705 second using v1.01-cache-2.11-cpan-39bf76dae61 )