package local::lib;
-use 5.8.1; # probably works with earlier versions but I'm not supporting them
- # (patches would, of course, be welcome)
+use 5.006;
use File::Spec ();
-use File::Path ();
-use Carp ();
use Config;
-our $VERSION = '1.000000'; # 1.0.0
+our $VERSION = '1.008026'; # 1.8.26
+$VERSION = eval $VERSION;
sub import {
+ my ($class, @args) = @_;
+
+ my @steps;
+ my %opts;
+
+ while (@args) {
+ my $arg = shift @args;
+ # check for lethal dash first to stop processing before causing problems
+ # the fancy dash is U+2212 or \xE2\x88\x92
+ if ($arg =~ /\xE2\x88\x92/ or $arg =~ /−/) {
+ die <<'DEATH';
+WHOA THERE! It looks like you've got some fancy dashes in your commandline!
+These are *not* the traditional -- dashes that software recognizes. You
+probably got these by copy-pasting from the perldoc for this module as
+rendered by a UTF8-capable formatter. This most typically happens on an OS X
+terminal, but can happen elsewhere too. Please try again after replacing the
+dashes with normal minus signs.
+DEATH
+ }
+ elsif ($arg eq '--self-contained') {
+ die "FATAL: The local::lib --self-contained flag has never worked reliably and the original author, Mark Stosberg, was unable or unwilling to maintain it. As such, this flag has been removed from the local::lib codebase in order to prevent misunderstandings and potentially broken builds. The local::lib authors recommend that you look at the lib::core::only module shipped with this distribution in order to create a more robust environment that is equivalent to what --self-contained provided (although quite possibly not what you originally thought it provided due to the poor quality of the documentation, for which we apologise).\n";
+ }
+ elsif( $arg =~ /^--deactivate(?:=(.*))?$/ ) {
+ my $path = defined $1 ? $1 : shift @args;
+ push @steps, ['deactivate', $path];
+ }
+ elsif ( $arg eq '--deactivate-all' ) {
+ push @steps, ['deactivate_all'];
+ }
+ elsif ( $arg =~ /^--shelltype(?:=(.*))?$/ ) {
+ my $shell = defined $1 ? $1 : shift @args;
+ $opts{shelltype} = $shell;
+ }
+ elsif ( $arg eq '--no-create' ) {
+ $opts{no_create} = 1;
+ }
+ elsif ( $arg =~ /^--/ ) {
+ die "Unknown import argument: $arg";
+ }
+ else {
+ push @steps, ['activate', $arg];
+ }
+ }
+ if (!@steps) {
+ push @steps, ['activate', undef];
+ }
+
+ my $self = $class->new(%opts);
+
+ for (@steps) {
+ my ($method, @args) = @$_;
+ $self = $self->$method(@args);
+ }
+
+ if ($0 eq '-') {
+ $self->print_environment_vars_for;
+ exit 0;
+ }
+ else {
+ $self->setup_local_lib_for;
+ }
+}
+
+sub new {
+ my $class = shift;
+ bless {@_}, $class;
+}
+
+sub clone {
+ my $self = shift;
+ bless {%$self, @_}, ref $self;
+}
+
+sub inc { $_[0]->{inc} ||= \@INC }
+sub libs { $_[0]->{libs} ||= [ \'PERL5LIB' ] }
+sub bins { $_[0]->{bins} ||= [ \'PATH' ] }
+sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
+sub extra { $_[0]->{extra} ||= {} }
+sub shelltype { $_[0]->{shelltype} ||= $_[0]->guess_shelltype }
+sub no_create { $_[0]->{no_create} }
+
+my $_archname = $Config{archname};
+my $_version = $Config{version};
+my @_inc_version_list = reverse split / /, $Config{inc_version_list};
+my $_path_sep = $Config{path_sep};
+
+sub _as_list {
+ my $list = shift;
+ grep length, map {
+ !(ref $_ && ref $_ eq 'SCALAR') ? $_ : (
+ defined $ENV{$$_} ? split(/\Q$_path_sep/, $ENV{$$_})
+ : ()
+ )
+ } ref $list ? @$list : $list;
+}
+sub _remove_from {
+ my ($list, @remove) = @_;
+ return @$list
+ if !@remove;
+ my %remove = map { $_ => 1 } @remove;
+ grep !$remove{$_}, _as_list($list);
+}
+
+my @_lib_subdirs = (
+ [$_version, $_archname],
+ [$_version],
+ [$_archname],
+ (@_inc_version_list ? \@_inc_version_list : ()),
+ [],
+);
+
+sub install_base_bin_path {
+ my ($class, $path) = @_;
+ return File::Spec->catdir($path, 'bin');
+}
+sub install_base_perl_path {
my ($class, $path) = @_;
- $path = $class->resolve_path($path);
- $class->setup_local_lib_for($path);
+ return File::Spec->catdir($path, 'lib', 'perl5');
+}
+sub install_base_arch_path {
+ my ($class, $path) = @_;
+ File::Spec->catdir($class->install_base_perl_path($path), $_archname);
+}
+
+sub lib_paths_for {
+ my ($class, $path) = @_;
+ my $base = $class->install_base_perl_path($path);
+ return map { File::Spec->catdir($base, @$_) } @_lib_subdirs;
+}
+
+sub _mm_escape_path {
+ my $path = shift;
+ $path =~ s/\\/\\\\\\\\/g;
+ if ($path =~ s/ /\\ /g) {
+ $path = qq{"\\"$path\\""};
+ }
+ return $path;
+}
+
+sub _mb_escape_path {
+ my $path = shift;
+ $path =~ s/\\/\\\\/g;
+ return qq{"$path"};
+}
+
+sub installer_options_for {
+ my ($class, $path) = @_;
+ return {
+ PERL_MM_OPT => defined $path ? "INSTALL_BASE="._mm_escape_path($path) : undef,
+ PERL_MB_OPT => defined $path ? "--install_base "._mb_escape_path($path) : undef,
+ };
+}
+
+sub active_paths {
+ my ($self) = @_;
+ $self = ref $self ? $self : $self->new;
+
+ return grep {
+ # screen out entries that aren't actually reflected in @INC
+ my $active_ll = $self->install_base_perl_path($_);
+ grep { $_ eq $active_ll } @{$self->inc};
+ } _as_list($self->roots);
+}
+
+
+sub deactivate {
+ my ($self, $path) = @_;
+ $self = $self->new unless ref $self;
+ $path = $self->resolve_path($path);
+ $path = $self->normalize_path($path);
+
+ my @active_lls = $self->active_paths;
+
+ if (!grep { $_ eq $path } @active_lls) {
+ warn "Tried to deactivate inactive local::lib '$path'\n";
+ return $self;
+ }
+
+ my %args = (
+ bins => [ _remove_from($self->bins, $self->install_base_bin_path($path)) ],
+ libs => [ _remove_from($self->libs, $self->install_base_perl_path($path)) ],
+ inc => [ _remove_from($self->inc, $self->lib_paths_for($path)) ],
+ roots => [ _remove_from($self->roots, $path) ],
+ );
+
+ $args{extra} = $self->installer_options_for($args{roots}[0]);
+
+ $self->clone(%args);
+}
+
+sub deactivate_all {
+ my ($self) = @_;
+ $self = $self->new unless ref $self;
+
+ my @active_lls = $self->active_paths;
+
+ my %args;
+ if (@active_lls) {
+ %args = (
+ bins => [ _remove_from($self->bins,
+ map $self->install_base_bin_path($_), @active_lls) ],
+ libs => [ _remove_from($self->libs,
+ map $self->install_base_perl_path($_), @active_lls) ],
+ inc => [ _remove_from($self->inc,
+ map $self->lib_paths_for($_), @active_lls) ],
+ roots => [ _remove_from($self->roots, @active_lls) ],
+ );
+ }
+
+ $args{extra} = $self->installer_options_for(undef);
+
+ $self->clone(%args);
+}
+
+sub activate {
+ my ($self, $path) = @_;
+ $self = $self->new unless ref $self;
+ $path = $self->resolve_path($path);
+ $self->ensure_dir_structure_for($path)
+ unless $self->no_create;
+
+ $path = $self->normalize_path($path);
+
+ my @active_lls = $self->active_paths;
+
+ if (grep { $_ eq $path } @active_lls[1 .. $#active_lls]) {
+ $self = $self->deactivate($path);
+ }
+
+ my %args;
+ if (!@active_lls || $active_lls[0] ne $path) {
+ %args = (
+ bins => [ $self->install_base_bin_path($path), @{$self->bins} ],
+ libs => [ $self->install_base_perl_path($path), @{$self->libs} ],
+ inc => [ $self->lib_paths_for($path), @{$self->inc} ],
+ roots => [ $path, @{$self->roots} ],
+ );
+ }
+
+ $args{extra} = $self->installer_options_for($path);
+
+ $self->clone(%args);
+}
+
+sub normalize_path {
+ my ($self, $path) = @_;
+ $path = ( Win32::GetShortPathName($path) || $path )
+ if $^O eq 'MSWin32';
+ return $path;
+}
+
+sub _legacy {
+ my ($self, $path) = @_;
+ $self = $self->new unless ref $self;
+ if (defined $path) {
+ $self = $self->activate($path);
+ }
+ $self;
+}
+
+sub build_environment_vars_for {
+ my ($self) = _legacy(@_);
+ (
+ PATH => join($_path_sep, _as_list($self->bins)),
+ PERL5LIB => join($_path_sep, _as_list($self->libs)),
+ PERL_LOCAL_LIB_ROOT => join($_path_sep, _as_list($self->roots)),
+ %{$self->extra},
+ );
+}
+
+sub setup_local_lib_for {
+ my ($self) = _legacy(@_);
+ $self->setup_env_hash_for;
+ @INC = @{$self->inc};
+}
+
+sub setup_env_hash_for {
+ my $self = shift;
+ my %env = $self->build_environment_vars_for(@_);
+ for my $key (keys %env) {
+ if (defined $env{$key}) {
+ $ENV{$key} = $env{$key};
+ }
+ else {
+ delete $ENV{$key};
+ }
+ }
+}
+
+sub print_environment_vars_for {
+ my $self = shift;
+ print $self->environment_vars_string_for(@_);
+}
+
+sub environment_vars_string_for {
+ my $self = _legacy(@_);
+
+ my $build_method = 'build_' . $self->shelltype . '_env_declaration';
+
+ my @envs = (
+ PATH => $self->bins,
+ PERL5LIB => $self->libs,
+ PERL_LOCAL_LIB_ROOT => $self->roots,
+ %{$self->extra},
+ );
+ my $out = '';
+ while (@envs) {
+ my ($name, $value) = (shift(@envs), shift(@envs));
+ if (
+ ref $value
+ && @$value == 1
+ && ref $value->[0]
+ && ref $value->[0] eq 'SCALAR'
+ && ${$value->[0]} eq $name) {
+ next;
+ }
+ if (
+ !ref $value
+ and defined $value
+ ? (defined $ENV{$name} && $value eq $ENV{$name})
+ : !defined $ENV{$name}
+ ) {
+ next;
+ }
+ $out .= $self->$build_method($name, $value);
+ }
+ my $wrap_method = 'wrap_' . $self->shelltype . '_output';
+ if ($self->can($wrap_method)) {
+ return $self->$wrap_method($out);
+ }
+ return $out;
+}
+
+sub build_bourne_env_declaration {
+ my ($class, $name, $args) = @_;
+ my $value = $class->_interpolate($args);
+ my $joined;
+ for (@$value) {
+ if (!defined $joined) {
+ $joined = $_;
+ }
+ elsif ($_ eq "\$$name") {
+ $joined .= "\${$name+$Config{path_sep}}$_";
+ }
+ else {
+ $joined .= "$Config{path_sep}$_";
+ }
+ }
+ defined $value
+ ? qq{export ${name}="$joined";\n}
+ : qq{unset ${name};\n};
+}
+sub build_csh_env_declaration {
+ my ($class, $name, $args) = @_;
+ my ($value, @vars) = $class->_interpolate($args, undef, undef, '"', qq{"\\"});
+
+ my $out = '';
+ if (@vars) {
+ $out = qq{if \$?$name };
+ }
+ $out .= defined $value ? qq{setenv $name "}.join($Config{path_sep},@$value).qq{";\n} : qq{unsetenv $name;\n};
+ if (@vars) {
+ my $no_var = $class->_interpolate([ grep { !ref } @$args ], undef, undef, '"', qq{"\\"});
+ if (defined $no_var) {
+ $out .= qq{if ! \$?$name setenv $name "}.join($Config{path_sep},@$no_var).qq{";\n};
+ }
+ }
+ $out;
+}
+sub build_cmd_env_declaration {
+ my ($class, $name, $args) = @_;
+ my $value = $class->_interpolate($args, '%', '%', qr([()!^"<>&|]), '^');
+ defined $value
+ ? qq{\@set $name=}.join($Config{path_sep},@$value).qq{\n}
+ : qq{\@set $name=\n};
+}
+sub build_powershell_env_declaration {
+ my ($class, $name, $args) = @_;
+ my $value = $class->_interpolate($args, '$env:', '', '"', '`');
+ defined $value
+ ? qq{\$env:$name = "}.join($Config{path_sep},@$value).qq{";\n}
+ : "Remove-Item Env:\\$name;\n";
+}
+sub wrap_powershell_output {
+ my ($class, $out) = @_;
+ return $out || " \n";
+}
+
+
+sub _interpolate {
+ my ($class, $args, $start, $end, $escape, $escape_char) = @_;
+ return
+ unless defined $args;
+ $args = [ $args ]
+ unless ref $args;
+ return
+ unless @$args;
+ $start = '$' unless defined $start;
+ $end = '' unless defined $end;
+ $escape = '"' unless defined $escape;
+ $escape_char = "\\" unless defined $escape_char;
+ my @vars;
+ my $string = [ map {
+ if (ref $_ && ref $_ eq 'SCALAR') {
+ push @vars, $$_;
+ $start.$$_.$end;
+ }
+ else {
+ my $str = $_;
+ $str =~ s/($escape)/$escape_char$1/g;
+ $str;
+ }
+ } @$args ];
+ return wantarray ? ($string, @vars) : $string;
}
sub pipeline;
}
}
-=for test pipeline
+=begin testing
+
+#:: test pipeline
package local::lib;
{ package Foo; sub foo { -$_[1] } sub bar { $_[1]+2 } sub baz { $_[1]+3 } }
-my $foo = bless({}, 'Foo');
+my $foo = bless({}, 'Foo');
Test::More::ok($foo->${pipeline qw(foo bar baz)}(10) == -15);
+=end testing
+
=cut
sub resolve_path {
my ($class, $path) = @_;
- $class->${pipeline qw(
+
+ $path = $class->${pipeline qw(
resolve_relative_path
resolve_home_path
resolve_empty_path
)}($path);
+
+ $path;
}
sub resolve_empty_path {
}
}
-=for test classmethod setup
+=begin testing
+
+#:: test classmethod setup
my $c = 'local::lib';
-=cut
+=end testing
+
+=begin testing
-=for test classmethod
+#:: test classmethod
is($c->resolve_empty_path, '~/perl5');
is($c->resolve_empty_path('foo'), 'foo');
+=end testing
+
=cut
sub resolve_home_path {
my ($class, $path) = @_;
return $path unless ($path =~ /^~/);
my ($user) = ($path =~ /^~([^\/]+)/); # can assume ^~ so undef for 'us'
- my $tried_file_homedir;
my $homedir = do {
- if (eval { require File::HomeDir } && $File::HomeDir::VERSION >= 0.65) {
- $tried_file_homedir = 1;
- if (defined $user) {
- File::HomeDir->users_home($user);
- } else {
- File::HomeDir->my_homedir;
- }
- } else {
- if (defined $user) {
- (getpwnam $user)[7];
- } else {
- if (defined $ENV{HOME}) {
- $ENV{HOME};
- } else {
- (getpwuid $<)[7];
- }
- }
+ if (!defined $user && defined $ENV{HOME}) {
+ $ENV{HOME}
+ }
+ else {
+ require File::Glob;
+ File::Glob::bsd_glob("~$user", File::Glob::GLOB_TILDE());
}
};
unless (defined $homedir) {
+ require Carp;
Carp::croak(
"Couldn't resolve homedir for "
.(defined $user ? $user : 'current user')
- .($tried_file_homedir ? '' : ' - consider installing File::HomeDir')
);
}
$path =~ s/^~[^\/]*/$homedir/;
sub resolve_relative_path {
my ($class, $path) = @_;
- File::Spec->rel2abs($path);
+ $path = File::Spec->rel2abs($path);
}
-=for test classmethod
+=begin testing
+
+#:: test classmethod
local *File::Spec::rel2abs = sub { shift; 'FOO'.shift; };
is($c->resolve_relative_path('bar'),'FOObar');
-=cut
-
-sub setup_local_lib_for {
- my ($class, $path) = @_;
- $class->ensure_dir_structure_for($path);
- if ($0 eq '-') {
- $class->print_environment_vars_for($path);
- exit 0;
- } else {
- $class->setup_env_hash_for($path);
- }
-}
-
-sub modulebuildrc_path {
- my ($class, $path) = @_;
- File::Spec->catfile($path, '.modulebuildrc');
-}
-
-sub install_base_bin_path {
- my ($class, $path) = @_;
- File::Spec->catdir($path, 'bin');
-}
+=end testing
-sub install_base_perl_path {
- my ($class, $path) = @_;
- File::Spec->catdir($path, 'lib', 'perl5');
-}
-
-sub install_base_arch_path {
- my ($class, $path) = @_;
- File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
-}
+=cut
sub ensure_dir_structure_for {
my ($class, $path) = @_;
unless (-d $path) {
warn "Attempting to create directory ${path}\n";
}
- File::Path::mkpath($path);
- my $modulebuildrc_path = $class->modulebuildrc_path($path);
- if (-e $modulebuildrc_path) {
- unless (-f _) {
- Carp::croak("${modulebuildrc_path} exists but is not a plain file");
- }
- } else {
- warn "Attempting to create file ${modulebuildrc_path}\n";
- open MODULEBUILDRC, '>', $modulebuildrc_path
- || Carp::croak("Couldn't open ${modulebuildrc_path} for writing: $!");
- print MODULEBUILDRC qq{--install_base ${path}\n}
- || Carp::croak("Couldn't write line to ${modulebuildrc_path}: $!");
- close MODULEBUILDRC
- || Carp::croak("Couldn't close file ${modulebuildrc_path}: $@");
+ require File::Basename;
+ my @dirs;
+ while(!-d $path) {
+ push @dirs, $path;
+ $path = File::Basename::dirname($path);
}
+ mkdir $_ for reverse @dirs;
+ return;
}
-sub INTERPOLATE_PATH () { 1 }
-sub LITERAL_PATH () { 0 }
+=begin testing
-sub print_environment_vars_for {
- my ($class, $path) = @_;
- my @envs = $class->build_environment_vars_for($path, LITERAL_PATH);
- my $out = '';
- while (@envs) {
- my ($name, $value) = (shift(@envs), shift(@envs));
- $value =~ s/(\\")/\\$1/g;
- $out .= qq{export ${name}="${value}"\n};
- }
- print $out;
-}
-
-sub setup_env_hash_for {
- my ($class, $path) = @_;
- my %envs = $class->build_environment_vars_for($path, INTERPOLATE_PATH);
- @ENV{keys %envs} = values %envs;
-}
-
-sub build_environment_vars_for {
- my ($class, $path, $interpolate) = @_;
- return (
- MODULEBUILDRC => $class->modulebuildrc_path($path),
- PERL_MM_OPT => "INSTALL_BASE=${path}",
- PERL5LIB => join(':',
- $class->install_base_perl_path($path),
- $class->install_base_arch_path($path),
- ),
- PATH => join(':',
- $class->install_base_bin_path($path),
- ($interpolate == INTERPOLATE_PATH
- ? $ENV{PATH}
- : '$PATH')
- ),
- )
-}
-
-=for test classmethod
+#:: test classmethod
File::Path::rmtree('t/var/splat');
ok(-d 't/var/splat');
-ok(-f 't/var/splat/.modulebuildrc');
+=end testing
+
+=cut
+
+sub guess_shelltype {
+ my $shellbin
+ = defined $ENV{SHELL}
+ ? (File::Spec->splitpath($ENV{SHELL}))[-1]
+ : ( $^O eq 'MSWin32' && exists $ENV{'!EXITCODE'} )
+ ? 'bash'
+ : ( $^O eq 'MSWin32' && $ENV{PROMPT} && $ENV{COMSPEC} )
+ ? (File::Spec->splitpath($ENV{COMSPEC}))[-1]
+ : ( $^O eq 'MSWin32' && !$ENV{PROMPT} )
+ ? 'powershell.exe'
+ : 'sh';
+
+ for ($shellbin) {
+ return
+ /csh/ ? 'csh'
+ : /command\.com/i ? 'cmd'
+ : /cmd\.exe/i ? 'cmd'
+ : /4nt\.exe/i ? 'cmd'
+ : /powershell\.exe/i ? 'powershell'
+ : 'bourne';
+ }
+}
+
+1;
+__END__
+
+=encoding utf8
=head1 NAME
use local::lib '~/foo'; # same, but ~/foo
+ # Or...
+ use FindBin;
+ use local::lib "$FindBin::Bin/../support"; # app-local support library
+
From the shell -
+ # Install LWP and its missing dependencies to the '~/perl5' directory
+ perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'
+
+ # Just print out useful shell commands
$ perl -Mlocal::lib
- export MODULEBUILDRC=/home/username/perl/.modulebuildrc
- export PERL_MM_OPT='INSTALL_BASE=/home/username/perl'
- export PERL5LIB='/home/username/perl/lib/perl5:/home/username/perl/lib/perl5/i386-linux'
- export PATH="/home/username/perl/bin:$PATH"
+ export PERL_MB_OPT='--install_base /home/username/perl5'
+ export PERL_MM_OPT='INSTALL_BASE=/home/username/perl5'
+ export PERL5LIB="/home/username/perl5/lib/perl5"
+ export PATH="/home/username/perl5/bin:$PATH"
+
+=head2 The bootstrapping technique
+
+A typical way to install local::lib is using what is known as the
+"bootstrapping" technique. You would do this if your system administrator
+hasn't already installed local::lib. In this case, you'll need to install
+local::lib in your home directory.
+
+Even if you do have administrative privileges, you will still want to set up your
+environment variables, as discussed in step 4. Without this, you would still
+install the modules into the system CPAN installation and also your Perl scripts
+will not use the lib/ path you bootstrapped with local::lib.
+
+By default local::lib installs itself and the CPAN modules into ~/perl5.
+
+Windows users must also see L</Differences when using this module under Win32>.
+
+1. Download and unpack the local::lib tarball from CPAN (search for "Download"
+on the CPAN page about local::lib). Do this as an ordinary user, not as root
+or administrator. Unpack the file in your home directory or in any other
+convenient location.
+
+2. Run this:
+
+ perl Makefile.PL --bootstrap
+
+If the system asks you whether it should automatically configure as much
+as possible, you would typically answer yes.
+
+In order to install local::lib into a directory other than the default, you need
+to specify the name of the directory when you call bootstrap, as follows:
+
+ perl Makefile.PL --bootstrap=~/foo
+
+3. Run this: (local::lib assumes you have make installed on your system)
+
+ make test && make install
+
+4. Now we need to setup the appropriate environment variables, so that Perl
+starts using our newly generated lib/ directory. If you are using bash or
+any other Bourne shells, you can add this to your shell startup script this
+way:
+
+ echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc
+
+If you are using C shell, you can do this as follows:
+
+ /bin/csh
+ echo $SHELL
+ /bin/csh
+ echo 'eval `perl -I$HOME/perl5/lib/perl5 -Mlocal::lib`' >> ~/.cshrc
+
+If you passed to bootstrap a directory other than default, you also need to
+give that as import parameter to the call of the local::lib module like this
+way:
+
+ echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc
+
+After writing your shell configuration file, be sure to re-read it to get the
+changed settings into your current shell's environment. Bourne shells use
+C<. ~/.bashrc> for this, whereas C shells use C<source ~/.cshrc>.
+
+If you're on a slower machine, or are operating under draconian disk space
+limitations, you can disable the automatic generation of manpages from POD when
+installing modules by using the C<--no-manpages> argument when bootstrapping:
+
+ perl Makefile.PL --bootstrap --no-manpages
+
+To avoid doing several bootstrap for several Perl module environments on the
+same account, for example if you use it for several different deployed
+applications independently, you can use one bootstrapped local::lib
+installation to install modules in different directories directly this way:
+
+ cd ~/mydir1
+ perl -Mlocal::lib=./
+ eval $(perl -Mlocal::lib=./) ### To set the environment for this shell alone
+ printenv ### You will see that ~/mydir1 is in the PERL5LIB
+ perl -MCPAN -e install ... ### whatever modules you want
+ cd ../mydir2
+ ... REPEAT ...
+
+If you are working with several C<local::lib> environments, you may want to
+remove some of them from the current environment without disturbing the others.
+You can deactivate one environment like this (using bourne sh):
+
+ eval $(perl -Mlocal::lib=--deactivate,~/path)
+
+which will generate and run the commands needed to remove C<~/path> from your
+various search paths. Whichever environment was B<activated most recently> will
+remain the target for module installations. That is, if you activate
+C<~/path_A> and then you activate C<~/path_B>, new modules you install will go
+in C<~/path_B>. If you deactivate C<~/path_B> then modules will be installed
+into C<~/pathA> -- but if you deactivate C<~/path_A> then they will still be
+installed in C<~/pathB> because pathB was activated later.
+
+You can also ask C<local::lib> to clean itself completely out of the current
+shell's environment with the C<--deactivate-all> option.
+For multiple environments for multiple apps you may need to include a modified
+version of the C<< use FindBin >> instructions in the "In code" sample above.
+If you did something like the above, you have a set of Perl modules at C<<
+~/mydir1/lib >>. If you have a script at C<< ~/mydir1/scripts/myscript.pl >>,
+you need to tell it where to find the modules you installed for it at C<<
+~/mydir1/lib >>.
+
+In C<< ~/mydir1/scripts/myscript.pl >>:
+
+ use strict;
+ use warnings;
+ use local::lib "$FindBin::Bin/.."; ### points to ~/mydir1 and local::lib finds lib
+ use lib "$FindBin::Bin/../lib"; ### points to ~/mydir1/lib
+
+Put this before any BEGIN { ... } blocks that require the modules you installed.
+
+=head2 Differences when using this module under Win32
+
+To set up the proper environment variables for your current session of
+C<CMD.exe>, you can use this:
+
+ C:\>perl -Mlocal::lib
+ set PERL_MB_OPT=--install_base C:\DOCUME~1\ADMINI~1\perl5
+ set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
+ set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5
+ set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%
+
+ ### To set the environment for this shell alone
+ C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\tmp.bat
+ ### instead of $(perl -Mlocal::lib=./)
+
+If you want the environment entries to persist, you'll need to add them to the
+Control Panel's System applet yourself or use L<App::local::lib::Win32Helper>.
+
+The "~" is translated to the user's profile directory (the directory named for
+the user under "Documents and Settings" (Windows XP or earlier) or "Users"
+(Windows Vista or later)) unless $ENV{HOME} exists. After that, the home
+directory is translated to a short name (which means the directory must exist)
+and the subdirectories are created.
+
+=head3 PowerShell
+
+local::lib also supports PowerShell, and an be used with the
+C<Invoke-Expression> cmdlet.
+
+ Invoke-Expression "$(perl -Mlocal::lib)"
+
+=head1 RATIONALE
+
+The version of a Perl package on your machine is not always the version you
+need. Obviously, the best thing to do would be to update to the version you
+need. However, you might be in a situation where you're prevented from doing
+this. Perhaps you don't have system administrator privileges; or perhaps you
+are using a package management system such as Debian, and nobody has yet gotten
+around to packaging up the version you need.
+
+local::lib solves this problem by allowing you to create your own directory of
+Perl packages downloaded from CPAN (in a multi-user system, this would typically
+be within your own home directory). The existing system Perl installation is
+not affected; you simply invoke Perl with special options so that Perl uses the
+packages in your own local package directory rather than the system packages.
+local::lib arranges things so that your locally installed version of the Perl
+packages takes precedence over the system installation.
+
+If you are using a package management system (such as Debian), you don't need to
+worry about Debian and CPAN stepping on each other's toes. Your local version
+of the packages will be written to an entirely separate directory from those
+installed by Debian.
+
+=head1 DESCRIPTION
+
+This module provides a quick, convenient way of bootstrapping a user-local Perl
+module library located within the user's home directory. It also constructs and
+prints out for the user the list of environment variables using the syntax
+appropriate for the user's current shell (as specified by the C<SHELL>
+environment variable), suitable for directly adding to one's shell
+configuration file.
+
+More generally, local::lib allows for the bootstrapping and usage of a
+directory containing Perl modules outside of Perl's C<@INC>. This makes it
+easier to ship an application with an app-specific copy of a Perl module, or
+collection of modules. Useful in cases like when an upstream maintainer hasn't
+applied a patch to a module of theirs that you need for your application.
+
+On import, local::lib sets the following environment variables to appropriate
+values:
+
+=over 4
+
+=item PERL_MB_OPT
+
+=item PERL_MM_OPT
+
+=item PERL5LIB
+
+=item PATH
+
+=back
+
+When possible, these will be appended to instead of overwritten entirely.
+
+These values are then available for reference by any code after import.
+
+=head1 CREATING A SELF-CONTAINED SET OF MODULES
+
+See L<lib::core::only> for one way to do this - but note that
+there are a number of caveats, and the best approach is always to perform a
+build against a clean perl (i.e. site and vendor as close to empty as possible).
+
+=head1 OPTIONS
+
+Options are values that can be passed to the C<local::lib> import besides the
+directory to use. They are specified as C<use local::lib '--option'[, path];>
+or C<perl -Mlocal::lib=--option[,path]>.
+
+=head2 --deactivate
+
+Remove the chosen path (or the default path) from the module search paths if it
+was added by C<local::lib>, instead of adding it.
+
+=head2 --deactivate-all
+
+Remove all directories that were added to search paths by C<local::lib> from the
+search paths.
+
+=head2 --shelltype
+
+Specify the shell type to use for output. By default, the shell will be
+detected based on the environment. Should be one of: C<bourne>, C<csh>,
+C<cmd>, or C<powershell>.
+
+=head2 --no-create
+
+Prevents C<local::lib> from creating directories when activating dirs. This is
+likely to cause issues on Win32 systems.
+
+=head1 METHODS
+
+=head2 ensure_dir_structure_for
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: None
+
+=back
+
+Attempts to create the given path, and all required parent directories. Throws
+an exception on failure.
+
+=head2 print_environment_vars_for
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: None
+
+=back
+
+Prints to standard output the variables listed above, properly set to use the
+given path as the base directory.
+
+=head2 build_environment_vars_for
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: %environment_vars
+
+=back
+
+Returns a hash with the variables listed above, properly set to use the
+given path as the base directory.
+
+=head2 setup_env_hash_for
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: None
+
+=back
+
+Constructs the C<%ENV> keys for the given path, by calling
+L</build_environment_vars_for>.
+
+=head2 active_paths
+
+=over 4
+
+=item Arguments: None
+
+=item Return value: @paths
+
+=back
+
+Returns a list of active C<local::lib> paths, according to the
+C<PERL_LOCAL_LIB_ROOT> environment variable and verified against
+what is really in C<@INC>.
+
+=head2 install_base_perl_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $install_base_perl_path
+
+=back
+
+Returns a path describing where to install the Perl modules for this local
+library installation. Appends the directories C<lib> and C<perl5> to the given
+path.
+
+=head2 install_base_bin_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $install_base_bin_path
+
+=back
+
+Returns a path describing where to install the executable programs for this
+local library installation. Appends the directory C<bin> to the given path.
+
+=head2 resolve_empty_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $base_path
+
+=back
+
+Builds and returns the base path into which to set up the local module
+installation. Defaults to C<~/perl5>.
+
+=head2 resolve_home_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $home_path
+
+=back
+
+Attempts to find the user's home directory. If installed, uses C<File::HomeDir>
+for this purpose. If no definite answer is available, throws an exception.
+
+=head2 resolve_relative_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $absolute_path
+
+=back
+
+Translates the given path into an absolute path.
+
+=head2 resolve_path
+
+=over 4
+
+=item Arguments: $path
+
+=item Return value: $absolute_path
+
+=back
+
+Calls the following in a pipeline, passing the result from the previous to the
+next, in an attempt to find where to configure the environment for a local
+library installation: L</resolve_empty_path>, L</resolve_home_path>,
+L</resolve_relative_path>. Passes the given path argument to
+L</resolve_empty_path> which then returns a result that is passed to
+L</resolve_home_path>, which then has its result passed to
+L</resolve_relative_path>. The result of this final call is returned from
+L</resolve_path>.
+
+=head1 A WARNING ABOUT UNINST=1
+
+Be careful about using local::lib in combination with "make install UNINST=1".
+The idea of this feature is that will uninstall an old version of a module
+before installing a new one. However it lacks a safety check that the old
+version and the new version will go in the same directory. Used in combination
+with local::lib, you can potentially delete a globally accessible version of a
+module while installing the new version in a local place. Only combine "make
+install UNINST=1" and local::lib if you understand these possible consequences.
+
+=head1 LIMITATIONS
+
+=over 4
+
+=item * Directory names with spaces in them are not well supported by the perl
+toolchain and the programs it uses. Pure-perl distributions should support
+spaces, but problems are more likely with dists that require compilation. A
+workaround you can do is moving your local::lib to a directory with spaces
+B<after> you installed all modules inside your local::lib bootstrap. But be
+aware that you can't update or install CPAN modules after the move.
+
+=item * Rather basic shell detection. Right now anything with csh in its name is
+assumed to be a C shell or something compatible, and everything else is assumed
+to be Bourne, except on Win32 systems. If the C<SHELL> environment variable is
+not set, a Bourne-compatible shell is assumed.
+
+=item * Kills any existing PERL_MM_OPT or PERL_MB_OPT.
+
+=item * Should probably auto-fixup CPAN config if not already done.
+
+=back
+
+Patches very much welcome for any of the above.
+
+=over 4
+
+=item * On Win32 systems, does not have a way to write the created environment
+variables to the registry, so that they can persist through a reboot.
+
+=back
+
+=head1 TROUBLESHOOTING
+
+If you've configured local::lib to install CPAN modules somewhere in to your
+home directory, and at some point later you try to install a module with C<cpan
+-i Foo::Bar>, but it fails with an error like: C<Warning: You do not have
+permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
+/usr/lib64/perl5/5.8.8/Foo/Bar.pm> and buried within the install log is an
+error saying C<'INSTALL_BASE' is not a known MakeMaker parameter name>, then
+you've somehow lost your updated ExtUtils::MakeMaker module.
+
+To remedy this situation, rerun the bootstrapping procedure documented above.
+
+Then, run C<rm -r ~/.cpan/build/Foo-Bar*>
+
+Finally, re-run C<cpan -i Foo::Bar> and it should install without problems.
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item SHELL
+
+=item COMSPEC
+
+local::lib looks at the user's C<SHELL> environment variable when printing out
+commands to add to the shell configuration file.
+
+On Win32 systems, C<COMSPEC> is also examined.
+
+=back
+
+=head1 SEE ALSO
+
+=over 4
+
+=item * L<Perl Advent article, 2011|http://perladvent.org/2011/2011-12-01.html>
+
+=back
+
+=head1 SUPPORT
+
+IRC:
+
+ Join #local-lib on irc.perl.org.
=head1 AUTHOR
Matt S Trout <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/
+auto_install fixes kindly sponsored by http://www.takkle.com/
+
+=head1 CONTRIBUTORS
+
+Patches to correctly output commands for csh style shells, as well as some
+documentation additions, contributed by Christopher Nehren <apeiron@cpan.org>.
+
+Doc patches for a custom local::lib directory, more cleanups in the english
+documentation and a L<german documentation|POD2::DE::local::lib> contributed by
+Torsten Raudssus <torsten@raudssus.de>.
+
+Hans Dieter Pearcey <hdp@cpan.org> sent in some additional tests for ensuring
+things will install properly, submitted a fix for the bug causing problems with
+writing Makefiles during bootstrapping, contributed an example program, and
+submitted yet another fix to ensure that local::lib can install and bootstrap
+properly. Many, many thanks!
+
+pattern of Freenode IRC contributed the beginnings of the Troubleshooting
+section. Many thanks!
+
+Patch to add Win32 support contributed by Curtis Jewell <csjewell@cpan.org>.
+
+Warnings for missing PATH/PERL5LIB (as when not running interactively) silenced
+by a patch from Marco Emilio Poleggi.
+
+Mark Stosberg <mark@summersault.com> provided the code for the now deleted
+'--self-contained' option.
+
+Documentation patches to make win32 usage clearer by
+David Mertens <dcmertens.perl@gmail.com> (run4flat).
+
+Brazilian L<portuguese translation|POD2::PT_BR::local::lib> and minor doc
+patches contributed by Breno G. de Oliveira <garu@cpan.org>.
+
+Improvements to stacking multiple local::lib dirs and removing them from the
+environment later on contributed by Andrew Rodland <arodland@cpan.org>.
+
+Patch for Carp version mismatch contributed by Hakim Cassimally
+<osfameron@cpan.org>.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2007 - 2010 the local::lib L</AUTHOR> and L</CONTRIBUTORS> as
+listed above.
+
=head1 LICENSE
-This library is free software under the same license as perl itself
+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
-
-1;