917 lines
30 KiB
Perl
917 lines
30 KiB
Perl
package CPANPLUS::Dist::Build;
|
|
$CPANPLUS::Dist::Build::VERSION = '0.90';
|
|
#ABSTRACT: CPANPLUS plugin to install packages that use Build.PL
|
|
|
|
use if $] > 5.017, 'deprecate';
|
|
|
|
use strict;
|
|
use warnings;
|
|
use vars qw[@ISA $STATUS];
|
|
@ISA = qw[CPANPLUS::Dist];
|
|
|
|
use CPANPLUS::Internals::Constants;
|
|
|
|
### these constants were exported by CPANPLUS::Internals::Constants
|
|
### in previous versions.. they do the same though. If we want to have
|
|
### a normal 'use' here, up the dependency to CPANPLUS 0.056 or higher
|
|
BEGIN {
|
|
require CPANPLUS::Dist::Build::Constants;
|
|
CPANPLUS::Dist::Build::Constants->import()
|
|
if not __PACKAGE__->can('BUILD') && __PACKAGE__->can('BUILD_DIR');
|
|
}
|
|
|
|
use CPANPLUS::Error;
|
|
|
|
use Config;
|
|
use FileHandle;
|
|
use Cwd;
|
|
use version;
|
|
|
|
use IPC::Cmd qw[run];
|
|
use Params::Check qw[check];
|
|
use Module::Load::Conditional qw[can_load check_install];
|
|
use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
|
|
|
|
local $Params::Check::VERBOSE = 1;
|
|
|
|
|
|
|
|
### check if the format is available ###
|
|
sub format_available {
|
|
my $mod = 'Module::Build';
|
|
unless( can_load( modules => { $mod => '0.2611' }, nocache => 1 ) ) {
|
|
error( loc( "You do not have '%1' -- '%2' not available",
|
|
$mod, __PACKAGE__ ) );
|
|
return;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
sub init {
|
|
my $dist = shift;
|
|
my $status = $dist->status;
|
|
|
|
$status->mk_accessors(qw[build_pl build test created installed uninstalled
|
|
_create_args _install_args _prepare_args
|
|
_mb_object _buildflags _metadata
|
|
]);
|
|
|
|
### just in case 'format_available' didn't get called
|
|
require Module::Build;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
sub prepare {
|
|
### just in case you already did a create call for this module object
|
|
### just via a different dist object
|
|
my $dist = shift;
|
|
my $self = $dist->parent;
|
|
|
|
### we're also the cpan_dist, since we don't need to have anything
|
|
### prepared from another installer
|
|
$dist = $self->status->dist_cpan if $self->status->dist_cpan;
|
|
$self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
|
|
|
|
my $cb = $self->parent;
|
|
my $conf = $cb->configure_object;
|
|
my %hash = @_;
|
|
|
|
my $dir;
|
|
unless( $dir = $self->status->extract ) {
|
|
error( loc( "No dir found to operate on!" ) );
|
|
return;
|
|
}
|
|
|
|
my $args;
|
|
my( $force, $verbose, $buildflags, $perl, $prereq_target, $prereq_format,
|
|
$prereq_build );
|
|
{ local $Params::Check::ALLOW_UNKNOWN = 1;
|
|
my $tmpl = {
|
|
force => { default => $conf->get_conf('force'),
|
|
store => \$force },
|
|
verbose => { default => $conf->get_conf('verbose'),
|
|
store => \$verbose },
|
|
perl => { default => $^X, store => \$perl },
|
|
buildflags => { default => $conf->get_conf('buildflags'),
|
|
store => \$buildflags },
|
|
prereq_target => { default => '', store => \$prereq_target },
|
|
prereq_format => { default => '',
|
|
store => \$prereq_format },
|
|
prereq_build => { default => 0, store => \$prereq_build },
|
|
};
|
|
|
|
$args = check( $tmpl, \%hash ) or return;
|
|
}
|
|
|
|
return 1 if $dist->status->prepared && !$force;
|
|
|
|
$dist->status->_prepare_args( $args );
|
|
|
|
### chdir to work directory ###
|
|
my $orig = cwd();
|
|
unless( $cb->_chdir( dir => $dir ) ) {
|
|
error( loc( "Could not chdir to build directory '%1'", $dir ) );
|
|
return;
|
|
}
|
|
|
|
### by now we've loaded module::build, and we're using the API, so
|
|
### it's safe to remove CPANPLUS::inc from our inc path, especially
|
|
### because it can trip up tests run under taint (just like EU::MM).
|
|
### turn off our PERL5OPT so no modules from CPANPLUS::inc get
|
|
### included in make test -- it should build without.
|
|
### also, modules that run in taint mode break if we leave
|
|
### our code ref in perl5opt
|
|
### XXX we've removed the ENV settings from cp::inc, so only need
|
|
### to reset the @INC
|
|
#local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt;
|
|
#local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib;
|
|
#local @INC = CPANPLUS::inc->original_inc;
|
|
|
|
### this will generate warnings under anything lower than M::B 0.2606
|
|
my @buildflags = $dist->_buildflags_as_list( $buildflags );
|
|
$dist->status->_buildflags( $buildflags );
|
|
|
|
my $fail; my $prereq_fail;
|
|
my $status = { };
|
|
RUN: {
|
|
|
|
# 0.85_01
|
|
### we resolve 'configure requires' here, so we can run the 'perl
|
|
### Makefile.PL' command
|
|
### XXX for tests: mock f_c_r to something that *can* resolve and
|
|
### something that *doesn't* resolve. Check the error log for ok
|
|
### on this step or failure
|
|
### XXX make a separate tarball to test for this scenario: simply
|
|
### containing a makefile.pl/build.pl for test purposes?
|
|
my $safe_ver = version->new('0.85_01');
|
|
if ( version->new($CPANPLUS::Internals::VERSION) >= $safe_ver )
|
|
{ my $configure_requires = $dist->find_configure_requires;
|
|
my $ok = $dist->_resolve_prereqs(
|
|
format => $prereq_format,
|
|
verbose => $verbose,
|
|
prereqs => $configure_requires,
|
|
target => $prereq_target,
|
|
force => $force,
|
|
prereq_build => $prereq_build,
|
|
);
|
|
|
|
unless( $ok ) {
|
|
|
|
#### use $dist->flush to reset the cache ###
|
|
error( loc( "Unable to satisfy '%1' for '%2' " .
|
|
"-- aborting install",
|
|
'configure_requires', $self->module ) );
|
|
$dist->status->prepared(0);
|
|
$prereq_fail++;
|
|
$fail++;
|
|
last RUN;
|
|
}
|
|
### end of prereq resolving ###
|
|
}
|
|
|
|
# Wrap the exception that may be thrown here (should likely be
|
|
# done at a much higher level).
|
|
my $prep_output;
|
|
|
|
my $metadata = $dist->status->_metadata;
|
|
my $x_use_unsafe_inc = ( defined $metadata && exists $metadata->{x_use_unsafe_inc} ? $metadata->{x_use_unsafe_inc} : undef );
|
|
$x_use_unsafe_inc = 1 unless defined $x_use_unsafe_inc;
|
|
|
|
local $ENV{PERL_USE_UNSAFE_INC} = $x_use_unsafe_inc
|
|
unless exists $ENV{PERL_USE_UNSAFE_INC};
|
|
|
|
my $env = ENV_CPANPLUS_IS_EXECUTING;
|
|
local $ENV{$env} = BUILD_PL->( $dir );
|
|
my @run_perl = $dist->_perlrun();
|
|
my $cmd = [$perl, @run_perl, BUILD_PL->($dir), @buildflags];
|
|
|
|
unless ( scalar run( command => $cmd,
|
|
buffer => \$prep_output,
|
|
verbose => $verbose )
|
|
) {
|
|
error( loc( "Build.PL failed: %1", $prep_output ) );
|
|
if ( $conf->get_conf('cpantest') ) {
|
|
$status->{stage} = 'prepare';
|
|
$status->{capture} = $prep_output;
|
|
}
|
|
$fail++; last RUN;
|
|
}
|
|
|
|
unless ( -e BUILD->( $dir ) ) {
|
|
error( loc( "Build.PL failed to generate a Build script: %1", $prep_output ) );
|
|
if ( $conf->get_conf('cpantest') ) {
|
|
$status->{stage} = 'prepare';
|
|
$status->{capture} = $prep_output;
|
|
}
|
|
$fail++; last RUN;
|
|
}
|
|
|
|
msg( $prep_output, 0 );
|
|
|
|
my $prereqs = $self->status->prereqs;
|
|
|
|
$prereqs ||= $dist->_find_prereqs( verbose => $verbose,
|
|
dir => $dir,
|
|
perl => $perl,
|
|
buildflags => $buildflags );
|
|
|
|
}
|
|
|
|
### send out test report? ###
|
|
### there is no way to accurately know if it is a PASS/FAIL/ETC
|
|
### CPANPLUS::Dist::MM doesn't bother why are we?
|
|
if( 0 and $fail and $conf->get_conf('cpantest') and not $prereq_fail ) {
|
|
$cb->_send_report(
|
|
module => $self,
|
|
failed => $fail,
|
|
buffer => CPANPLUS::Error->stack_as_string,
|
|
status => $status,
|
|
verbose => $verbose,
|
|
force => $force,
|
|
) or error(loc("Failed to send test report for '%1'",
|
|
$self->module ) );
|
|
}
|
|
|
|
unless( $cb->_chdir( dir => $orig ) ) {
|
|
error( loc( "Could not chdir back to start dir '%1'", $orig ) );
|
|
}
|
|
|
|
### save where we wrote this stuff -- same as extract dir in normal
|
|
### installer circumstances
|
|
$dist->status->distdir( $self->status->extract );
|
|
|
|
return $dist->status->prepared( $fail ? 0 : 1 );
|
|
}
|
|
|
|
sub _find_prereqs {
|
|
my $dist = shift;
|
|
my $self = $dist->parent;
|
|
my $cb = $self->parent;
|
|
my $conf = $cb->configure_object;
|
|
my %hash = @_;
|
|
|
|
my ($verbose, $dir, $buildflags, $perl);
|
|
my $tmpl = {
|
|
verbose => { default => $conf->get_conf('verbose'), store => \$verbose },
|
|
dir => { default => $self->status->extract, store => \$dir },
|
|
perl => { default => $^X, store => \$perl },
|
|
buildflags => { default => $conf->get_conf('buildflags'),
|
|
store => \$buildflags },
|
|
};
|
|
|
|
my $args = check( $tmpl, \%hash ) or return;
|
|
|
|
my $prereqs = {};
|
|
|
|
$prereqs = $dist->find_mymeta_requires()
|
|
if $dist->can('find_mymeta_requires');
|
|
|
|
if ( keys %$prereqs ) {
|
|
# Ugly hack
|
|
}
|
|
else {
|
|
my $safe_ver = version->new('0.31_03');
|
|
my $content;
|
|
PREREQS: {
|
|
if ( version->new( $Module::Build::VERSION ) >= $safe_ver and IPC::Cmd->can_capture_buffer ) {
|
|
my @buildflags = $dist->_buildflags_as_list( $buildflags );
|
|
|
|
# Use the new Build action 'prereq_data'
|
|
my @run_perl = $dist->_perlrun();
|
|
|
|
unless ( scalar run( command => [$perl, @run_perl, BUILD->($dir), 'prereq_data', @buildflags],
|
|
buffer => \$content,
|
|
verbose => 0 )
|
|
) {
|
|
error( loc( "Build 'prereq_data' failed: %1 %2", $!, $content ) );
|
|
#return;
|
|
}
|
|
else {
|
|
last PREREQS;
|
|
}
|
|
|
|
}
|
|
|
|
my $file = File::Spec->catfile( $dir, '_build', 'prereqs' );
|
|
return unless -f $file;
|
|
|
|
my $fh = FileHandle->new();
|
|
|
|
unless( $fh->open( $file ) ) {
|
|
error( loc( "Cannot open '%1': %2", $file, $! ) );
|
|
return;
|
|
}
|
|
|
|
$content = do { local $/; <$fh> };
|
|
|
|
}
|
|
|
|
return unless $content;
|
|
my $bphash = eval $content;
|
|
return unless $bphash and ref $bphash eq 'HASH';
|
|
foreach my $type ('requires', 'build_requires', 'test_requires') {
|
|
next unless $bphash->{$type} and ref $bphash->{$type} eq 'HASH';
|
|
$prereqs->{$_} = $bphash->{$type}->{$_} for keys %{ $bphash->{$type} };
|
|
}
|
|
}
|
|
|
|
{
|
|
delete $prereqs->{'perl'}
|
|
unless version->new($CPANPLUS::Internals::VERSION)
|
|
>= version->new('0.9102');
|
|
}
|
|
|
|
### allows for a user defined callback to filter the prerequisite
|
|
### list as they see fit, to remove (or add) any prereqs they see
|
|
### fit. The default installed callback will return the hashref in
|
|
### an unmodified form
|
|
### this callback got added after cpanplus 0.0562, so use a 'can'
|
|
### to find out if it's supported. For older versions, we'll just
|
|
### return the hashref as is ourselves.
|
|
my $href = $cb->_callbacks->can('filter_prereqs')
|
|
? $cb->_callbacks->filter_prereqs->( $cb, $prereqs )
|
|
: $prereqs;
|
|
|
|
$self->status->prereqs( $href );
|
|
|
|
### make sure it's not the same ref
|
|
return { %$href };
|
|
}
|
|
|
|
|
|
sub create {
|
|
### just in case you already did a create call for this module object
|
|
### just via a different dist object
|
|
my $dist = shift;
|
|
my $self = $dist->parent;
|
|
|
|
### we're also the cpan_dist, since we don't need to have anything
|
|
### prepared from another installer
|
|
$dist = $self->status->dist_cpan if $self->status->dist_cpan;
|
|
$self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
|
|
|
|
my $cb = $self->parent;
|
|
my $conf = $cb->configure_object;
|
|
my %hash = @_;
|
|
|
|
my $dir;
|
|
unless( $dir = $self->status->extract ) {
|
|
error( loc( "No dir found to operate on!" ) );
|
|
return;
|
|
}
|
|
|
|
my $args;
|
|
my( $force, $verbose, $buildflags, $skiptest, $prereq_target,
|
|
$perl, $prereq_format, $prereq_build);
|
|
{ local $Params::Check::ALLOW_UNKNOWN = 1;
|
|
my $tmpl = {
|
|
force => { default => $conf->get_conf('force'),
|
|
store => \$force },
|
|
verbose => { default => $conf->get_conf('verbose'),
|
|
store => \$verbose },
|
|
perl => { default => $^X, store => \$perl },
|
|
buildflags => { default => $conf->get_conf('buildflags'),
|
|
store => \$buildflags },
|
|
skiptest => { default => $conf->get_conf('skiptest'),
|
|
store => \$skiptest },
|
|
prereq_target => { default => '', store => \$prereq_target },
|
|
### don't set the default format to 'build' -- that is wrong!
|
|
prereq_format => { #default => $self->status->installer_type,
|
|
default => '',
|
|
store => \$prereq_format },
|
|
prereq_build => { default => 0, store => \$prereq_build },
|
|
};
|
|
|
|
$args = check( $tmpl, \%hash ) or return;
|
|
}
|
|
|
|
# restore the state as we have created this already.
|
|
if ( $dist->status->created && !$force ) {
|
|
### add this directory to your lib ###
|
|
$self->add_to_includepath();
|
|
return 1;
|
|
}
|
|
|
|
$dist->status->_create_args( $args );
|
|
|
|
### is this dist prepared?
|
|
unless( $dist->status->prepared ) {
|
|
error( loc( "You have not successfully prepared a '%2' distribution ".
|
|
"yet -- cannot create yet", __PACKAGE__ ) );
|
|
return;
|
|
}
|
|
|
|
### chdir to work directory ###
|
|
my $orig = cwd();
|
|
unless( $cb->_chdir( dir => $dir ) ) {
|
|
error( loc( "Could not chdir to build directory '%1'", $dir ) );
|
|
return;
|
|
}
|
|
|
|
### by now we've loaded module::build, and we're using the API, so
|
|
### it's safe to remove CPANPLUS::inc from our inc path, especially
|
|
### because it can trip up tests run under taint (just like EU::MM).
|
|
### turn off our PERL5OPT so no modules from CPANPLUS::inc get
|
|
### included in make test -- it should build without.
|
|
### also, modules that run in taint mode break if we leave
|
|
### our code ref in perl5opt
|
|
### XXX we've removed the ENV settings from cp::inc, so only need
|
|
### to reset the @INC
|
|
#local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt;
|
|
#local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib;
|
|
#local @INC = CPANPLUS::inc->original_inc;
|
|
|
|
### but do it *before* the new_from_context, as M::B seems
|
|
### to be actually running the file...
|
|
### an unshift in the block seems to be ignored.. somehow...
|
|
#{ my $lib = $self->best_path_to_module_build;
|
|
# unshift @INC, $lib if $lib;
|
|
#}
|
|
unshift @INC, $self->best_path_to_module_build
|
|
if $self->best_path_to_module_build;
|
|
|
|
### this will generate warnings under anything lower than M::B 0.2606
|
|
my @buildflags = $dist->_buildflags_as_list( $buildflags );
|
|
$dist->status->_buildflags( $buildflags );
|
|
|
|
my $fail; my $prereq_fail; my $test_fail;
|
|
my $status = { };
|
|
RUN: {
|
|
|
|
my @run_perl = $dist->_perlrun();
|
|
|
|
### this will set the directory back to the start
|
|
### dir, so we must chdir /again/
|
|
my $ok = $dist->_resolve_prereqs(
|
|
force => $force,
|
|
format => $prereq_format,
|
|
verbose => $verbose,
|
|
prereqs => $self->status->prereqs,
|
|
target => $prereq_target,
|
|
prereq_build => $prereq_build,
|
|
);
|
|
|
|
my $metadata = $dist->status->_metadata;
|
|
my $x_use_unsafe_inc = ( defined $metadata && exists $metadata->{x_use_unsafe_inc} ? $metadata->{x_use_unsafe_inc} : undef );
|
|
$x_use_unsafe_inc = 1 unless defined $x_use_unsafe_inc;
|
|
|
|
local $ENV{PERL_USE_UNSAFE_INC} = $x_use_unsafe_inc
|
|
unless exists $ENV{PERL_USE_UNSAFE_INC};
|
|
|
|
unless( $cb->_chdir( dir => $dir ) ) {
|
|
error( loc( "Could not chdir to build directory '%1'", $dir ) );
|
|
return;
|
|
}
|
|
|
|
unless( $ok ) {
|
|
#### use $dist->flush to reset the cache ###
|
|
error( loc( "Unable to satisfy prerequisites for '%1' " .
|
|
"-- aborting install", $self->module ) );
|
|
$dist->status->build(0);
|
|
$fail++; $prereq_fail++;
|
|
last RUN;
|
|
}
|
|
|
|
my ($captured, $cmd);
|
|
if ( ON_VMS ) {
|
|
$cmd = [$perl, BUILD->($dir), @buildflags];
|
|
}
|
|
else {
|
|
$cmd = [$perl, @run_perl, BUILD->($dir), @buildflags];
|
|
}
|
|
|
|
unless ( scalar run( command => $cmd,
|
|
buffer => \$captured,
|
|
verbose => $verbose )
|
|
) {
|
|
error( loc( "MAKE failed:\n%1", $captured ) );
|
|
$dist->status->build(0);
|
|
if ( $conf->get_conf('cpantest') ) {
|
|
$status->{stage} = 'build';
|
|
$status->{capture} = $captured;
|
|
}
|
|
$fail++; last RUN;
|
|
}
|
|
|
|
msg( $captured, 0 );
|
|
|
|
$dist->status->build(1);
|
|
|
|
### add this directory to your lib ###
|
|
$self->add_to_includepath();
|
|
|
|
### this buffer will not include what tests failed due to a
|
|
### M::B/Test::Harness bug. Reported as #9793 with patch
|
|
### against 0.2607 on 26/1/2005
|
|
unless( $skiptest ) {
|
|
my $test_output;
|
|
if ( ON_VMS ) {
|
|
$cmd = [$perl, BUILD->($dir), "test", @buildflags];
|
|
}
|
|
else {
|
|
$cmd = [$perl, @run_perl, BUILD->($dir), "test", @buildflags];
|
|
}
|
|
local $ENV{PERL_INSTALL_QUIET};
|
|
unless ( scalar run( command => $cmd,
|
|
buffer => \$test_output,
|
|
verbose => $verbose )
|
|
) {
|
|
error( loc( "MAKE TEST failed:\n%1 ", $test_output ), ( $verbose ? 0 : 1 ) );
|
|
|
|
### mark specifically *test* failure.. so we don't
|
|
### send success on force...
|
|
$test_fail++;
|
|
|
|
if( !$force and !$cb->_callbacks->proceed_on_test_failure->(
|
|
$self, $@ )
|
|
) {
|
|
$dist->status->test(0);
|
|
if ( $conf->get_conf('cpantest') ) {
|
|
$status->{stage} = 'test';
|
|
$status->{capture} = $test_output;
|
|
}
|
|
$fail++; last RUN;
|
|
}
|
|
|
|
}
|
|
else {
|
|
msg( loc( "MAKE TEST passed:\n%1", $test_output ), 0 );
|
|
$dist->status->test(1);
|
|
if ( $conf->get_conf('cpantest') ) {
|
|
$status->{stage} = 'test';
|
|
$status->{capture} = $test_output;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
msg(loc("Tests skipped"), $verbose);
|
|
}
|
|
}
|
|
|
|
unless( $cb->_chdir( dir => $orig ) ) {
|
|
error( loc( "Could not chdir back to start dir '%1'", $orig ) );
|
|
}
|
|
|
|
### send out test report? ###
|
|
if( $conf->get_conf('cpantest') and not $prereq_fail ) {
|
|
$cb->_send_report(
|
|
module => $self,
|
|
failed => $test_fail || $fail,
|
|
buffer => CPANPLUS::Error->stack_as_string,
|
|
status => $status,
|
|
verbose => $verbose,
|
|
force => $force,
|
|
tests_skipped => $skiptest,
|
|
) or error(loc("Failed to send test report for '%1'",
|
|
$self->module ) );
|
|
}
|
|
|
|
return $dist->status->created( $fail ? 0 : 1 );
|
|
}
|
|
|
|
|
|
sub install {
|
|
### just in case you already did a create call for this module object
|
|
### just via a different dist object
|
|
my $dist = shift;
|
|
my $self = $dist->parent;
|
|
|
|
### we're also the cpan_dist, since we don't need to have anything
|
|
### prepared from another installer
|
|
$dist = $self->status->dist_cpan if $self->status->dist_cpan;
|
|
|
|
my $cb = $self->parent;
|
|
my $conf = $cb->configure_object;
|
|
my %hash = @_;
|
|
|
|
|
|
my $verbose; my $perl; my $force; my $buildflags;
|
|
{ local $Params::Check::ALLOW_UNKNOWN = 1;
|
|
my $tmpl = {
|
|
verbose => { default => $conf->get_conf('verbose'),
|
|
store => \$verbose },
|
|
force => { default => $conf->get_conf('force'),
|
|
store => \$force },
|
|
buildflags => { default => $conf->get_conf('buildflags'),
|
|
store => \$buildflags },
|
|
perl => { default => $^X, store => \$perl },
|
|
};
|
|
|
|
my $args = check( $tmpl, \%hash ) or return;
|
|
$dist->status->_install_args( $args );
|
|
}
|
|
|
|
my $dir;
|
|
unless( $dir = $self->status->extract ) {
|
|
error( loc( "No dir found to operate on!" ) );
|
|
return;
|
|
}
|
|
|
|
my $orig = cwd();
|
|
|
|
unless( $cb->_chdir( dir => $dir ) ) {
|
|
error( loc( "Could not chdir to build directory '%1'", $dir ) );
|
|
return;
|
|
}
|
|
|
|
### value set and false -- means failure ###
|
|
if( defined $self->status->installed &&
|
|
!$self->status->installed && !$force
|
|
) {
|
|
error( loc( "Module '%1' has failed to install before this session " .
|
|
"-- aborting install", $self->module ) );
|
|
return;
|
|
}
|
|
|
|
my $fail;
|
|
my @buildflags = $dist->_buildflags_as_list( $buildflags );
|
|
my @run_perl = $dist->_perlrun();
|
|
|
|
my $metadata = $dist->status->_metadata;
|
|
my $x_use_unsafe_inc = ( defined $metadata && exists $metadata->{x_use_unsafe_inc} ? $metadata->{x_use_unsafe_inc} : undef );
|
|
$x_use_unsafe_inc = 1 unless defined $x_use_unsafe_inc;
|
|
|
|
local $ENV{PERL_USE_UNSAFE_INC} = $x_use_unsafe_inc
|
|
unless exists $ENV{PERL_USE_UNSAFE_INC};
|
|
|
|
### hmm, how is this going to deal with sudo?
|
|
### for now, check effective uid, if it's not root,
|
|
### shell out, otherwise use the method
|
|
if( $> ) {
|
|
|
|
### don't worry about loading the right version of M::B anymore
|
|
### the 'new_from_context' already added the 'right' path to
|
|
### M::B at the top of the build.pl
|
|
my $cmd;
|
|
if ( ON_VMS ) {
|
|
$cmd = [$perl, BUILD->($dir), "install", @buildflags];
|
|
}
|
|
else {
|
|
$cmd = [$perl, @run_perl, BUILD->($dir), "install", @buildflags];
|
|
}
|
|
|
|
### Detect local::lib type behaviour. Do not use 'sudo' in these cases
|
|
my $sudo = $conf->get_program('sudo');
|
|
SUDO: {
|
|
### Actual local::lib in use
|
|
last SUDO if defined $ENV{PERL_MB_OPT} and $ENV{PERL_MB_OPT} =~ m!install_base!;
|
|
### 'buildflags' is configured with '--install_base'
|
|
last SUDO if scalar grep { m!install_base! } @buildflags;
|
|
### oh well 'sudo make me a sandwich'
|
|
unshift @$cmd, $sudo;
|
|
}
|
|
|
|
my $buffer;
|
|
unless( scalar run( command => $cmd,
|
|
buffer => \$buffer,
|
|
verbose => $verbose )
|
|
) {
|
|
error(loc("Could not run '%1': %2", 'Build install', $buffer));
|
|
$fail++;
|
|
}
|
|
} else {
|
|
my ($install_output, $cmd);
|
|
if ( ON_VMS ) {
|
|
$cmd = [$perl, BUILD->($dir), "install", @buildflags];
|
|
}
|
|
else {
|
|
$cmd = [$perl, @run_perl, BUILD->($dir), "install", @buildflags];
|
|
}
|
|
unless( scalar run( command => $cmd,
|
|
buffer => \$install_output,
|
|
verbose => $verbose )
|
|
) {
|
|
error(loc("Could not run '%1': %2", 'Build install', $install_output));
|
|
$fail++;
|
|
}
|
|
else {
|
|
msg( $install_output, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
unless( $cb->_chdir( dir => $orig ) ) {
|
|
error( loc( "Could not chdir back to start dir '%1'", $orig ) );
|
|
}
|
|
|
|
return $dist->status->installed( $fail ? 0 : 1 );
|
|
}
|
|
|
|
### returns the string 'foo=bar --zot quux'
|
|
### as the list 'foo=bar', '--zot', 'qux'
|
|
sub _buildflags_as_list {
|
|
my $self = shift;
|
|
my $flags = shift or return;
|
|
|
|
return Module::Build->split_like_shell($flags);
|
|
}
|
|
|
|
{
|
|
my $afe_ver = version->new($CPANPLUS::Internals::VERSION) >= version->new("0.9166");
|
|
|
|
sub _perlrun {
|
|
my $self = shift;
|
|
if ( $afe_ver ) {
|
|
return ( '-MCPANPLUS::Internals::Utils::Autoflush' );
|
|
}
|
|
else {
|
|
return ( '-e', CPDB_PERL_WRAPPER );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
qq[Putting the Module::Build into CPANPLUS];
|
|
|
|
|
|
# Local variables:
|
|
# c-indentation-style: bsd
|
|
# c-basic-offset: 4
|
|
# indent-tabs-mode: nil
|
|
# End:
|
|
# vim: expandtab shiftwidth=4:
|
|
|
|
__END__
|
|
|
|
=pod
|
|
|
|
=encoding UTF-8
|
|
|
|
=head1 NAME
|
|
|
|
CPANPLUS::Dist::Build - CPANPLUS plugin to install packages that use Build.PL
|
|
|
|
=head1 VERSION
|
|
|
|
version 0.90
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
my $build = CPANPLUS::Dist->new(
|
|
format => 'CPANPLUS::Dist::Build',
|
|
module => $modobj,
|
|
);
|
|
|
|
$build->prepare; # runs Build.PL
|
|
$build->create; # runs build && build test
|
|
$build->install; # runs build install
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
C<CPANPLUS::Dist::Build> is a distribution class for C<Module::Build>
|
|
related modules.
|
|
Using this package, you can create, install and uninstall perl
|
|
modules. It inherits from C<CPANPLUS::Dist>.
|
|
|
|
Normal users won't have to worry about the interface to this module,
|
|
as it functions transparently as a plug-in to C<CPANPLUS> and will
|
|
just C<Do The Right Thing> when it's loaded.
|
|
|
|
=head1 ACCESSORS
|
|
|
|
=over 4
|
|
|
|
=item C<parent()>
|
|
|
|
Returns the C<CPANPLUS::Module> object that parented this object.
|
|
|
|
=item C<status()>
|
|
|
|
Returns the C<Object::Accessor> object that keeps the status for
|
|
this module.
|
|
|
|
=back
|
|
|
|
=head1 STATUS ACCESSORS
|
|
|
|
All accessors can be accessed as follows:
|
|
$build->status->ACCESSOR
|
|
|
|
=over 4
|
|
|
|
=item C<build_pl ()>
|
|
|
|
Location of the Build file.
|
|
Set to 0 explicitly if something went wrong.
|
|
|
|
=item C<build ()>
|
|
|
|
BOOL indicating if the C<Build> command was successful.
|
|
|
|
=item C<test ()>
|
|
|
|
BOOL indicating if the C<Build test> command was successful.
|
|
|
|
=item C<prepared ()>
|
|
|
|
BOOL indicating if the C<prepare> call exited successfully
|
|
This gets set after C<perl Build.PL>
|
|
|
|
=item C<distdir ()>
|
|
|
|
Full path to the directory in which the C<prepare> call took place,
|
|
set after a call to C<prepare>.
|
|
|
|
=item C<created ()>
|
|
|
|
BOOL indicating if the C<create> call exited successfully. This gets
|
|
set after C<Build> and C<Build test>.
|
|
|
|
=item C<installed ()>
|
|
|
|
BOOL indicating if the module was installed. This gets set after
|
|
C<Build install> exits successfully.
|
|
|
|
=item uninstalled ()
|
|
|
|
BOOL indicating if the module was uninstalled properly.
|
|
|
|
=item C<_create_args ()>
|
|
|
|
Storage of the arguments passed to C<create> for this object. Used
|
|
for recursive calls when satisfying prerequisites.
|
|
|
|
=item C<_install_args ()>
|
|
|
|
Storage of the arguments passed to C<install> for this object. Used
|
|
for recursive calls when satisfying prerequisites.
|
|
|
|
=back
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 $bool = CPANPLUS::Dist::Build->format_available();
|
|
|
|
Returns a boolean indicating whether or not you can use this package
|
|
to create and install modules in your environment.
|
|
|
|
=head2 $bool = $dist->init();
|
|
|
|
Sets up the C<CPANPLUS::Dist::Build> object for use.
|
|
Effectively creates all the needed status accessors.
|
|
|
|
Called automatically whenever you create a new C<CPANPLUS::Dist> object.
|
|
|
|
=head2 $bool = $dist->prepare([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL])
|
|
|
|
C<prepare> prepares a distribution, running C<Build.PL>
|
|
and establishing any prerequisites this
|
|
distribution has.
|
|
|
|
The variable C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path
|
|
of the C<Build.PL> that is being executed. This enables any code inside
|
|
the C<Build.PL> to know that it is being installed via CPANPLUS.
|
|
|
|
After a successful C<prepare> you may call C<create> to create the
|
|
distribution, followed by C<install> to actually install it.
|
|
|
|
Returns true on success and false on failure.
|
|
|
|
=head2 $dist->create([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL])
|
|
|
|
C<create> preps a distribution for installation. This means it will
|
|
run C<Build> and C<Build test>.
|
|
This will also satisfy any prerequisites the module may have.
|
|
|
|
If you set C<skiptest> to true, it will skip the C<Build test> stage.
|
|
If you set C<force> to true, it will go over all the stages of the
|
|
C<Build> process again, ignoring any previously cached results. It
|
|
will also ignore a bad return value from C<Build test> and still allow
|
|
the operation to return true.
|
|
|
|
Returns true on success and false on failure.
|
|
|
|
You may then call C<< $dist->install >> on the object to actually
|
|
install it.
|
|
|
|
=head2 $dist->install([verbose => BOOL, perl => /path/to/perl])
|
|
|
|
Actually installs the created dist.
|
|
|
|
Returns true on success and false on failure.
|
|
|
|
=head1 PROMINENCE
|
|
|
|
Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working
|
|
condition by Ken Williams E<lt>kwilliams@cpan.orgE<gt>.
|
|
|
|
Other hackery and currently maintained by Chris C<BinGOs> Williams ( no relation ). E<lt>bingos@cpan.orgE<gt>.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Jos Boumans <kane[at]cpan.org>, Ken Williams <kwilliams@cpan.org>
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
This software is copyright (c) 2018 by Jos Boumans, Ken Williams, Chris Williams and David Golden.
|
|
|
|
This is free software; you can redistribute it and/or modify it under
|
|
the same terms as the Perl 5 programming language system itself.
|
|
|
|
=cut
|