<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package CPANPLUS::Dist::Build;

use strict;
use warnings;
use vars    qw[@ISA $STATUS $VERSION];
@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-&gt;import()
        if not __PACKAGE__-&gt;can('BUILD') &amp;&amp; __PACKAGE__-&gt;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 =&gt; 'CPANPLUS', Style =&gt; 'gettext';

local $Params::Check::VERBOSE = 1;

$VERSION = '0.62';

=pod

=head1 NAME

CPANPLUS::Dist::Build - CPANPLUS plugin to install packages that use Build.PL

=head1 SYNOPSIS

    my $build = CPANPLUS::Dist-&gt;new(
                                format  =&gt; 'CPANPLUS::Dist::Build',
                                module  =&gt; $modobj,
                            );

    $build-&gt;prepare;    # runs Build.PL
    $build-&gt;create;     # runs build &amp;&amp; build test
    $build-&gt;install;    # runs build install


=head1 DESCRIPTION

C&lt;CPANPLUS::Dist::Build&gt; is a distribution class for C&lt;Module::Build&gt;
related modules.
Using this package, you can create, install and uninstall perl
modules. It inherits from C&lt;CPANPLUS::Dist&gt;.

Normal users won't have to worry about the interface to this module,
as it functions transparently as a plug-in to C&lt;CPANPLUS&gt; and will
just C&lt;Do The Right Thing&gt; when it's loaded.

=head1 ACCESSORS

=over 4

=item C&lt;parent()&gt;

Returns the C&lt;CPANPLUS::Module&gt; object that parented this object.

=item C&lt;status()&gt;

Returns the C&lt;Object::Accessor&gt; object that keeps the status for
this module.

=back

=head1 STATUS ACCESSORS

All accessors can be accessed as follows:
    $build-&gt;status-&gt;ACCESSOR

=over 4

=item C&lt;build_pl ()&gt;

Location of the Build file.
Set to 0 explicitly if something went wrong.

=item C&lt;build ()&gt;

BOOL indicating if the C&lt;Build&gt; command was successful.

=item C&lt;test ()&gt;

BOOL indicating if the C&lt;Build test&gt; command was successful.

=item C&lt;prepared ()&gt;

BOOL indicating if the C&lt;prepare&gt; call exited successfully
This gets set after C&lt;perl Build.PL&gt;

=item C&lt;distdir ()&gt;

Full path to the directory in which the C&lt;prepare&gt; call took place,
set after a call to C&lt;prepare&gt;.

=item C&lt;created ()&gt;

BOOL indicating if the C&lt;create&gt; call exited successfully. This gets
set after C&lt;Build&gt; and C&lt;Build test&gt;.

=item C&lt;installed ()&gt;

BOOL indicating if the module was installed. This gets set after
C&lt;Build install&gt; exits successfully.

=item uninstalled ()

BOOL indicating if the module was uninstalled properly.

=item C&lt;_create_args ()&gt;

Storage of the arguments passed to C&lt;create&gt; for this object. Used
for recursive calls when satisfying prerequisites.

=item C&lt;_install_args ()&gt;

Storage of the arguments passed to C&lt;install&gt; for this object. Used
for recursive calls when satisfying prerequisites.

=back

=cut

=head1 METHODS

=head2 $bool = CPANPLUS::Dist::Build-&gt;format_available();

Returns a boolean indicating whether or not you can use this package
to create and install modules in your environment.

=cut

### check if the format is available ###
sub format_available {
    my $mod = 'Module::Build';
    unless( can_load( modules =&gt; { $mod =&gt; '0.2611' }, nocache =&gt; 1 ) ) {
        error( loc( "You do not have '%1' -- '%2' not available",
                    $mod, __PACKAGE__ ) );
        return;
    }

    return 1;
}


=head2 $bool = $dist-&gt;init();

Sets up the C&lt;CPANPLUS::Dist::Build&gt; object for use.
Effectively creates all the needed status accessors.

Called automatically whenever you create a new C&lt;CPANPLUS::Dist&gt; object.

=cut

sub init {
    my $dist    = shift;
    my $status  = $dist-&gt;status;

    $status-&gt;mk_accessors(qw[build_pl build test created installed uninstalled
                             _create_args _install_args _prepare_args
                             _mb_object _buildflags
                            ]);

    ### just in case 'format_available' didn't get called
    require Module::Build;

    return 1;
}

