The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

### Setup a "Good" Copy of @INC to use at runtime, and a
### temporary one to use at bootstrap time.
BEGIN {
    use strict;
    use warnings;

    use Config;
    use FindBin;
    use File::Spec;
    use File::Spec::Unix;

    use vars qw[@RUN_TIME_INC $LIB_DIR $BUNDLE_DIR $BASE $PRIV_LIB];
    $LIB_DIR        = File::Spec->catdir( $FindBin::Bin, qw[.. lib] );
    $BUNDLE_DIR     = File::Spec->catdir( $FindBin::Bin, qw[.. inc bundle] );

    ### must set the PERL5LIB env var here as well, as some
    ### code in CPANPLUS resets it between iterations. So we
    ### have to set our 'final' perl5lib before loading any
    ### CPANPLUS code. The constants code is 'safe' but better
    ### safe than sorry. So duplicating the 'constants' behaviour
    ### of DOT_CPANPLUS
    # use CPANPLUS::Internals::Constants;
    my $who     = getlogin || getpwuid($<) || $<;
    $BASE       = File::Spec->catfile(
                            $FindBin::Bin, '..', '.cpanplus', $who);
    $PRIV_LIB   = File::Spec->catfile( $BASE, 'lib' );

    @RUN_TIME_INC   = ($PRIV_LIB, @INC);
    unshift @INC, $LIB_DIR, $BUNDLE_DIR;

    ### set it in the environment too, for when we shell out
    ### (like at 'perl makefile.pl' time.
    $ENV{'PERL5LIB'} = join $Config{'path_sep'}, grep { defined }
                        $PRIV_LIB,              # to find the boxed config
                        #$LIB_DIR,               # the CPANPLUS libs
                        $ENV{'PERL5LIB'};       # original PERL5LIB

}

use FindBin;
use File::Find                          qw[find];
use CPANPLUS::Error;
use CPANPLUS::Configure;
use CPANPLUS::Internals::Constants;
use CPANPLUS::Internals::Utils;

### now, load in all the .pms from the bundle dir, so they're in
### memory. Skip the ones already loaded, and ignore failed requires.
### XXX this section *somehow* makes 'system(cmd.exe)' return immediately
### on win32, when run from cpanp-boxed (regular cpanp is fine). Probably
### need to load only a subsection of these modules, for safety sake.
{   for my $dir ( ($BUNDLE_DIR, $LIB_DIR) ) {
        my $base_re = quotemeta $dir;

        find( sub { my $file = $File::Find::name;
                return unless -e $file && -f _ && -s _;

                return if $file =~ /\._/;   # osx temp files

                ### strip base dir. Might not end in / (or local
                ### dir delimiter), so remove that if needed too
                $file =~ s/^$base_re(\W)?//;

                ### file already loaded.
                return if $INC{$file};

                ### construct pm name and strip suffix
                my $unixfile = File::Spec::Unix->catfile(
                                    File::Spec->splitdir( $file )
                                );
                my $pm       = join '::', File::Spec->splitdir( $file );
                $pm =~ s/\.pm$//i or return;    # not a .pm file

                ### make sure we *DONT* load these blatantly
                #return if $pm =~ /(?:IPC::Run::)|(?:File::Spec::)/;

                eval "require $pm ; 1";

                ### if the require *FAILS* it's still added to %INC
                ### in some cases (mostly if a require in the required
                ### file fails or some such.. so remove it from our %INC!
                if( $@ ) {
                    push @failures, $unixfile;

                    ### dont enable warnings -- some modules
                    ### are OS specific. Uncomment only for debug
                    ### reasons
                    #warn $@;


                }
            }, $dir );
    }

    ### delete AFTER we've loaded everything!
    delete $INC{$_} for @failures;

    ### set @INC back to our non-bundled version
    @INC = @RUN_TIME_INC;
}


### setup the configuration
my $ConfObj     = CPANPLUS::Configure->new;
my $Config      = CONFIG_BOXED;
my $Util        = 'CPANPLUS::Internals::Utils';
my $ConfigFile  = $ConfObj->_config_pm_to_file( $Config => $PRIV_LIB );

### setup the environment if needed
{   ### no base dir even, set it up
    unless( IS_DIR->( $BASE ) ) {
        $Util->_mkdir( dir => $BASE ) or die CPANPLUS::Error->stack_as_string;
    }

    ### no config file exists yet, so we create it
    unless( -e $ConfigFile ) {
        ### alter what needs changing
        $ConfObj->set_conf( base    => $BASE );     # new base dir
        $ConfObj->set_conf( verbose => 1     );     # be verbose
        $ConfObj->set_conf( prereqs => 1     );     # install prereqs
        $ConfObj->save(     $Config => $PRIV_LIB ); # save the pm in that dir
    }
}

print qq[
===

Your boxed CPANPLUS install is setup to use:
  Basedir:  $BASE
  Config:   $ConfigFile

If you wish to save your boxed configuration, please type:
  s save boxed

You can bootstrap your CPANPLUS by running:
  s selfupdate dependencies
  s selfupdate enabled_features

===
    \n
];

### set the @INC to a runtime version, so our bundled modules
### are 'hidden' from probing, but loaded already for 'use' and
### 'require' statements

{   $Module::Load::Conditional::CHECK_INC_HASH = 1;
    do File::Spec->catfile( $FindBin::Bin, 'cpanp' ) or die "$! $@";
}