diff options
author | Edmund von der Burg <evdb@mysociety.org> | 2011-05-19 16:49:19 +0100 |
---|---|---|
committer | Edmund von der Burg <evdb@mysociety.org> | 2011-05-19 16:51:37 +0100 |
commit | 75a3614767dde3b3f0376acd9879bc09b4ba09e4 (patch) | |
tree | 02712419b2f5d2b4408f036586434d956659c620 /perl-external | |
parent | 4d2520605ddbc644a2e835a967659e92511e7961 (diff) |
Upgraded cpanm and local::lib to the latest versions
Diffstat (limited to 'perl-external')
-rwxr-xr-x | perl-external/bin/cpanm | 1755 | ||||
-rw-r--r-- | perl-external/dpan_config | 2 | ||||
-rw-r--r-- | perl-external/dpan_l4p_config | 5 | ||||
-rw-r--r-- | perl-external/lib/perl5/local/lib.pm | 226 |
4 files changed, 622 insertions, 1366 deletions
diff --git a/perl-external/bin/cpanm b/perl-external/bin/cpanm index 1c552fac2..15996e72c 100755 --- a/perl-external/bin/cpanm +++ b/perl-external/bin/cpanm @@ -1,4 +1,7 @@ -#!/usr/bin/env perl +#!/usr/bin/perl + +eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' + if 0; # not running under some shell # # You want to install cpanminus? Run the following command and it will # install itself for you. You might want to run it as a root with sudo @@ -18,7 +21,7 @@ my %fatpacked; $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS'; package App::cpanminus; - our $VERSION = "1.3001"; + our $VERSION = "1.4007"; =head1 NAME @@ -73,7 +76,7 @@ $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS'; to install the C<cpanm> executable to the perl's bin path, like C<~/perl5/perlbrew/bin/cpanm>. - =head2 Downloaing the standalone executable + =head2 Downloading the standalone executable You can also copy the standalone executable to whatever location you'd like. @@ -303,16 +306,18 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; use Config; use Cwd (); use File::Basename (); + use File::Find (); use File::Path (); use File::Spec (); use File::Copy (); use Getopt::Long (); use Parse::CPAN::Meta; + use Symbol (); use constant WIN32 => $^O eq 'MSWin32'; use constant SUNOS => $^O eq 'solaris'; - our $VERSION = "1.3001"; + our $VERSION = "1.4007"; my $quote = WIN32 ? q/"/ : q/'/; @@ -347,6 +352,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; uninstall_shadows => ($] < 5.012), skip_installed => 1, auto_cleanup => 7, # days + pod2man => 1, + installed_dists => 0, + scandeps => 0, + scandeps_tree => [], + format => 'tree', + save_dists => undef, @_, }, $class; } @@ -363,10 +374,6 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; push @ARGV, split /\s+/, $self->env('OPT'); push @ARGV, @_; - if ($0 ne '-' && !-t STDIN){ # e.g. $ cpanm < author/requires.cpanm - push @ARGV, $self->load_argv_from_fh(\*STDIN); - } - Getopt::Long::Configure("bundling"); Getopt::Long::GetOptions( 'f|force' => sub { $self->{skip_installed} = 0; $self->{force} = 1 }, @@ -378,7 +385,11 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; 'V|version' => sub { $self->{action} = 'show_version' }, 'perl=s' => \$self->{perl}, 'l|local-lib=s' => sub { $self->{local_lib} = $self->maybe_abs($_[1]) }, - 'L|local-lib-contained=s' => sub { $self->{local_lib} = $self->maybe_abs($_[1]); $self->{self_contained} = 1 }, + 'L|local-lib-contained=s' => sub { + $self->{local_lib} = $self->maybe_abs($_[1]); + $self->{self_contained} = 1; + $self->{pod2man} = undef; + }, 'mirror=s@' => $self->{mirrors}, 'mirror-only!' => \$self->{mirror_only}, 'prompt!' => \$self->{prompt}, @@ -395,8 +406,19 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; 'wget!' => \$self->{try_wget}, 'curl!' => \$self->{try_curl}, 'auto-cleanup=s' => \$self->{auto_cleanup}, + 'man-pages!' => \$self->{pod2man}, + 'scandeps' => \$self->{scandeps}, + 'format=s' => \$self->{format}, + 'save-dists=s' => sub { + $self->{save_dists} = $self->maybe_abs($_[1]); + }, ); + if (!@ARGV && $0 ne '-' && !-t STDIN){ # e.g. # cpanm < author/requires.cpanm + push @ARGV, $self->load_argv_from_fh(\*STDIN); + $self->{load_from_stdin} = 1; + } + $self->{argv} = \@ARGV; } @@ -407,6 +429,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $self->bootstrap_local_lib; if (@{$self->{bootstrap_deps} || []}) { local $self->{notest} = 1; # test failure in bootstrap should be tolerated + local $self->{scandeps} = 0; $self->install_deps(Cwd::cwd, 0, @{$self->{bootstrap_deps}}); } } @@ -421,7 +444,8 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $self->$action() and return 1; } - $self->show_help(1) unless @{$self->{argv}}; + $self->show_help(1) + unless @{$self->{argv}} or $self->{load_from_stdin}; $self->configure_mirrors; @@ -439,6 +463,15 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $self->cleanup_workdirs; } + if ($self->{installed_dists}) { + my $dists = $self->{installed_dists} > 1 ? "distributions" : "distribution"; + $self->diag("$self->{installed_dists} $dists installed\n", 1); + } + + if ($self->{scandeps}) { + $self->dump_scandeps(); + } + return !@fail; } @@ -467,20 +500,18 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; }; } - open my $out, ">$self->{log}" or die "$self->{log}: $!"; - print $out "cpanm (App::cpanminus) $VERSION on perl $] built for $Config{archname}\n"; - print $out "Work directory is $self->{base}\n"; + { open my $out, ">$self->{log}" or die "$self->{log}: $!" } + + $self->chat("cpanm (App::cpanminus) $VERSION on perl $] built for $Config{archname}\n" . + "Work directory is $self->{base}\n"); } - sub fetch_meta { + sub fetch_meta_sco { my($self, $dist) = @_; + return if $self->{mirror_only}; - unless ($self->{mirror_only}) { - my $meta_yml = $self->get("http://cpansearch.perl.org/src/$dist->{cpanid}/$dist->{distvname}/META.yml"); - return $self->parse_meta_string($meta_yml); - } - - return undef; + my $meta_yml = $self->get("http://search.cpan.org/meta/$dist->{distvname}/META.yml"); + return $self->parse_meta_string($meta_yml); } sub package_index_for { @@ -510,7 +541,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; print $fh $buffer; } } else { - unless (system("gunzip -c $gz_file > $file")) { + if (system("gunzip -c $gz_file > $file")) { $self->diag_fail("Cannot uncompress -- please install gunzip or Compress::Zlib"); return; } @@ -541,7 +572,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $uri = "http://cpanmetadb.appspot.com/v1.0/package/$module"; my $yaml = $self->get($uri); my $meta = $self->parse_meta_string($yaml); - if ($meta->{distfile}) { + if ($meta && $meta->{distfile}) { return $self->cpan_module($module, $meta->{distfile}, $meta->{version}); } @@ -624,7 +655,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; Options: -v,--verbose Turns on chatty output - -q,--quiet Turns off all output + -q,--quiet Turns off the most output --interactive Turns on interactive configure (required for Task:: modules) -f,--force force install -n,--notest Do not run unit tests @@ -729,19 +760,44 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } sub _dump_inc { - my($self, $inc) = @_; + my($self, $inc, $std_inc) = @_; - my @inc = map { qq('$_') } (@$inc, '.'); # . for inc/Module/Install.pm + # $self->{base} for ModuleBuildPatch.pm, . for inc/Module/Install.pm + my @new_inc = map { qq('$_') } (@$inc, $self->{base}, '.'); + my @exclude_inc = map { qq('$_') } grep { $_ ne '.' && !ref } $self->_diff($inc, $std_inc); open my $out, ">$self->{base}/DumpedINC.pm" or die $!; local $" = ","; - print $out "BEGIN { \@INC = (@inc) }\n1;\n"; + print $out <<EOF; + package DumpedINC; + my \%exclude = map { \$_ => 1 } (@exclude_inc); + sub import { + if (\$_[1] eq "tests") { + \@INC = grep !\$exclude{\$_}, \@INC; + } else { + \@INC = (@new_inc); + } + } + 1; + EOF + } + + sub _diff { + my($self, $old, $new) = @_; + + my @diff; + my %old = map { $_ => 1 } @$old; + for my $n (@$new) { + push @diff, $n unless exists $old{$n}; + } + + @diff; } - sub _import_local_lib { - my($self, @args) = @_; + sub _setup_local_lib_env { + my($self, $base) = @_; local $SIG{__WARN__} = sub { }; # catch 'Attempting to write ...' - local::lib->import(@args); + local::lib->setup_env_hash_for($base); } sub setup_local_lib { @@ -753,10 +809,16 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $base ||= "~/perl5"; if ($self->{self_contained}) { my @inc = $self->_core_only_inc($base); - $self->_dump_inc(\@inc); + $self->_dump_inc(\@inc, \@INC); $self->{search_inc} = [ @inc ]; + } else { + $self->{search_inc} = [ + local::lib->install_base_arch_path($base), + local::lib->install_base_perl_path($base), + @INC, + ]; } - $self->_import_local_lib($base); + $self->_setup_local_lib_env($base); } $self->bootstrap_local_lib_deps; @@ -784,7 +846,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $dispdef = defined $def ? "[$def] " : " "; $def = defined $def ? $def : ""; - if ($self->{quiet} || !$self->{prompt} || (!$isa_tty && eof STDIN)) { + if (!$self->{prompt} || (!$isa_tty && eof STDIN)) { return $def; } @@ -819,7 +881,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } sub diag_fail { - my($self, $msg) = @_; + my($self, $msg, $always) = @_; chomp $msg; if ($self->{in_progress}) { $self->_diag("FAIL\n"); @@ -827,7 +889,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } if ($msg) { - $self->_diag("! $msg\n"); + $self->_diag("! $msg\n", $always); $self->log("-> FAIL $msg\n"); } } @@ -841,13 +903,13 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } sub _diag { - my $self = shift; - print STDERR @_ if $self->{verbose} or !$self->{quiet}; + my($self, $msg, $always) = @_; + print STDERR $msg if $always or $self->{verbose} or !$self->{quiet}; } sub diag { - my($self, $msg) = @_; - $self->_diag($msg); + my($self, $msg, $always) = @_; + $self->_diag($msg, $always); $self->log($msg); } @@ -945,6 +1007,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $use_default = !$self->{interactive}; local $ENV{PERL_MM_USE_DEFAULT} = $use_default; + # skip man page generation + local $ENV{PERL_MM_OPT} = $ENV{PERL_MM_OPT}; + unless ($self->{pod2man}) { + $ENV{PERL_MM_OPT} .= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none"; + } + local $self->{verbose} = $self->{verbose} || $self->{interactive}; $self->run_timeout($cmd, $self->{configure_timeout}); } @@ -969,6 +1037,9 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; local $ENV{AUTOMATED_TESTING} = 1 unless $self->env('NO_AUTOMATED_TESTING'); + local $ENV{PERL5OPT} = "-I$self->{base} -MDumpedINC=tests" + if $self->{self_contained}; + return 1 if $self->run_timeout($cmd, $self->{test_timeout}); if ($self->{force}) { $self->diag_fail("Testing $distname failed but installing it anyway."); @@ -1045,7 +1116,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $dist = $self->resolve_name($module); unless ($dist) { - $self->diag_fail("Couldn't find module or a distribution $module"); + $self->diag_fail("Couldn't find module or a distribution $module", 1); return; } @@ -1054,21 +1125,18 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; return 1; } - if ($dist->{source} eq 'cpan') { - $dist->{meta} = $self->fetch_meta($dist); - } - if ($self->{cmd} eq 'info') { - print $dist->{cpanid}, "/", $dist->{filename}, "\n"; + print $self->format_dist($dist), "\n"; return 1; } $self->check_libs; + $self->setup_module_build_patch unless $self->{pod2man}; if ($dist->{module}) { my($ok, $local) = $self->check_module($dist->{module}, $dist->{module_version} || 0); if ($self->{skip_installed} && $ok) { - $self->diag("$dist->{module} is up to date. ($local)\n"); + $self->diag("$dist->{module} is up to date. ($local)\n", 1); return 1; } } @@ -1083,7 +1151,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $dist->{dir} ||= $self->fetch_module($dist); unless ($dist->{dir}) { - $self->diag_fail("Failed to fetch distribution $dist->{distvname}"); + $self->diag_fail("Failed to fetch distribution $dist->{distvname}", 1); return; } @@ -1099,6 +1167,13 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; return $self->build_stuff($module, $dist, $depth); } + sub format_dist { + my($self, $dist) = @_; + + # TODO support --dist-format? + return "$dist->{cpanid}/$dist->{filename}"; + } + sub fetch_module { my($self, $dist) = @_; @@ -1141,10 +1216,18 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } $self->diag_ok; + $dist->{local_path} = File::Spec->rel2abs($name); my $dir = $self->unpack($file); next unless $dir; # unpack failed + if (my $save = $self->{save_dists}) { + my $path = "$save/authors/id/$dist->{pathname}"; + $self->chat("Copying $name to $path\n"); + File::Path::mkpath([ File::Basename::dirname($path) ], 0, 0777); + File::Copy::copy($file, $path) or warn $!; + } + return $dist, $dir; } } @@ -1238,6 +1321,23 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; }; } + sub setup_module_build_patch { + my $self = shift; + + open my $out, ">$self->{base}/ModuleBuildSkipMan.pm" or die $!; + print $out <<EOF; + package ModuleBuildSkipMan; + CHECK { + if (%Module::Build::) { + no warnings 'redefine'; + *Module::Build::Base::ACTION_manpages = sub {}; + *Module::Build::Base::ACTION_docs = sub {}; + } + } + 1; + EOF + } + sub check_module { my($self, $mod, $want_ver) = @_; @@ -1250,8 +1350,21 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; # When -L is in use, the version loaded from 'perl' library path # might be newer than the version that is shipped with the current perl if ($self->{self_contained} && $self->loaded_from_perl_lib($meta)) { - require Module::CoreList; - $version = $Module::CoreList::version{$]}{$mod}; + my $core_version = eval { + require Module::CoreList; + $Module::CoreList::version{$]+0}{$mod}; + }; + + # HACK: Module::Build 0.3622 or later has non-core module + # dependencies such as Perl::OSType and CPAN::Meta, and causes + # issues when a newer version is loaded from 'perl' while deps + # are loaded from the 'site' library path. Just assume it's + # not in the core, and install to the new local library path. + if ($mod eq 'Module::Build' && $core_version != $version) { + return 0, undef; + } + + $version = $core_version if $core_version; } $self->{local_versions}{$mod} = $version; @@ -1259,7 +1372,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; if ($self->is_deprecated($meta)){ return 0, $version; } elsif (!$want_ver or $version >= version->new($want_ver)) { - return 1, $version; + return 1, ($version || 'undef'); } else { return 0, $version; } @@ -1340,7 +1453,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; if (@fail) { unless ($self->prompt_bool("Installing the following dependencies failed:\n==> " . join(", ", @fail) . "\nDo you want to continue building $target anyway?", "n")) { - $self->diag_fail("Bailing out the installation for $target. Retry with --prompt or --force."); + $self->diag_fail("Bailing out the installation for $target. Retry with --prompt or --force.", 1); return; } } @@ -1348,25 +1461,6 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; return 1; } - sub _patch_module_build_config_deps { - my($self, $config_deps) = @_; - - # Crazy hack to auto-add Module::Build dependencies into - # configure_requires if Module::Build is there, since there's a - # possibility where Module::Build is in 'perl' library path while - # the dependencies are in 'site' and can't be loaded when -L - # (--local-lib-contained) is in effect. - - my %config_deps = (@{$config_deps}); - if ($config_deps{"Module::Build"}) { - push @{$config_deps}, ( - 'Perl::OSType' => 1, - 'Module::Metadata' => 1.000002, - 'version' => 0.87, - ); - } - } - sub build_stuff { my($self, $stuff, $dist, $depth) = @_; @@ -1376,13 +1470,17 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $dist->{meta} = $self->parse_meta('META.yml'); } + if (!$dist->{meta} && $dist->{source} eq 'cpan') { + $self->chat("META.yml not found or unparsable. Fetching META.yml from search.cpan.org\n"); + $dist->{meta} = $self->fetch_meta_sco($dist); + } + + $dist->{meta} ||= {}; + push @config_deps, %{$dist->{meta}{configure_requires} || {}}; my $target = $dist->{meta}{name} ? "$dist->{meta}{name}-$dist->{meta}{version}" : $dist->{dir}; - $self->_patch_module_build_config_deps(\@config_deps) - if $self->{self_contained}; - $self->install_deps_bailout($target, $dist->{dir}, $depth, @config_deps) or return; @@ -1392,13 +1490,34 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $self->diag_ok($configure_state->{configured_ok} ? "OK" : "N/A"); - my @deps = $self->find_prereqs($dist->{meta}); + my @deps = $self->find_prereqs($dist); my $distname = $dist->{meta}{name} ? "$dist->{meta}{name}-$dist->{meta}{version}" : $stuff; + my $walkup; + if ($self->{scandeps}) { + $walkup = $self->scandeps_append_child($dist); + } + $self->install_deps_bailout($distname, $dist->{dir}, $depth, @deps) or return; + if ($self->{scandeps}) { + unless ($configure_state->{configured_ok}) { + my $diag = <<DIAG; + ! Configuring $distname failed. See $self->{log} for details. + ! You might have to install the following modules first to get --scandeps working correctly. + DIAG + if (@config_deps) { + my @tree = @{$self->{scandeps_tree}}; + $diag .= "!\n" . join("", map "! * $_->[0]{module}\n", @tree[0..$#tree-1]) if @tree; + } + $self->diag("!\n$diag!\n", 1); + } + $walkup->(); + return 1; + } + if ($self->{installdeps} && $depth == 0) { $self->diag("<== Installed dependencies for $stuff. Finishing.\n"); return 1; @@ -1406,10 +1525,11 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $installed; if ($configure_state->{use_module_build} && -e 'Build' && -f _) { + my @switches = $self->{pod2man} ? () : ("-I$self->{base}", "-MModuleBuildSkipMan"); $self->diag_progress("Building " . ($self->{notest} ? "" : "and testing ") . $distname); - $self->build([ $self->{perl}, "./Build" ], $distname) && + $self->build([ $self->{perl}, @switches, "./Build" ], $distname) && $self->test([ $self->{perl}, "./Build", "test" ], $distname) && - $self->install([ $self->{perl}, "./Build", "install" ], [ "--uninst", 1 ]) && + $self->install([ $self->{perl}, @switches, "./Build", "install" ], [ "--uninst", 1 ]) && $installed++; } elsif ($self->{make} && -e 'Makefile') { $self->diag_progress("Building " . ($self->{notest} ? "" : "and testing ") . $distname); @@ -1424,7 +1544,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; elsif ($self->{make}) { $why = "The distribution doesn't have a proper Makefile.PL/Build.PL" } else { $why = "Can't configure the distribution. You probably need to have 'make'." } - $self->diag_fail("$why See $self->{log} for details."); + $self->diag_fail("$why See $self->{log} for details.", 1); return; } @@ -1438,11 +1558,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; : "installed $distname" ; my $msg = "Successfully $how"; $self->diag_ok; - $self->diag("$msg\n"); + $self->diag("$msg\n", 1); + $self->{installed_dists}++; return 1; } else { my $msg = "Building $distname failed"; - $self->diag_fail("Installing $stuff failed. See $self->{log} for details."); + $self->diag_fail("Installing $stuff failed. See $self->{log} for details.", 1); return; } } @@ -1454,6 +1575,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; @switches = ("-I$self->{base}", "-MDumpedINC") if $self->{self_contained}; local $ENV{PERL5LIB} = '' if $self->{self_contained}; + my @mb_switches = @switches; + unless ($self->{pod2man}) { + # it has to be push, so Module::Build is loaded from the adjusted path when -L is in use + push @mb_switches, ("-I$self->{base}", "-MModuleBuildSkipMan"); + } + my $state = {}; my $try_eumm = sub { @@ -1475,7 +1602,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; my $try_mb = sub { if (-e 'Build.PL') { $self->chat("Running Build.PL\n"); - if ($self->configure([ $self->{perl}, @switches, "Build.PL" ])) { + if ($self->configure([ $self->{perl}, @mb_switches, "Build.PL" ])) { $state->{configured_ok} = -e 'Build' && -f _; } $state->{use_module_build}++; @@ -1517,14 +1644,18 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } sub find_prereqs { - my($self, $meta) = @_; + my($self, $dist) = @_; my @deps; + + my $meta = $dist->{meta}; if (-e 'MYMETA.yml') { $self->chat("Checking dependencies from MYMETA.yml ...\n"); my $mymeta = $self->parse_meta('MYMETA.yml'); - @deps = $self->extract_requires($mymeta); - $meta->{$_} = $mymeta->{$_} for keys %$mymeta; # merge + if ($mymeta) { + @deps = $self->extract_requires($mymeta); + $meta->{$_} = $mymeta->{$_} for keys %$mymeta; # merge + } } elsif (-e '_build/prereqs') { $self->chat("Checking dependencies from _build/prereqs ...\n"); my $mymeta = do { open my $in, "_build/prereqs"; $self->safe_eval(join "", <$in>) }; @@ -1550,12 +1681,50 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } } + if ($dist->{module} =~ /^Bundle::/i) { + push @deps, $self->bundle_deps($dist); + } + # No need to remove, but this gets in the way of signature testing :/ - unlink 'MYMETA.yml'; + unlink $_ for qw(MYMETA.json MYMETA.yml); return @deps; } + sub bundle_deps { + my($self, $dist) = @_; + + my @files; + File::Find::find({ + wanted => sub { push @files, File::Spec->rel2abs($_) if /\.pm/i }, + no_chdir => 1, + }, '.'); + + my @deps; + + for my $file (@files) { + open my $pod, "<", $file or next; + my $in_contents; + while (<$pod>) { + if (/^=head\d\s+CONTENTS/) { + $in_contents = 1; + } elsif (/^=/) { + $in_contents = 0; + } elsif ($in_contents) { + /^(\S+)\s*(\S+)?/ + and push @deps, $1, $self->maybe_version($2); + } + } + } + + return @deps; + } + + sub maybe_version { + my($self, $string) = @_; + return $string && $string =~ /^\.?\d/ ? $string : undef; + } + sub extract_requires { my($self, $meta) = @_; @@ -1587,6 +1756,64 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } } + sub scandeps_append_child { + my($self, $dist) = @_; + + my $new_node = [ $dist, [] ]; + + my $curr_node = $self->{scandeps_current} || [ undef, $self->{scandeps_tree} ]; + push @{$curr_node->[1]}, $new_node; + + $self->{scandeps_current} = $new_node; + + return sub { $self->{scandeps_current} = $curr_node }; + } + + sub dump_scandeps { + my $self = shift; + + if ($self->{format} eq 'tree') { + $self->walk_down(sub { + my($dist, $depth) = @_; + if ($depth == 0) { + print "$dist->{distvname}\n"; + } else { + print " " x ($depth - 1); + print "\\_ $dist->{distvname}\n"; + } + }, 1); + } elsif ($self->{format} =~ /^dists?$/) { + $self->walk_down(sub { + my($dist, $depth) = @_; + print $self->format_dist($dist), "\n"; + }, 0); + } elsif ($self->{format} eq 'json') { + require JSON; + print JSON::encode_json($self->{scandeps_tree}); + } elsif ($self->{format} eq 'yaml') { + require YAML; + print YAML::Dump($self->{scandeps_tree}); + } else { + $self->diag("Unknown format: $self->{format}\n"); + } + } + + sub walk_down { + my($self, $cb, $pre) = @_; + $self->_do_walk_down($self->{scandeps_tree}, $cb, 0, $pre); + } + + sub _do_walk_down { + my($self, $children, $cb, $depth, $pre) = @_; + + # DFS - $pre determines when we call the callback + for my $node (@$children) { + $cb->($node->[0], $depth) if $pre; + $self->_do_walk_down($node->[1], $cb, $depth + 1, $pre); + $cb->($node->[0], $depth) unless $pre; + } + } + sub DESTROY { my $self = shift; $self->{at_exit}->($self) if $self->{at_exit}; @@ -1596,7 +1823,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; sub shell_quote { my($self, $stuff) = @_; - $quote . $stuff . $quote; + $stuff =~ /^${quote}.+${quote}$/ ? $stuff : ($quote . $stuff . $quote); } sub which { @@ -1667,32 +1894,32 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; $self->{_backends}{get} = sub { my($self, $uri) = @_; return $self->file_get($uri) if $uri =~ s!^file:/+!/!; - my $q = $self->{verbose} ? '' : '-q'; - open my $fh, "$wget $uri $q -O - |" or die "wget $uri: $!"; + $self->safeexec( my $fh, $wget, $uri, ( $self->{verbose} ? () : '-q' ), '-O', '-' ) or die "wget $uri: $!"; local $/; <$fh>; }; $self->{_backends}{mirror} = sub { my($self, $uri, $path) = @_; return $self->file_mirror($uri, $path) if $uri =~ s!^file:/+!/!; - my $q = $self->{verbose} ? '' : '-q'; - system "$wget --retry-connrefused $uri $q -O $path"; + $self->safeexec( my $fh, $wget, '--retry-connrefused', $uri, ( $self->{verbose} ? () : '-q' ), '-O', $path ) or die "wget $uri: $!"; + local $/; + <$fh>; }; } elsif ($self->{try_curl} and my $curl = $self->which('curl')) { $self->chat("You have $curl\n"); $self->{_backends}{get} = sub { my($self, $uri) = @_; return $self->file_get($uri) if $uri =~ s!^file:/+!/!; - my $q = $self->{verbose} ? '' : '-s'; - open my $fh, "$curl -L $q $uri |" or die "curl $uri: $!"; + $self->safeexec( my $fh, $curl, '-L', ( $self->{verbose} ? () : '-s' ), $uri ) or die "curl $uri: $!"; local $/; <$fh>; }; $self->{_backends}{mirror} = sub { my($self, $uri, $path) = @_; return $self->file_mirror($uri, $path) if $uri =~ s!^file:/+!/!; - my $q = $self->{verbose} ? '' : '-s'; - system "$curl -L $uri $q -# -o $path"; + $self->safeexec( my $fh, $curl, '-L', $uri, ( $self->{verbose} ? () : '-s' ), '-#', '-o', $path ) or die "curl $uri: $!"; + local $/; + <$fh>; }; } else { require HTTP::Tiny; @@ -1728,6 +1955,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; or return undef; chomp $root; + $root =~ s!^\./!!; $root =~ s{^(.+?)/.*$}{$1}; system "$tar $xf$ar $tarfile"; @@ -1817,14 +2045,35 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT'; } } + sub safeexec { + my $self = shift; + my $rdr = $_[0] ||= Symbol::gensym(); + + if (WIN32) { + my $cmd = join q{ }, map { $self->shell_quote($_) } @_[ 1 .. $#_ ]; + return open( $rdr, "$cmd |" ); + } + + if ( my $pid = open( $rdr, '-|' ) ) { + return $pid; + } + elsif ( defined $pid ) { + exec( @_[ 1 .. $#_ ] ); + exit 1; + } + else { + return; + } + } + sub parse_meta { my($self, $file) = @_; - return eval { (Parse::CPAN::Meta::LoadFile($file))[0] } || {}; + return eval { (Parse::CPAN::Meta::LoadFile($file))[0] } || undef; } sub parse_meta_string { my($self, $yaml) = @_; - return eval { (Parse::CPAN::Meta::Load($yaml))[0] } || {}; + return eval { (Parse::CPAN::Meta::Load($yaml))[0] } || undef; } 1; @@ -1935,99 +2184,6 @@ $fatpacked{"CPAN/DistnameInfo.pm"} = <<'CPAN_DISTNAMEINFO'; __END__ - =head1 NAME - - CPAN::DistnameInfo - Extract distribution name and version from a distribution filename - - =head1 SYNOPSIS - - my $pathname = "authors/id/G/GB/GBARR/CPAN-DistnameInfo-0.02.tar.gz"; - - my $d = CPAN::DistnameInfo->new($pathname); - - my $dist = $d->dist; # "CPAN-DistnameInfo" - my $version = $d->version; # "0.02" - my $maturity = $d->maturity; # "released" - my $filename = $d->filename; # "CPAN-DistnameInfo-0.02.tar.gz" - my $cpanid = $d->cpanid; # "GBARR" - my $distvname = $d->distvname; # "CPAN-DistnameInfo-0.02" - my $extension = $d->extension; # "tar.gz" - my $pathname = $d->pathname; # "authors/id/G/GB/GBARR/..." - - my %prop = $d->properties; - - =head1 DESCRIPTION - - Many online services that are centered around CPAN attempt to - associate multiple uploads by extracting a distribution name from - the filename of the upload. For most distributions this is easy as - they have used ExtUtils::MakeMaker or Module::Build to create the - distribution, which results in a uniform name. But sadly not all - uploads are created in this way. - - C<CPAN::DistnameInfo> uses heuristics that have been learnt by - L<http://search.cpan.org/> to extract the distribution name and - version from filenames and also report if the version is to be - treated as a developer release - - The constructor takes a single pathname, returning an object with the following methods - - =over - - =item cpanid - - If the path given looked like a CPAN authors directory path, then this will be the - the CPAN id of the author. - - =item dist - - The name of the distribution - - =item distvname - - The file name with any suffix and leading directory names removed - - =item filename - - If the path given looked like a CPAN authors directory path, then this will be the - path to the file relative to the detected CPAN author directory. Otherwise it is the path - that was passed in. - - =item maturity - - The maturity of the distribution. This will be either C<released> or C<developer> - - =item extension - - The extension of the distribution, often used to denote the archive type (e.g. 'tar.gz') - - =item pathname - - The pathname that was passed to the constructor when creating the object. - - =item properties - - This will return a list of key-value pairs, suitable for assigning to a hash, - for the known properties. - - =item version - - The extracted version - - =back - - =head1 AUTHOR - - Graham Barr <gbarr@pobox.com> - - =head1 COPYRIGHT - - Copyright (c) 2003 Graham Barr. All rights reserved. This program is - free software; you can redistribute it and/or modify it under the same - terms as Perl itself. - - =cut - CPAN_DISTNAMEINFO $fatpacked{"HTTP/Tiny.pm"} = <<'HTTP_TINY'; @@ -2786,327 +2942,6 @@ $fatpacked{"HTTP/Tiny.pm"} = <<'HTTP_TINY'; __END__ =pod - =head1 NAME - - HTTP::Tiny - A small, simple, correct HTTP/1.1 client - - =head1 VERSION - - version 0.009 - - =head1 SYNOPSIS - - use HTTP::Tiny; - - my $response = HTTP::Tiny->new->get('http://example.com/'); - - die "Failed!\n" unless $response->{success}; - - print "$response->{status} $response->{reason}\n"; - - while (my ($k, $v) = each %{$response->{headers}}) { - for (ref $v eq 'ARRAY' ? @$v : $v) { - print "$k: $_\n"; - } - } - - print $response->{content} if length $response->{content}; - - =head1 DESCRIPTION - - This is a very simple HTTP/1.1 client, designed primarily for doing simple GET - requests without the overhead of a large framework like L<LWP::UserAgent>. - - It is more correct and more complete than L<HTTP::Lite>. It supports - proxies (currently only non-authenticating ones) and redirection. It - also correctly resumes after EINTR. - - =head1 METHODS - - =head2 new - - $http = HTTP::Tiny->new( %attributes ); - - This constructor returns a new HTTP::Tiny object. Valid attributes include: - - =over 4 - - =item * - - agent - - A user-agent string (defaults to 'HTTP::Tiny/$VERSION') - - =item * - - default_headers - - A hashref of default headers to apply to requests - - =item * - - max_redirect - - Maximum number of redirects allowed (defaults to 5) - - =item * - - max_size - - Maximum response size (only when not using a data callback). If defined, - responses larger than this will die with an error message - - =item * - - proxy - - URL of a proxy server to use. - - =item * - - timeout - - Request timeout in seconds (default is 60) - - =back - - =head2 get - - $response = $http->get($url); - $response = $http->get($url, \%options); - - Executes a C<GET> request for the given URL. The URL must have unsafe - characters escaped and international domain names encoded. Internally, it just - calls C<request()> with 'GET' as the method. See C<request()> for valid - options and a description of the response. - - =head2 mirror - - $response = $http->mirror($url, $file, \%options) - if ( $response->{success} ) { - print "$file is up to date\n"; - } - - Executes a C<GET> request for the URL and saves the response body to the file - name provided. The URL must have unsafe characters escaped and international - domain names encoded. If the file already exists, the request will includes an - C<If-Modified-Since> header with the modification timestamp of the file. You - may specificy a different C<If-Modified-Since> header yourself in the C<< - $options->{headers} >> hash. - - The C<success> field of the response will be true if the status code is 2XX - or 304 (unmodified). - - If the file was modified and the server response includes a properly - formatted C<Last-Modified> header, the file modification time will - be updated accordingly. - - =head2 request - - $response = $http->request($method, $url); - $response = $http->request($method, $url, \%options); - - Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST', - 'PUT', etc.) on the given URL. The URL must have unsafe characters escaped and - international domain names encoded. A hashref of options may be appended to - modify the request. - - Valid options are: - - =over 4 - - =item * - - headers - - A hashref containing headers to include with the request. If the value for - a header is an array reference, the header will be output multiple times with - each value in the array. These headers over-write any default headers. - - =item * - - content - - A scalar to include as the body of the request OR a code reference - that will be called iteratively to produce the body of the response - - =item * - - trailer_callback - - A code reference that will be called if it exists to provide a hashref - of trailing headers (only used with chunked transfer-encoding) - - =item * - - data_callback - - A code reference that will be called for each chunks of the response - body received. - - =back - - If the C<content> option is a code reference, it will be called iteratively - to provide the content body of the request. It should return the empty - string or undef when the iterator is exhausted. - - If the C<data_callback> option is provided, it will be called iteratively until - the entire response body is received. The first argument will be a string - containing a chunk of the response body, the second argument will be the - in-progress response hash reference, as described below. (This allows - customizing the action of the callback based on the C<status> or C<headers> - received prior to the content body.) - - The C<request> method returns a hashref containing the response. The hashref - will have the following keys: - - =over 4 - - =item * - - success - - Boolean indicating whether the operation returned a 2XX status code - - =item * - - status - - The HTTP status code of the response - - =item * - - reason - - The response phrase returned by the server - - =item * - - content - - The body of the response. If the response does not have any content - or if a data callback is provided to consume the response body, - this will be the empty string - - =item * - - headers - - A hashref of header fields. All header field names will be normalized - to be lower case. If a header is repeated, the value will be an arrayref; - it will otherwise be a scalar string containing the value - - =back - - On an exception during the execution of the request, the C<status> field will - contain 599, and the C<content> field will contain the text of the exception. - - =for Pod::Coverage agent - default_headers - max_redirect - max_size - proxy - timeout - - =head1 LIMITATIONS - - HTTP::Tiny is I<conditionally compliant> with the - L<HTTP/1.1 specification|http://www.w3.org/Protocols/rfc2616/rfc2616.html>. - It attempts to meet all "MUST" requirements of the specification, but does not - implement all "SHOULD" requirements. - - Some particular limitations of note include: - - =over - - =item * - - HTTP::Tiny focuses on correct transport. Users are responsible for ensuring - that user-defined headers and content are compliant with the HTTP/1.1 - specification. - - =item * - - Users must ensure that URLs are properly escaped for unsafe characters and that - international domain names are properly encoded to ASCII. See L<URI::Escape>, - L<URI::_punycode> and L<Net::IDN::Encode>. - - =item * - - Redirection is very strict against the specification. Redirection is only - automatic for response codes 301, 302 and 307 if the request method is 'GET' or - 'HEAD'. Response code 303 is always converted into a 'GET' redirection, as - mandated by the specification. There is no automatic support for status 305 - ("Use proxy") redirections. - - =item * - - Persistant connections are not supported. The C<Connection> header will - always be set to C<close>. - - =item * - - Direct C<https> connections are supported only if L<IO::Socket::SSL> is - installed. There is no support for C<https> connections via proxy. - - =item * - - Cookies are not directly supported. Users that set a C<Cookie> header - should also set C<max_redirect> to zero to ensure cookies are not - inappropriately re-transmitted. - - =item * - - Proxy environment variables are not supported. - - =item * - - There is no provision for delaying a request body using an C<Expect> header. - Unexpected C<1XX> responses are silently ignored as per the specification. - - =item * - - Only 'chunked' C<Transfer-Encoding> is supported. - - =item * - - There is no support for a Request-URI of '*' for the 'OPTIONS' request. - - =back - - =head1 SEE ALSO - - =over 4 - - =item * - - L<LWP::UserAgent> - - =back - - =head1 AUTHORS - - =over 4 - - =item * - - Christian Hansen <chansen@cpan.org> - - =item * - - David Golden <dagolden@cpan.org> - - =back - - =head1 COPYRIGHT AND LICENSE - - This software is copyright (c) 2011 by Christian Hansen. - - 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 - HTTP_TINY $fatpacked{"Module/Metadata.pm"} = <<'MODULE_METADATA'; @@ -3756,116 +3591,6 @@ $fatpacked{"Module/Metadata.pm"} = <<'MODULE_METADATA'; 1; - =head1 NAME - - Module::Metadata - Gather package and POD information from perl module files - - =head1 DESCRIPTION - - =over 4 - - =item new_from_file($filename, collect_pod => 1) - - Construct a C<ModuleInfo> object given the path to a file. Takes an optional - argument C<collect_pod> which is a boolean that determines whether - POD data is collected and stored for reference. POD data is not - collected by default. POD headings are always collected. - - =item new_from_module($module, collect_pod => 1, inc => \@dirs) - - Construct a C<ModuleInfo> object given a module or package name. In addition - to accepting the C<collect_pod> argument as described above, this - method accepts a C<inc> argument which is a reference to an array of - of directories to search for the module. If none are given, the - default is @INC. - - =item name() - - Returns the name of the package represented by this module. If there - are more than one packages, it makes a best guess based on the - filename. If it's a script (i.e. not a *.pm) the package name is - 'main'. - - =item version($package) - - Returns the version as defined by the $VERSION variable for the - package as returned by the C<name> method if no arguments are - given. If given the name of a package it will attempt to return the - version of that package if it is specified in the file. - - =item filename() - - Returns the absolute path to the file. - - =item packages_inside() - - Returns a list of packages. - - =item pod_inside() - - Returns a list of POD sections. - - =item contains_pod() - - Returns true if there is any POD in the file. - - =item pod($section) - - Returns the POD data in the given section. - - =item find_module_by_name($module, \@dirs) - - Returns the path to a module given the module or package name. A list - of directories can be passed in as an optional parameter, otherwise - @INC is searched. - - Can be called as either an object or a class method. - - =item find_module_dir_by_name($module, \@dirs) - - Returns the entry in C<@dirs> (or C<@INC> by default) that contains - the module C<$module>. A list of directories can be passed in as an - optional parameter, otherwise @INC is searched. - - Can be called as either an object or a class method. - - =item package_versions_from_directory($dir, \@files?) - - Scans C<$dir> for .pm files (unless C<@files> is given, in which case looks - for those files in C<$dir> - and reads each file for packages and versions, - returning a hashref of the form: - - { - 'Package::Name' => { - version => '0.123', - file => 'Package/Name.pm' - }, - 'OtherPackage::Name' => ... - } - - =item log_info (internal) - - Used internally to perform logging; imported from Log::Contextual if - Log::Contextual has already been loaded, otherwise simply calls warn. - - =back - - =head1 AUTHOR - - Ken Williams <kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org> - - Released as Module::Metadata by Matt S Trout (mst) <mst@shadowcat.co.uk> with - assistance from David Golden (xdg) <dagolden@cpan.org> - - =head1 COPYRIGHT - - Copyright (c) 2001-2011 Ken Williams. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the same terms as Perl itself. - - =cut - MODULE_METADATA $fatpacked{"Parse/CPAN/Meta.pm"} = <<'PARSE_CPAN_META'; @@ -4211,101 +3936,6 @@ $fatpacked{"Parse/CPAN/Meta.pm"} = <<'PARSE_CPAN_META'; __END__
- =pod
-
- =head1 NAME
-
- Parse::CPAN::Meta - Parse META.yml and other similar CPAN metadata files
-
- =head1 SYNOPSIS
-
- #############################################
- # In your file
-
- ---
- rootproperty: blah
- section:
- one: two
- three: four
- Foo: Bar
- empty: ~
-
-
-
- #############################################
- # In your program
-
- use Parse::CPAN::Meta;
-
- # Create a YAML file
- my @yaml = Parse::CPAN::Meta::LoadFile( 'Meta.yml' );
-
- # Reading properties
- my $root = $yaml[0]->{rootproperty};
- my $one = $yaml[0]->{section}->{one};
- my $Foo = $yaml[0]->{section}->{Foo};
-
- =head1 DESCRIPTION
-
- B<Parse::CPAN::Meta> is a parser for F<META.yml> files, based on the
- parser half of L<YAML::Tiny>.
-
- It supports a basic subset of the full YAML specification, enough to
- implement parsing of typical F<META.yml> files, and other similarly simple
- YAML files.
-
- If you need something with more power, move up to a full YAML parser such
- as L<YAML>, L<YAML::Syck> or L<YAML::LibYAML>.
-
- B<Parse::CPAN::Meta> provides a very simply API of only two functions,
- based on the YAML functions of the same name. Wherever possible,
- identical calling semantics are used.
-
- All error reporting is done with exceptions (die'ing).
-
- =head1 FUNCTIONS
-
- For maintenance clarity, no functions are exported.
-
- =head2 Load
-
- my @yaml = Load( $string );
-
- Parses a string containing a valid YAML stream into a list of Perl data
- structures.
-
- =head2 LoadFile
-
- my @yaml = LoadFile( 'META.yml' );
-
- Reads the YAML stream from a file instead of a string.
-
- =head1 SUPPORT
-
- Bugs should be reported via the CPAN bug tracker at
-
- L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Parse-CPAN-Meta>
-
- =head1 AUTHOR
-
- Adam Kennedy E<lt>adamk@cpan.orgE<gt>
-
- =head1 SEE ALSO
-
- L<YAML>, L<YAML::Syck>, L<Config::Tiny>, L<CSS::Tiny>,
- L<http://use.perl.org/~Alias/journal/29427>, L<http://ali.as/>
-
- =head1 COPYRIGHT
-
- Copyright 2006 - 2009 Adam Kennedy.
-
- This program is free software; you can redistribute
- it and/or modify it under the same terms as Perl itself.
-
- The full text of the license can be found in the
- LICENSE file included with this module.
-
- =cut
PARSE_CPAN_META $fatpacked{"lib/core/only.pm"} = <<'LIB_CORE_ONLY'; @@ -4320,89 +3950,6 @@ $fatpacked{"lib/core/only.pm"} = <<'LIB_CORE_ONLY'; return } - =head1 NAME - - lib::core::only - Remove all non-core paths from @INC to avoid site/vendor dirs - - =head1 SYNOPSIS - - use lib::core::only; # now @INC contains only the two core directories - - To get only the core directories plus the ones for the local::lib in scope: - - $ perl -Mlib::core::only -Mlocal::lib=~/perl5 myscript.pl - - To attempt to do a self-contained build (but note this will not reliably - propagate into subprocesses, see the CAVEATS below): - - $ PERL5OPT='-Mlib::core::only -Mlocal::lib=~/perl5' cpan - - =head1 DESCRIPTION - - lib::core::only is simply a shortcut to say "please reduce my @INC to only - the core lib and archlib (architecture-specific lib) directories of this perl". - - You might want to do this to ensure a local::lib contains only the code you - need, or to test an L<App::FatPacker|App::FatPacker> tree, or to avoid known - bad vendor packages. - - You might want to use this to try and install a self-contained tree of perl - modules. Be warned that that probably won't work (see L</CAVEATS>). - - This module was extracted from L<local::lib|local::lib>'s --self-contained - feature, and contains the only part that ever worked. I apologise to anybody - who thought anything else did. - - =head1 CAVEATS - - This does B<not> propagate properly across perl invocations like local::lib's - stuff does. It can't. It's only a module import, so it B<only affects the - specific perl VM instance in which you load and import() it>. - - If you want to cascade it across invocations, you can set the PERL5OPT - environment variable to '-Mlib::core::only' and it'll sort of work. But be - aware that taint mode ignores this, so some modules' build and test code - probably will as well. - - You also need to be aware that perl's command line options are not processed - in order - -I options take effect before -M options, so - - perl -Mlib::core::only -Ilib - - is unlike to do what you want - it's exactly equivalent to: - - perl -Mlib::core::only - - If you want to combine a core-only @INC with additional paths, you need to - add the additional paths using -M options and the L<lib|lib> module: - - perl -Mlib::core::only -Mlib=lib - - # or if you're trying to test compiled code: - - perl -Mlib::core::only -Mblib - - For more information on the impossibility of sanely propagating this across - module builds without help from the build program, see - L<http://www.shadowcat.co.uk/blog/matt-s-trout/tainted-love> - and for ways - to achieve the old --self-contained feature's results, look at - L<App::FatPacker|App::FatPacker>'s tree function, and at - L<App::cpanminus|cpanm>'s --local-lib-contained feature. - - =head1 AUTHOR - - Matt S. Trout <mst@shadowcat.co.uk> - - =head1 LICENSE - - This library is free software under the same terms as perl itself. - - =head1 COPYRIGHT - - (c) 2010 the lib::core::only L</AUTHOR> as specified above. - - =cut - 1; LIB_CORE_ONLY @@ -4488,20 +4035,6 @@ $fatpacked{"local/lib.pm"} = <<'LOCAL_LIB'; } } - =begin testing - - #:: test pipeline - - package local::lib; - - { package Foo; sub foo { -$_[1] } sub bar { $_[1]+2 } sub baz { $_[1]+3 } } - my $foo = bless({}, 'Foo'); - Test::More::ok($foo->${pipeline qw(foo bar baz)}(10) == -15); - - =end testing - - =cut - sub _uniq { my %seen; grep { ! $seen{$_}++ } @_; @@ -4525,25 +4058,6 @@ $fatpacked{"local/lib.pm"} = <<'LOCAL_LIB'; } } - =begin testing - - #:: test classmethod setup - - my $c = 'local::lib'; - - =end testing - - =begin testing - - #:: 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 =~ /^~/); @@ -4585,17 +4099,6 @@ $fatpacked{"local/lib.pm"} = <<'LOCAL_LIB'; $path = File::Spec->rel2abs($path); } - =begin testing - - #:: test classmethod - - local *File::Spec::rel2abs = sub { shift; 'FOO'.shift; }; - is($c->resolve_relative_path('bar'),'FOObar'); - - =end testing - - =cut - sub setup_local_lib_for { my ($class, $path) = @_; $path = $class->ensure_dir_structure_for($path); @@ -4751,505 +4254,6 @@ $fatpacked{"local/lib.pm"} = <<'LOCAL_LIB'; ) } - =begin testing - - #:: test classmethod - - File::Path::rmtree('t/var/splat'); - - $c->ensure_dir_structure_for('t/var/splat'); - - ok(-d 't/var/splat'); - - =end testing - - =encoding utf8 - - =head1 NAME - - local::lib - create and use a local lib/ for perl modules with PERL5LIB - - =head1 SYNOPSIS - - In code - - - use local::lib; # sets up a local lib at ~/perl5 - - 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 PERL_MB_OPT='--install_base /home/username/perl5' - export PERL_MM_OPT='INSTALL_BASE=/home/username/perl5' - export PERL5LIB='/home/username/perl5/lib/perl5/i386-linux:/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. - - 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 - 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 ... - - 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;C:\DOCUME~1\ADMINI~1\perl5\lib\perl5\MSWin32-x86-multi-thread - 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%\temp.bat - ### instead of $(perl -Mlocal::lib=./) - - If you want the environment entries to persist, you'll need to add then 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. - - =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 - - PATH is appended to, rather than clobbered. - - =back - - 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 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, $interpolate - - =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 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_arch_path - - =over 4 - - =item Arguments: $path - - =item Return value: $install_base_arch_path - - =back - - Returns a path describing where to install the architecture-specific Perl - modules for this local library installation. Based on the - L</install_base_perl_path> method's return value, and appends the value of - C<$Config{archname}>. - - =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. Based on the L</install_base_perl_path> method's - return value, and appends the directory C<bin>. - - =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 - - The perl toolchain is unable to handle directory names with spaces in it, - so you cant put your local::lib bootstrap into a directory with spaces. What - 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 - cant update or install CPAN modules after the move. - - 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. - - Bootstrap is a hack and will use CPAN.pm for ExtUtils::MakeMaker even if you - have CPANPLUS installed. - - Kills any existing PERL5LIB, PERL_MM_OPT or PERL_MB_OPT. - - Should probably auto-fixup CPAN config if not already done. - - Patches very much welcome for any of the above. - - 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. - - =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 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>. - - =head1 COPYRIGHT - - Copyright (c) 2007 - 2010 the local::lib L</AUTHOR> and L</CONTRIBUTORS> as - listed above. - - =head1 LICENSE - - This library is free software and may be distributed under the same terms - as perl itself. - - =cut - 1; LOCAL_LIB @@ -6442,6 +5446,7 @@ cpanm - get, unpack build and install modules from CPAN cpanm --installdeps . # install all the deps for the current directory cpanm -L extlib Plack # install Plack and all non-core deps into extlib cpanm --mirror http://cpan.cpantesters.org/ DBI # use the fast-syncing mirror + cpanm --scandeps Moose # See what modules will be installed for Moose =head1 COMMANDS @@ -6602,6 +5607,70 @@ requires custom configuration or Task:: distributions. Defaults to false, and you can say C<--no-interactive> to override when it's set in the default options in C<PERL_CPANM_OPT>. +=item --scandeps + +Scans the depencencies of given modules and output the tree in a text +format. (See C<--format> below for more options) + +Because this command doesn't actually install any distributions, it +will be useful that by typing: + + cpanm --scandeps Catalyst::Runtime + +you can make sure what modules will be installed. + +This command takes into account which modules you already have +installed in your system. If you want to see what modules will be +installed against a vanilla perl installation, you might want to +combine it with C<-L> option. + +=item --format + +Determines what format to display the scanned dependency +tree. Available options are C<tree>, C<json>, C<yaml> and C<dists>. + +=over 8 + +=item tree + +Displays the tree in a plain text format. This is the default value. + +=item json, yaml + +Outputs the tree in a JSON or YAML format. L<JSON> and L<YAML> modules +need to be installed respectively. The output tree is represented as a +recursive tuple of: + + [ distribution, dependencies ] + +and the container is an array containing the root elements. Note that +there may be multiple root nodes, since you can give multiple modules +to the C<--scandeps> command. + +=item dists + +C<dists> is a special output format, where it prints the distribution +filename in the I<depth first order> after the dependency resolution, +like: + + GAAS/MIME-Base64-3.13.tar.gz + GAAS/URI-1.58.tar.gz + PETDANCE/HTML-Tagset-3.20.tar.gz + GAAS/HTML-Parser-3.68.tar.gz + GAAS/libwww-perl-5.837.tar.gz + +which means you can install these distributions in this order without +extra dependencies. When combined with C<-L> option, it will be useful +to replay installations on other machines. + +=back + +=item --save-dists + +Specifies the optional directory path to copy downloaded tarballs in +the CPAN mirror compatible directory structure +i.e. I<authors/id/A/AU/AUTHORS/Foo-Bar-version.tar.gz> + =item --uninst-shadows Uninstalls the shadow files of the distribution that you're @@ -6633,6 +5702,14 @@ cleaned up in one week. You can set the value to C<0> to make cpan never cleanup those directories. +=item --man-pages + +Generates man pages for executables (man1) and libraries (man3). + +Defaults to false (no man pages generated) if +C<-L|--local-lib-contained> option is supplied. Otherwise, defaults to +true, and you can disable it with C<--no-man-pages>. + =item --lwp Uses L<LWP> module to download stuff over HTTP. Defaults to true, and diff --git a/perl-external/dpan_config b/perl-external/dpan_config deleted file mode 100644 index cd0d0b203..000000000 --- a/perl-external/dpan_config +++ /dev/null @@ -1,2 +0,0 @@ -extra_reports_dir extra_reports -skip_dists_regexes common-sense
\ No newline at end of file diff --git a/perl-external/dpan_l4p_config b/perl-external/dpan_l4p_config deleted file mode 100644 index dace9b77f..000000000 --- a/perl-external/dpan_l4p_config +++ /dev/null @@ -1,5 +0,0 @@ -log4perl.rootLogger = DEBUG, Screen - -log4perl.appender.Screen = Log::Log4perl::Appender::Screen -log4perl.appender.Screen.stderr = 0 -log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout diff --git a/perl-external/lib/perl5/local/lib.pm b/perl-external/lib/perl5/local/lib.pm index 65e5365a6..87d186903 100644 --- a/perl-external/lib/perl5/local/lib.pm +++ b/perl-external/lib/perl5/local/lib.pm @@ -11,9 +11,15 @@ use File::Path (); use Carp (); use Config; -our $VERSION = '1.008001'; # 1.8.1 +our $VERSION = '1.008004'; # 1.8.4 -our @KNOWN_FLAGS = qw(--self-contained); +our @KNOWN_FLAGS = qw(--self-contained --deactivate --deactivate-all); + +sub DEACTIVATE_ONE () { 1 } +sub DEACTIVATE_ALL () { 2 } + +sub INTERPOLATE_ENV () { 1 } +sub LITERAL_ENV () { 0 } sub import { my ($class, @args) = @_; @@ -51,8 +57,16 @@ DEATH 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"; } + my $deactivating = 0; + if ($arg_store{deactivate}) { + $deactivating = DEACTIVATE_ONE; + } + if ($arg_store{'deactivate-all'}) { + $deactivating = DEACTIVATE_ALL; + } + $arg_store{path} = $class->resolve_path($arg_store{path}); - $class->setup_local_lib_for($arg_store{path}); + $class->setup_local_lib_for($arg_store{path}, $deactivating); for (@INC) { # Untaint @INC next if ref; # Skip entry if it is an ARRAY, CODE, blessed, etc. @@ -188,13 +202,32 @@ is($c->resolve_relative_path('bar'),'FOObar'); =cut sub setup_local_lib_for { - my ($class, $path) = @_; + my ($class, $path, $deactivating) = @_; + + my $interpolate = LITERAL_ENV; + my @active_lls = $class->active_paths; + $path = $class->ensure_dir_structure_for($path); + + if (! $deactivating) { + if (@active_lls && $active_lls[-1] eq $path) { + exit 0 if $0 eq '-'; + return; # Asked to add what's already at the top of the stack + } elsif (grep { $_ eq $path} @active_lls) { + # Asked to add a dir that's lower in the stack -- so we remove it from + # where it is, and then add it back at the top. + $class->setup_env_hash_for($path, DEACTIVATE_ONE); + # Which means we can no longer output "PERL5LIB=...:$PERL5LIB" stuff + # anymore because we're taking something *out*. + $interpolate = INTERPOLATE_ENV; + } + } + if ($0 eq '-') { - $class->print_environment_vars_for($path); + $class->print_environment_vars_for($path, $deactivating, $interpolate); exit 0; } else { - $class->setup_env_hash_for($path); + $class->setup_env_hash_for($path, $deactivating); @INC = _uniq(split($Config{path_sep}, $ENV{PERL5LIB}), @INC); } } @@ -227,9 +260,6 @@ sub ensure_dir_structure_for { return $path; } -sub INTERPOLATE_ENV () { 1 } -sub LITERAL_ENV () { 0 } - sub guess_shelltype { my $shellbin = 'sh'; if(defined $ENV{'SHELL'}) { @@ -266,13 +296,13 @@ sub guess_shelltype { } sub print_environment_vars_for { - my ($class, $path) = @_; - print $class->environment_vars_string_for($path); + my ($class, $path, $deactivating, $interpolate) = @_; + print $class->environment_vars_string_for($path, $deactivating, $interpolate); } sub environment_vars_string_for { - my ($class, $path) = @_; - my @envs = $class->build_environment_vars_for($path, LITERAL_ENV); + my ($class, $path, $deactivating, $interpolate) = @_; + my @envs = $class->build_environment_vars_for($path, $deactivating, $interpolate); my $out = ''; # rather basic csh detection, goes on the assumption that something won't @@ -285,7 +315,7 @@ sub environment_vars_string_for { while (@envs) { my ($name, $value) = (shift(@envs), shift(@envs)); - $value =~ s/(\\")/\\$1/g; + $value =~ s/(\\")/\\$1/g if defined $value; $out .= $class->${\"build_${shelltype}_env_declaration"}($name, $value); } return $out; @@ -297,31 +327,51 @@ sub environment_vars_string_for { sub build_bourne_env_declaration { my $class = shift; my($name, $value) = @_; - return qq{export ${name}="${value}"\n}; + return defined($value) ? qq{export ${name}="${value}";\n} : qq{unset ${name};\n}; } sub build_csh_env_declaration { my $class = shift; my($name, $value) = @_; - return qq{setenv ${name} "${value}"\n}; + return defined($value) ? qq{setenv ${name} "${value}"\n} : qq{unsetenv ${name}\n}; } sub build_win32_env_declaration { my $class = shift; my($name, $value) = @_; - return qq{set ${name}=${value}\n}; + return defined($value) ? qq{set ${name}=${value}\n} : qq{set ${name}=\n}; } sub setup_env_hash_for { - my ($class, $path) = @_; - my %envs = $class->build_environment_vars_for($path, INTERPOLATE_ENV); + my ($class, $path, $deactivating) = @_; + my %envs = $class->build_environment_vars_for($path, $deactivating, INTERPOLATE_ENV); @ENV{keys %envs} = values %envs; } sub build_environment_vars_for { + my ($class, $path, $deactivating, $interpolate) = @_; + + if ($deactivating == DEACTIVATE_ONE) { + return $class->build_deactivate_environment_vars_for($path, $interpolate); + } elsif ($deactivating == DEACTIVATE_ALL) { + return $class->build_deact_all_environment_vars_for($path, $interpolate); + } else { + return $class->build_activate_environment_vars_for($path, $interpolate); + } +} + +sub build_activate_environment_vars_for { my ($class, $path, $interpolate) = @_; return ( - PERL_LOCAL_LIB_ROOT => $path, + PERL_LOCAL_LIB_ROOT => join($Config{path_sep}, + (($ENV{PERL_LOCAL_LIB_ROOT}||()) ? + ($interpolate == INTERPOLATE_ENV + ? ($ENV{PERL_LOCAL_LIB_ROOT}||()) + : (($^O ne 'MSWin32') ? '$PERL_LOCAL_LIB_ROOT' + : '%PERL_LOCAL_LIB_ROOT%' )) + : ()), + $path + ), PERL_MB_OPT => "--install_base ${path}", PERL_MM_OPT => "INSTALL_BASE=${path}", PERL5LIB => join($Config{path_sep}, @@ -342,6 +392,94 @@ sub build_environment_vars_for { ) } +sub active_paths { + my ($class) = @_; + + return () unless defined $ENV{PERL_LOCAL_LIB_ROOT}; + return split /\Q$Config{path_sep}/, $ENV{PERL_LOCAL_LIB_ROOT}; +} + +sub build_deactivate_environment_vars_for { + my ($class, $path, $interpolate) = @_; + + my @active_lls = $class->active_paths; + + if (!grep { $_ eq $path } @active_lls) { + warn "Tried to deactivate inactive local::lib '$path'\n"; + return (); + } + + my @new_ll_root = grep { $_ ne $path } @active_lls; + my @new_perl5lib = grep { + $_ ne $class->install_base_arch_path($path) && + $_ ne $class->install_base_perl_path($path) + } split /\Q$Config{path_sep}/, $ENV{PERL5LIB}; + + my %env = ( + PERL_LOCAL_LIB_ROOT => (@new_ll_root ? + join($Config{path_sep}, @new_ll_root) : undef + ), + PERL5LIB => (@new_perl5lib ? + join($Config{path_sep}, @new_perl5lib) : undef + ), + PATH => join($Config{path_sep}, + grep { $_ ne $class->install_base_bin_path($path) } + split /\Q$Config{path_sep}/, $ENV{PATH} + ), + ); + + # If removing ourselves from the "top of the stack", set install paths to + # correspond with the new top of stack. + if ($active_lls[-1] eq $path) { + if (@active_lls > 1) { + my $new_top = $active_lls[-2]; + %env = (%env, + PERL_MB_OPT => "--install_base ${new_top}", + PERL_MM_OPT => "INSTALL_BASE=${new_top}", + ); + } else { + %env = (%env, + PERL_MB_OPT => undef, + PERL_MM_OPT => undef, + ); + } + } + + return %env; +} + +sub build_deact_all_environment_vars_for { + my ($class, $path, $interpolate) = @_; + + my @active_lls = $class->active_paths; + + my @new_perl5lib = split /\Q$Config{path_sep}/, $ENV{PERL5LIB}; + my @new_path = split /\Q$Config{path_sep}/, $ENV{PATH}; + + for my $path (@active_lls) { + @new_perl5lib = grep { + $_ ne $class->install_base_arch_path($path) && + $_ ne $class->install_base_perl_path($path) + } @new_perl5lib; + + @new_path = grep { + $_ ne $class->install_base_bin_path($path) + } @new_path; + } + + my %env = ( + PERL_LOCAL_LIB_ROOT => undef, + PERL_MM_OPT => undef, + PERL_MB_OPT => undef, + PERL5LIB => (@new_perl5lib ? + join($Config{path_sep}, @new_perl5lib) : undef + ), + PATH => join($Config{path_sep}, @new_path), + ); + + return %env; +} + =begin testing #:: test classmethod @@ -463,6 +601,22 @@ installation to install modules in different directories directly this way: 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<< @@ -565,6 +719,22 @@ 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. + =head1 METHODS =head2 ensure_dir_structure_for @@ -619,6 +789,19 @@ given path as the base directory. 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. + =head2 install_base_perl_path =over 4 @@ -829,6 +1012,9 @@ 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>. + =head1 COPYRIGHT Copyright (c) 2007 - 2010 the local::lib L</AUTHOR> and L</CONTRIBUTORS> as |