=pod

=head2 $bool = $dist-&gt;prepare([perl =&gt; '/path/to/perl', buildflags =&gt; 'EXTRA=FLAGS', force =&gt; BOOL, verbose =&gt; BOOL])

C&lt;prepare&gt; prepares a distribution, running C&lt;Build.PL&gt;
and establishing any prerequisites this
distribution has.

The variable C&lt;PERL5_CPANPLUS_IS_EXECUTING&gt; will be set to the full path
of the C&lt;Build.PL&gt; that is being executed. This enables any code inside
the C&lt;Build.PL&gt; to know that it is being installed via CPANPLUS.

After a successful C&lt;prepare&gt; you may call C&lt;create&gt; to create the
distribution, followed by C&lt;install&gt; to actually install it.

Returns true on success and false on failure.

=cut

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-&gt;parent;

    ### we're also the cpan_dist, since we don't need to have anything
    ### prepared from another installer
    $dist    = $self-&gt;status-&gt;dist_cpan if      $self-&gt;status-&gt;dist_cpan;
    $self-&gt;status-&gt;dist_cpan( $dist )   unless  $self-&gt;status-&gt;dist_cpan;

    my $cb   = $self-&gt;parent;
    my $conf = $cb-&gt;configure_object;
    my %hash = @_;

    my $dir;
    unless( $dir = $self-&gt;status-&gt;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           =&gt; {    default =&gt; $conf-&gt;get_conf('force'),
                                    store   =&gt; \$force },
            verbose         =&gt; {    default =&gt; $conf-&gt;get_conf('verbose'),
                                    store   =&gt; \$verbose },
            perl            =&gt; {    default =&gt; $^X, store =&gt; \$perl },
            buildflags      =&gt; {    default =&gt; $conf-&gt;get_conf('buildflags'),
                                    store   =&gt; \$buildflags },
            prereq_target   =&gt; {    default =&gt; '', store =&gt; \$prereq_target },
            prereq_format   =&gt; {    default =&gt; '',
                                    store   =&gt; \$prereq_format },
            prereq_build    =&gt; {    default =&gt; 0, store =&gt; \$prereq_build },
        };

        $args = check( $tmpl, \%hash ) or return;
    }

    return 1 if $dist-&gt;status-&gt;prepared &amp;&amp; !$force;

    $dist-&gt;status-&gt;_prepare_args( $args );

    ### chdir to work directory ###
    my $orig = cwd();
    unless( $cb-&gt;_chdir( dir =&gt; $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-&gt;original_perl5opt;
    #local $ENV{PERL5LIB} = CPANPLUS::inc-&gt;original_perl5lib;
    #local @INC           = CPANPLUS::inc-&gt;original_inc;

    ### this will generate warnings under anything lower than M::B 0.2606
    my @buildflags = $dist-&gt;_buildflags_as_list( $buildflags );
    $dist-&gt;status-&gt;_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-&gt;new('0.85_01');
        if ( version-&gt;new($CPANPLUS::Internals::VERSION) &gt;= $safe_ver )
        {   my $configure_requires = $dist-&gt;find_configure_requires;
            my $ok = $dist-&gt;_resolve_prereqs(
                            format          =&gt; $prereq_format,
                            verbose         =&gt; $verbose,
                            prereqs         =&gt; $configure_requires,
                            target          =&gt; $prereq_target,
                            force           =&gt; $force,
                            prereq_build    =&gt; $prereq_build,
                    );

            unless( $ok ) {

                #### use $dist-&gt;flush to reset the cache ###
                error( loc( "Unable to satisfy '%1' for '%2' " .
                            "-- aborting install",
                            'configure_requires', $self-&gt;module ) );
                $dist-&gt;status-&gt;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 $env = ENV_CPANPLUS_IS_EXECUTING;
        local $ENV{$env} = BUILD_PL-&gt;( $dir );
        my @run_perl    = ( '-e', CPDB_PERL_WRAPPER );
        my $cmd = [$perl, @run_perl, BUILD_PL-&gt;($dir), @buildflags];

        unless ( scalar run(    command =&gt; $cmd,
                                buffer  =&gt; \$prep_output,
                                verbose =&gt; $verbose )
        ) {
            error( loc( "Build.PL failed: %1", $prep_output ) );
            if ( $conf-&gt;get_conf('cpantest') ) {
               $status-&gt;{stage} = 'prepare';
               $status-&gt;{capture} = $prep_output;
            }
            $fail++; last RUN;
        }

        msg( $prep_output, 0 );

        my $prereqs = $self-&gt;status-&gt;prereqs;

        $prereqs ||= $dist-&gt;_find_prereqs( verbose =&gt; $verbose,
                                           dir =&gt; $dir,
                                           perl =&gt; $perl,
                                           buildflags =&gt; $buildflags );

    }

    ### send out test report? ###
    if( $fail and $conf-&gt;get_conf('cpantest') and not $prereq_fail ) {
           $cb-&gt;_send_report(
            module  =&gt; $self,
            failed  =&gt; $fail,
            buffer  =&gt; CPANPLUS::Error-&gt;stack_as_string,
            status  =&gt; $status,
            verbose =&gt; $verbose,
            force   =&gt; $force,
        ) or error(loc("Failed to send test report for '%1'",
                    $self-&gt;module ) );
    }

    unless( $cb-&gt;_chdir( dir =&gt; $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-&gt;status-&gt;distdir( $self-&gt;status-&gt;extract );

    return $dist-&gt;status-&gt;prepared( $fail ? 0 : 1 );
}

sub _find_prereqs {
    my $dist = shift;
    my $self = $dist-&gt;parent;
    my $cb   = $self-&gt;parent;
    my $conf = $cb-&gt;configure_object;
    my %hash = @_;

    my ($verbose, $dir, $buildflags, $perl);
    my $tmpl = {
        verbose =&gt; { default =&gt; $conf-&gt;get_conf('verbose'), store =&gt; \$verbose },
        dir     =&gt; { default =&gt; $self-&gt;status-&gt;extract, store =&gt; \$dir },
        perl    =&gt; { default =&gt; $^X, store =&gt; \$perl },
        buildflags =&gt; { default =&gt; $conf-&gt;get_conf('buildflags'),
                        store   =&gt; \$buildflags },
    };

    my $args = check( $tmpl, \%hash ) or return;

    my $prereqs = {};

    $prereqs = $dist-&gt;find_mymeta_requires()
       if $dist-&gt;can('find_mymeta_requires');

    if ( keys %$prereqs ) {
        # Ugly hack
    }
    else {
      my $safe_ver = version-&gt;new('0.31_03');
      my $content;
      PREREQS: {
        if ( version-&gt;new( $Module::Build::VERSION ) &gt;= $safe_ver and IPC::Cmd-&gt;can_capture_buffer ) {
          my @buildflags = $dist-&gt;_buildflags_as_list( $buildflags );

          # Use the new Build action 'prereq_data'
          my @run_perl    = ( '-e', CPDB_PERL_WRAPPER );

          unless ( scalar run(    command =&gt; [$perl, @run_perl, BUILD-&gt;($dir), 'prereq_data', @buildflags],
                                buffer  =&gt; \$content,
                                verbose =&gt; 0 )
          ) {
            error( loc( "Build 'prereq_data' failed: %1 %2", $!, $content ) );
            #return;
          }
          else {
            last PREREQS;
          }

        }

        my $file = File::Spec-&gt;catfile( $dir, '_build', 'prereqs' );
        return unless -f $file;

        my $fh = FileHandle-&gt;new();

        unless( $fh-&gt;open( $file ) ) {
          error( loc( "Cannot open '%1': %2", $file, $! ) );
          return;
        }

        $content = do { local $/; &lt;$fh&gt; };

      }

      return unless $content;
      my $bphash = eval $content;
      return unless $bphash and ref $bphash eq 'HASH';
      foreach my $type ('requires', 'build_requires') {
        next unless $bphash-&gt;{$type} and ref $bphash-&gt;{$type} eq 'HASH';
        $prereqs-&gt;{$_} = $bphash-&gt;{$type}-&gt;{$_} for keys %{ $bphash-&gt;{$type} };
      }
    }

    {
      delete $prereqs-&gt;{'perl'}
         unless version-&gt;new($CPANPLUS::Internals::VERSION)
             &gt;= version-&gt;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-&gt;_callbacks-&gt;can('filter_prereqs')
                    ? $cb-&gt;_callbacks-&gt;filter_prereqs-&gt;( $cb, $prereqs )
                    : $prereqs;

    $self-&gt;status-&gt;prereqs( $href );

    ### make sure it's not the same ref
    return { %$href };
}

=pod

=head2 $dist-&gt;create([perl =&gt; '/path/to/perl', buildflags =&gt; 'EXTRA=FLAGS', prereq_target =&gt; TARGET, force =&gt; BOOL, verbose =&gt; BOOL, skiptest =&gt; BOOL])

C&lt;create&gt; preps a distribution for installation. This means it will
run C&lt;Build&gt; and C&lt;Build test&gt;.
This will also satisfy any prerequisites the module may have.

If you set C&lt;skiptest&gt; to true, it will skip the C&lt;Build test&gt; stage.
If you set C&lt;force&gt; to true, it will go over all the stages of the
C&lt;Build&gt; process again, ignoring any previously cached results. It
will also ignore a bad return value from C&lt;Build test&gt; and still allow
the operation to return true.

Returns true on success and false on failure.

You may then call C&lt;&lt; $dist-&gt;install &gt;&gt; on the object to actually
install it.

=cut

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-&gt;parent;

    ### we're also the cpan_dist, since we don't need to have anything
    ### prepared from another installer
    $dist    = $self-&gt;status-&gt;dist_cpan if      $self-&gt;status-&gt;dist_cpan;
    $self-&gt;status-&gt;dist_cpan( $dist )   unless  $self-&gt;status-&gt;dist_cpan;

    my $cb   = $self-&gt;parent;
    my $conf = $cb-&gt;configure_object;
    my %hash = @_;

    my $dir;
    unless( $dir = $self-&gt;status-&gt;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           =&gt; {    default =&gt; $conf-&gt;get_conf('force'),
                                    store   =&gt; \$force },
            verbose         =&gt; {    default =&gt; $conf-&gt;get_conf('verbose'),
                                    store   =&gt; \$verbose },
            perl            =&gt; {    default =&gt; $^X, store =&gt; \$perl },
            buildflags      =&gt; {    default =&gt; $conf-&gt;get_conf('buildflags'),
                                    store   =&gt; \$buildflags },
            skiptest        =&gt; {    default =&gt; $conf-&gt;get_conf('skiptest'),
                                    store   =&gt; \$skiptest },
            prereq_target   =&gt; {    default =&gt; '', store =&gt; \$prereq_target },
            ### don't set the default format to 'build' -- that is wrong!
            prereq_format   =&gt; {    #default =&gt; $self-&gt;status-&gt;installer_type,
                                    default =&gt; '',
                                    store   =&gt; \$prereq_format },
            prereq_build    =&gt; {    default =&gt; 0, store =&gt; \$prereq_build },
        };

        $args = check( $tmpl, \%hash ) or return;
    }

    # restore the state as we have created this already.
    if ( $dist-&gt;status-&gt;created &amp;&amp; !$force ) {
        ### add this directory to your lib ###
        $self-&gt;add_to_includepath();
        return 1;
    }

    $dist-&gt;status-&gt;_create_args( $args );

    ### is this dist prepared?
    unless( $dist-&gt;status-&gt;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-&gt;_chdir( dir =&gt; $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-&gt;original_perl5opt;
    #local $ENV{PERL5LIB} = CPANPLUS::inc-&gt;original_perl5lib;
    #local @INC           = CPANPLUS::inc-&gt;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-&gt;best_path_to_module_build;
    #    unshift @INC, $lib if $lib;
    #}
    unshift @INC, $self-&gt;best_path_to_module_build
                if $self-&gt;best_path_to_module_build;

    ### this will generate warnings under anything lower than M::B 0.2606
    my @buildflags = $dist-&gt;_buildflags_as_list( $buildflags );
    $dist-&gt;status-&gt;_buildflags( $buildflags );

    my $fail; my $prereq_fail; my $test_fail;
    my $status = { };
    RUN: {

        my @run_perl    = ( '-e', CPDB_PERL_WRAPPER );

        ### this will set the directory back to the start
        ### dir, so we must chdir /again/
        my $ok = $dist-&gt;_resolve_prereqs(
                        force           =&gt; $force,
                        format          =&gt; $prereq_format,
                        verbose         =&gt; $verbose,
                        prereqs         =&gt; $self-&gt;status-&gt;prereqs,
                        target          =&gt; $prereq_target,
                        prereq_build    =&gt; $prereq_build,
                    );

        unless( $cb-&gt;_chdir( dir =&gt; $dir ) ) {
            error( loc( "Could not chdir to build directory '%1'", $dir ) );
            return;
        }

        unless( $ok ) {
            #### use $dist-&gt;flush to reset the cache ###
            error( loc( "Unable to satisfy prerequisites for '%1' " .
                        "-- aborting install", $self-&gt;module ) );
            $dist-&gt;status-&gt;build(0);
            $fail++; $prereq_fail++;
            last RUN;
        }

        my ($captured, $cmd);
        if ( ON_VMS ) {
            $cmd = [$perl, BUILD-&gt;($dir), @buildflags];
        }
        else {
            $cmd = [$perl, @run_perl, BUILD-&gt;($dir), @buildflags];
        }

        unless ( scalar run(    command =&gt; $cmd,
                                buffer  =&gt; \$captured,
                                verbose =&gt; $verbose )
        ) {
            error( loc( "MAKE failed:\n%1", $captured ) );
            $dist-&gt;status-&gt;build(0);
            if ( $conf-&gt;get_conf('cpantest') ) {
               $status-&gt;{stage} = 'build';
               $status-&gt;{capture} = $captured;
            }
            $fail++; last RUN;
        }

        msg( $captured, 0 );

        $dist-&gt;status-&gt;build(1);

        ### add this directory to your lib ###
        $self-&gt;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-&gt;($dir), "test", @buildflags];
            }
            else {
                $cmd     = [$perl, @run_perl, BUILD-&gt;($dir), "test", @buildflags];
            }
            unless ( scalar run(    command =&gt; $cmd,
                                    buffer  =&gt; \$test_output,
                                    verbose =&gt; $verbose )
            ) {
                error( loc( "MAKE TEST failed:\n%1 ", $test_output ), ( $verbose ? 0 : 1 ) );

                ### mark specifically *test* failure.. so we dont
                ### send success on force...
                $test_fail++;

                if( !$force and !$cb-&gt;_callbacks-&gt;proceed_on_test_failure-&gt;(
                                      $self, $@ )
                ) {
                    $dist-&gt;status-&gt;test(0);
                    if ( $conf-&gt;get_conf('cpantest') ) {
                      $status-&gt;{stage} = 'test';
                      $status-&gt;{capture} = $test_output;
                    }
                    $fail++; last RUN;
                }

            }
            else {
                msg( loc( "MAKE TEST passed:\n%1", $test_output ), 0 );
                $dist-&gt;status-&gt;test(1);
                if ( $conf-&gt;get_conf('cpantest') ) {
                   $status-&gt;{stage} = 'test';
                   $status-&gt;{capture} = $test_output;
                }
            }
        }
        else {
            msg(loc("Tests skipped"), $verbose);
        }
    }

    unless( $cb-&gt;_chdir( dir =&gt; $orig ) ) {
        error( loc( "Could not chdir back to start dir '%1'", $orig ) );
    }

    ### send out test report? ###
    if( $conf-&gt;get_conf('cpantest') and not $prereq_fail ) {
        $cb-&gt;_send_report(
            module          =&gt; $self,
            failed          =&gt; $test_fail || $fail,
            buffer          =&gt; CPANPLUS::Error-&gt;stack_as_string,
            status          =&gt; $status,
            verbose         =&gt; $verbose,
            force           =&gt; $force,
            tests_skipped   =&gt; $skiptest,
        ) or error(loc("Failed to send test report for '%1'",
                    $self-&gt;module ) );
    }

    return $dist-&gt;status-&gt;created( $fail ? 0 : 1 );
}

=head2 $dist-&gt;install([verbose =&gt; BOOL, perl =&gt; /path/to/perl])

Actually installs the created dist.

Returns true on success and false on failure.

=cut

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-&gt;parent;

    ### we're also the cpan_dist, since we don't need to have anything
    ### prepared from another installer
    $dist    = $self-&gt;status-&gt;dist_cpan if $self-&gt;status-&gt;dist_cpan;

    my $cb   = $self-&gt;parent;
    my $conf = $cb-&gt;configure_object;
    my %hash = @_;


    my $verbose; my $perl; my $force; my $buildflags;
    {   local $Params::Check::ALLOW_UNKNOWN = 1;
        my $tmpl = {
            verbose =&gt; { default =&gt; $conf-&gt;get_conf('verbose'),
                         store   =&gt; \$verbose },
            force   =&gt; { default =&gt; $conf-&gt;get_conf('force'),
                         store   =&gt; \$force },
            buildflags =&gt; { default =&gt; $conf-&gt;get_conf('buildflags'),
                            store   =&gt; \$buildflags },
            perl    =&gt; { default =&gt; $^X, store   =&gt; \$perl },
        };

        my $args = check( $tmpl, \%hash ) or return;
        $dist-&gt;status-&gt;_install_args( $args );
    }

    my $dir;
    unless( $dir = $self-&gt;status-&gt;extract ) {
        error( loc( "No dir found to operate on!" ) );
        return;
    }

    my $orig = cwd();

    unless( $cb-&gt;_chdir( dir =&gt; $dir ) ) {
        error( loc( "Could not chdir to build directory '%1'", $dir ) );
        return;
    }

    ### value set and false -- means failure ###
    if( defined $self-&gt;status-&gt;installed &amp;&amp;
        !$self-&gt;status-&gt;installed &amp;&amp; !$force
    ) {
        error( loc( "Module '%1' has failed to install before this session " .
                    "-- aborting install", $self-&gt;module ) );
        return;
    }

    my $fail;
    my @buildflags = $dist-&gt;_buildflags_as_list( $buildflags );
    my @run_perl    = ( '-e', CPDB_PERL_WRAPPER );

    ### 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( $&gt; ) {

        ### 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-&gt;($dir), "install", @buildflags];
        }
        else {
            $cmd     = [$perl, @run_perl, BUILD-&gt;($dir), "install", @buildflags];
        }

        ### Detect local::lib type behaviour. Do not use 'sudo' in these cases
        my $sudo    = $conf-&gt;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 =&gt; $cmd,
                            buffer  =&gt; \$buffer,
                            verbose =&gt; $verbose )
        ) {
            error(loc("Could not run '%1': %2", 'Build install', $buffer));
            $fail++;
        }
    } else {
        my ($install_output, $cmd);
        if ( ON_VMS ) {
            $cmd     = [$perl, BUILD-&gt;($dir), "install", @buildflags];
        }
        else {
            $cmd     = [$perl, @run_perl, BUILD-&gt;($dir), "install", @buildflags];
        }
        unless( scalar run( command =&gt; $cmd,
                            buffer  =&gt; \$install_output,
                            verbose =&gt; $verbose )
        ) {
            error(loc("Could not run '%1': %2", 'Build install', $install_output));
            $fail++;
        }
        else {
            msg( $install_output, 0 );
        }
    }


    unless( $cb-&gt;_chdir( dir =&gt; $orig ) ) {
        error( loc( "Could not chdir back to start dir '%1'", $orig ) );
    }

    return $dist-&gt;status-&gt;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-&gt;split_like_shell($flags);
}

=head1 AUTHOR

Originally by Jos Boumans E&lt;lt&gt;kane@cpan.orgE&lt;gt&gt;.  Brought to working
condition by Ken Williams E&lt;lt&gt;kwilliams@cpan.orgE&lt;gt&gt;.

Other hackery and currently maintained by Chris C&lt;BinGOs&gt; Williams ( no relation ). E&lt;lt&gt;bingos@cpan.orgE&lt;gt&gt;.

=head1 LICENSE

The CPAN++ interface (of which this module is a part of) is
copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E&lt;lt&gt;kane@cpan.orgE&lt;gt&gt;.
All rights reserved.

This library is free software;
you may redistribute and/or modify it under the same
terms as Perl itself.

=cut

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:

</pre></body></html>