cpanfile000644001750001750 203314465441602 15177 0ustar00gugodgugod000000000000App-perlbrew-0.98# Always requires the latest for this two. requires 'CPAN::Perl::Releases' => '5.20230720'; requires 'Devel::PatchPerl' => '2.08'; requires 'Capture::Tiny' => '0.48'; requires 'Pod::Usage' => '1.69'; requires 'File::Copy' => '0'; requires 'File::Temp' => '0.2304'; requires 'JSON::PP' => '0'; requires 'local::lib' => '2.000014'; requires 'ExtUtils::MakeMaker' => '7.22'; on test => sub { requires 'File::Temp' => '0.2304'; requires 'File::Which' => '1.21'; requires 'IO::All' => '0.51'; requires 'Path::Class' => '0.33'; requires 'Test::Exception' => '0.32'; requires 'Test::More' => '1.001002'; requires 'Test::NoWarnings' => '1.04'; requires 'Test::Output' => '1.03'; requires 'Test::Simple' => '1.001002'; requires 'Test::Spec' => '0.49'; requires 'Test::TempDir::Tiny' => '0.016'; }; on develop => sub { requires 'Pod::Markdown' => '2.002'; }; 11.editdist.t000644001750001750 53114465441602 16135 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use App::Perlbrew::Util qw< editdist >; is editdist(qw/Joe Jim/), 2; is editdist(qw/Jack Jill/), 3; is editdist(qw/Jim Jimmy/), 2; is editdist(qw/superman supergirl/), 4; is editdist(qw/supercalifragilisticexpyalligocious superman/), 29; is editdist(qw/foo bar/), 3; done_testing; command-compgen.t000644001750001750 476714465441602 17207 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; use Test::Output qw( stdout_from ); $ENV{PERLBREW_DEBUG_COMPLETION} = 0; my @perls = qw( perl-5.12.3 perl-5.12.4 perl-5.14.1 perl-5.14.2 ); mock_perlbrew_install($_) for @perls; { no warnings 'redefine'; sub App::perlbrew::current_perl { "perl-5.12.3" } } describe "compgen command," => sub { describe "when there is no args", sub { it "displays a list of subcommands", sub { my $app = App::perlbrew->new("compgen"); my $out = stdout_from { $app->run; }; my @subcommands = sort split ' ', $out; is join(' ', @subcommands), join(' ', sort $app->commands()); }; }; describe "when there is a part of a subcommand", sub { it "displays a list of l*", sub { my $part = "l"; my $app = App::perlbrew->new("compgen", 1, 'perlbrew', $part); my $out = stdout_from { $app->run; }; my @subcommands = sort split ' ', $out; is join(' ', @subcommands), join(' ', sort grep { /\A \Q$part\E /xms } $app->commands()); }; it "'versio[tab]' is completed as 'version'", sub { my $part = "versio"; my $app = App::perlbrew->new("compgen", 1, 'perlbrew', $part); my $out = stdout_from { $app->run; }; my @subcommands = sort split ' ', $out; is join(' ', @subcommands), join(' ', 'version'); }; }; foreach my $use(qw(use switch)) { describe "given '$use' subcommand", sub { it "'use [tab]' suggests a list of installed perls", sub { my $app = App::perlbrew->new( "compgen", 2, 'perlbrew', 'use'); my $out = stdout_from { $app->run; }; my @subcommands = sort split ' ', $out; is join(' ', @subcommands), join(' ', sort @perls); }; it "'use 5.12 [tab]' suggests perls with /5\\.12/", sub { my $app = App::perlbrew->new( "compgen", 2, 'perlbrew', 'use', '5.12'); my $out = stdout_from { $app->run; }; my @subcommands = sort split ' ', $out; is join(' ', @subcommands), join(' ', sort( qw(perl-5.12.3 perl-5.12.4) )); }; }; } }; runtests unless caller; command-lib.t000644001750001750 1163614465441602 16336 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse strict; use warnings; use FindBin; use lib $FindBin::Bin; use Test::Spec; use Test::Output; use Test::Exception; use App::perlbrew; require "test_helpers.pl"; mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.14.2"); mock_perlbrew_install("perl-5.14.3"); describe "lib command," => sub { describe "when invoked with unknown action name,", sub { it "should display error" => sub { my $x = "correcthorsebatterystaple"; my $app = App::perlbrew->new("lib", $x); stdout_like { eval { $app->run; 1; } or do { print STDERR $@; }; } qr/Unknown command: $x/; } }; describe "without lib name" => sub { it "create errs gracefully showing usage" => sub { my $app = App::perlbrew->new; throws_ok { $app->{args} = [ "lib", "create"]; $app->run; } qr/ERROR: /i; }; it "delte errs gracefully showing usage" => sub { my $app = App::perlbrew->new; throws_ok { $app->{args} = [ "lib", "delete"]; $app->run; } qr/ERROR: /i; }; }; describe "`create` sub-command," => sub { my ($app, $libdir); before each => sub { $app = App::perlbrew->new; $app->expects("current_perl")->returns("perl-5.14.2")->at_least_once; $libdir = App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.14.2@nobita'); }; after each => sub { $libdir->rmpath; }; describe "with a bare lib name," => sub { it "creates the lib folder for current perl" => sub { stdout_is { $app->{args} = [ "lib", "create", "nobita" ]; $app->run; } qq{lib 'perl-5.14.2\@nobita' is created.\n}; ok -d $libdir; }; }; describe "with \@ in the beginning of lib name," => sub { it "creates the lib folder for current perl" => sub { stdout_is { $app->{args} = [ "lib", "create", '@nobita' ]; $app->run; } qq{lib 'perl-5.14.2\@nobita' is created.\n}; ok -d $libdir; } }; describe "with perl name and \@ as part of lib name," => sub { it "creates the lib folder for the specified perl" => sub { stdout_is { $app->{args} = [ "lib", "create", 'perl-5.14.2@nobita' ]; $app->run; } qq{lib 'perl-5.14.2\@nobita' is created.\n}; ok -d $libdir; }; it "creates the lib folder for the specified perl" => sub { stdout_is { $app->{args} = [ "lib", "create", 'perl-5.14.1@nobita' ]; $app->run; } qq{lib 'perl-5.14.1\@nobita' is created.\n}; $libdir = App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.14.1@nobita'); ok -d $libdir; }; it "shows errors if the specified perl does not exist." => sub { throws_ok { ## perl-5.8.8 is not mock-installed $app->{args} = [ "lib", "create", 'perl-5.8.8@nobita' ]; $app->run; } qr{^ERROR: 'perl-5.8.8' is not installed yet, 'perl-5.8.8\@nobita' cannot be created.\n}; $libdir = App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.8.8@nobita'); ok !-d $libdir; }; }; }; describe "`delete` sub-command," => sub { before each => sub { App::Perlbrew::Path ->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.14.2@nobita') ->mkpath ; }; it "deletes the local::lib folder" => sub { stdout_is { my $app = App::perlbrew->new("lib", "delete", "nobita"); $app->expects("current_perl")->returns("perl-5.14.2")->at_least_once; $app->run; } qq{lib 'perl-5.14.2\@nobita' is deleted.\n}; ok !-d App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.14.2@nobita'); ok !-e App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.14.2@nobita'); }; it "shows errors when the given lib does not exists " => sub { throws_ok { my $app = App::perlbrew->new("lib", "delete", "yoga"); $app->expects("current_perl")->returns("perl-5.14.2")->at_least_once; $app->run; } qr{^ERROR: 'perl-5\.14\.2\@yoga' does not exist\.}; }; }; }; runtests unless caller; current_perl.t000644001750001750 250114465441602 16627 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::Spec; mock_perlbrew_install("perl-5.12.3"); mock_perlbrew_install("perl-5.12.4"); mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.14.2"); describe "current perl" => sub { it "is decided from env var PERLBREW_PERL" => sub { for my $v (qw(perl-5.12.3 perl-5.12.3 perl-5.14.1 perl-5.14.2)) { local $ENV{PERLBREW_PERL} = $v; my $app = App::perlbrew->new; is $app->current_perl, $v; } }; it "can be decided from object attribute, which overrides env var." => sub { local $ENV{PERLBREW_PERL} = "perl-5.12.3"; for my $v (qw(perl-5.12.3 perl-5.12.3 perl-5.14.1 perl-5.14.2)) { my $app = App::perlbrew->new; $app->{current_perl} = $v; is $app->current_perl, $v; } }; it "can be set with current_perl method." => sub { local $ENV{PERLBREW_PERL} = "perl-5.12.3"; for my $v (qw(perl-5.12.3 perl-5.12.3 perl-5.14.1 perl-5.14.2)) { my $app = App::perlbrew->new; is $app->current_perl, "perl-5.12.3"; $app->current_perl($v); is $app->current_perl, $v; } }; }; runtests unless caller; 01.options.t000644001750001750 204614465441602 16041 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use Test::More tests => 12; use App::perlbrew; my $app = App::perlbrew->new('install', '-n', 'perl-5.12.1', '-Dusethreads', '-DDEBUGGING', '-Uusemymalloc', '-Accflags'); note explain($app) if (main->can('note') && main->can('explain')); is join(' ', $app->args), join(' ', qw(install perl-5.12.1)); is_deeply $app->{D}, [qw(usethreads DEBUGGING)], '-D'; is_deeply $app->{U}, [qw(usemymalloc)], '-U'; is_deeply $app->{A}, [qw(ccflags)], '-A'; ok !$app->{quiet}, 'not quiet'; ok $app->{notest}, 'notest'; $app = App::perlbrew->new('install', '--quiet', 'perl-5.12.1', '-D', 'usethreads', '-D=DEBUGGING', '-U', 'usemymalloc', '-A', 'ccflags'); note explain($app) if (main->can('note') && main->can('explain')); is join(' ', $app->args), join(' ', qw(install perl-5.12.1)); is_deeply $app->{D}, [qw(usethreads DEBUGGING)], '-D'; is_deeply $app->{U}, [qw(usemymalloc)], '-U'; is_deeply $app->{A}, [qw(ccflags)], '-A'; ok $app->{quiet}, 'quiet'; ok !$app->{notest}, 'notest'; test_helpers.pl000644001750001750 446314465441602 17005 0ustar00gugodgugod000000000000App-perlbrew-0.98/t=begin yada yada Copy this snippet to the beginning of tests: use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; tldr: This file should be `require`-ed after the "use App::perlbrew;" statement in the test. It is meant to override subroutines for testing purposes and not mess up developer's own perlbrew environment. `FindBin` should be used to put 't/' dir to `@INC`. =cut use strict; use Test::More; use IO::All; use File::Temp qw( tempdir ); sub dir { App::Perlbrew::Path->new(@_); } sub file { App::Perlbrew::Path->new(@_); } $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; delete $ENV{PERLBREW_LIB}; delete $ENV{PERLBREW_PERL}; delete $ENV{PERLBREW_PATH}; delete $ENV{PERLBREW_MANPATH}; delete $ENV{PERL_LOCAL_LIB_ROOT}; my $root = App::Perlbrew::Path::Root->new ($ENV{PERLBREW_ROOT}); $root->perls->mkpath; $root->build->mkpath; $root->dists->mkpath; no warnings 'redefine'; sub App::perlbrew::do_install_release { my ($self, $name) = @_; $name = $self->{as} if $self->{as}; my $root = $self->root; my $installation_dir = $root->perls ($name); $self->{installation_name} = $name; $installation_dir->mkpath; $root->perls($name, "bin")->mkpath; my $perl = $root->perls ($name, "bin")->child ("perl"); io($perl)->print(<<'CODE'); #!/usr/bin/env perl use File::Basename; my $name = basename(dirname(dirname($0))), "\n"; $name =~ s/^perl-//; my ($a,$b,$c) = split /\./, $name; printf('%d.%03d%03d' . "\n", $a, $b, $c); CODE chmod 0755, $perl; note "(mock) installed $name to $installation_dir"; } sub mock_perlbrew_install { my ($name, @args) = @_; App::perlbrew->new(install => $name, @args)->run(); } sub mock_perlbrew_off { mock_perlbrew_use(""); } sub mock_perlbrew_use { my ($name) = @_; my %env = App::perlbrew->new()->perlbrew_env($name); for my $k (qw< PERLBREW_PERL PERLBREW_LIB PERLBREW_PATH PERL5LIB >) { if (defined $env{$k}) { $ENV{$k} = $env{$k}; } else { delete $ENV{$k} } } } sub mock_perlbrew_lib_create { my $name = shift; App::Perlbrew::Path->new($App::perlbrew::PERLBREW_HOME, "libs", $name)->mkpath; } 1; Util.pm000644001750001750 435614465441602 20030 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrewpackage App::Perlbrew::Util; use strict; use warnings; use 5.008; use Exporter 'import'; our @EXPORT = qw( uniq min editdist files_are_the_same perl_version_to_integer ); our @EXPORT_OK = qw( find_similar_tokens ); sub uniq { my %seen; grep { !$seen{$_}++ } @_; } sub min(@) { my $m = $_[0]; for(@_) { $m = $_ if $_ < $m; } return $m; } # straight copy of Wikipedia's "Levenshtein Distance" sub editdist { my @a = split //, shift; my @b = split //, shift; # There is an extra row and column in the matrix. This is the # distance from the empty string to a substring of the target. my @d; $d[$_][0] = $_ for (0 .. @a); $d[0][$_] = $_ for (0 .. @b); for my $i (1 .. @a) { for my $j (1 .. @b) { $d[$i][$j] = ($a[$i-1] eq $b[$j-1] ? $d[$i-1][$j-1] : 1 + min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1])); } } return $d[@a][@b]; } sub files_are_the_same { ## Check dev and inode num. Not useful on Win32. ## The for loop should always return false on Win32, as a result. my @files = @_; my @stats = map {[ stat($_) ]} @files; my $stats0 = join " ", @{$stats[0]}[0,1]; for (@stats) { return 0 if ((! defined($_->[1])) || $_->[1] == 0); unless ($stats0 eq join(" ", $_->[0], $_->[1])) { return 0; } } return 1 } sub perl_version_to_integer { my $version = shift; my @v; if ($version eq 'blead') { @v = (999,999,999); } else { @v = split(/[\.\-_]/, $version); } return undef if @v < 2; if ($v[1] <= 5) { $v[2] ||= 0; $v[3] = 0; } else { $v[3] ||= $v[1] >= 6 ? 9 : 0; $v[3] =~ s/[^0-9]//g; } return $v[1]*1000000 + $v[2]*1000 + $v[3]; } sub find_similar_tokens { my ($token, $tokens) = @_; my $SIMILAR_DISTANCE = 6; my @similar_tokens = sort { $a->[1] <=> $b->[1] } map { my $d = editdist( $_, $token ); ( ( $d < $SIMILAR_DISTANCE ) ? [$_, $d] : () ) } @$tokens; if (@similar_tokens) { my $best_score = $similar_tokens[0][1]; @similar_tokens = map { $_->[0] } grep { $_->[1] == $best_score } @similar_tokens; } return \@similar_tokens; } 1; http-ua-detect-non-curl.t000644001750001750 136414465441602 20514 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin qw($Bin); BEGIN { $ENV{PATH} = "$Bin/fake-bin:" . $ENV{PATH}; } use File::Which qw(which); use App::Perlbrew::HTTP qw(http_user_agent_program); use Test::More; chmod 0755, "$Bin/fake-bin/curl"; diag "PATH=$ENV{PATH}"; my $curl_path = which("curl"); diag "curl = $curl_path"; is $curl_path, "$Bin/fake-bin/curl"; my $expected_ua; if (which("wget")) { $expected_ua = "wget"; } elsif (which("fetch")) { $expected_ua = "fetch"; } if ($expected_ua) { my $detected_ua = http_user_agent_program(); is $detected_ua, $expected_ua, "UA: $detected_ua"; } else { pass("Neither wget nor fetch can be found. This test requers at least one of them to be there."); } done_testing; Path.pm000644001750001750 417614465441602 20007 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrewuse strict; use warnings; package App::Perlbrew::Path; use File::Basename (); use File::Glob (); use File::Path (); use overload ( '""' => \& stringify, fallback => 1, ); sub _joinpath { for my $entry (@_) { no warnings 'uninitialized'; die 'Received an undefined entry as a parameter (all parameters are: '. join(', ', @_). ')' unless (defined($entry)); } return join "/", @_; } sub _child { my ($self, $package, @path) = @_; $package->new($self->{path}, @path); } sub _children { my ($self, $package) = @_; map { $package->new($_) } File::Glob::bsd_glob($self->child("*")); } sub new { my ($class, @path) = @_; bless { path => _joinpath (@path) }, $class; } sub exists { my ($self) = @_; -e $self->stringify; } sub basename { my ($self, $suffix) = @_; return scalar File::Basename::fileparse($self, ($suffix) x!! defined $suffix); } sub child { my ($self, @path) = @_; return $self->_child(__PACKAGE__, @path); } sub children { my ($self) = @_; return $self->_children(__PACKAGE__); } sub dirname { my ($self) = @_; return App::Perlbrew::Path->new( File::Basename::dirname($self) ); } sub mkpath { my ($self) = @_; File::Path::mkpath( [$self->stringify], 0, 0777 ); return $self; } sub readlink { my ($self) = @_; my $link = CORE::readlink( $self->stringify ); $link = __PACKAGE__->new($link) if defined $link; return $link; } sub rmpath { my ($self) = @_; File::Path::rmtree( [$self->stringify], 0, 0 ); return $self; } sub stringify { my ($self) = @_; return $self->{path}; } sub stringify_with_tilde { my ($self) = @_; my $path = $self->stringify; my $home = $ENV{HOME}; $path =~ s!\Q$home/\E!~/! if $home; return $path; } sub symlink { my ($self, $destination, $force) = @_; $destination = App::Perlbrew::Path->new($destination) unless ref $destination; CORE::unlink($destination) if $force && (-e $destination || -l $destination); $destination if CORE::symlink($self, $destination); } sub unlink { my ($self) = @_; CORE::unlink($self); } 1; Installations.pm000644001750001750 103014465441602 22615 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrew/Pathuse strict; use warnings; package App::Perlbrew::Path::Installations; require App::Perlbrew::Path; require App::Perlbrew::Path::Installation; our @ISA = qw( App::Perlbrew::Path ); sub child { my ($self, @params) = @_; my $return = $self; $return = $return->_child('App::Perlbrew::Path::Installation' => shift @params) if @params; $return = $return->child(@params) if @params; $return; } sub children { shift->_children('App::Perlbrew::Path::Installation' => @_); } sub list { shift->children; } 1; 15.no-reuse-build-dir.t000644001750001750 154014465441602 17757 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse strict; use warnings; use Test::More tests => 6; use File::Basename qw(basename); use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; my $pb = new_ok('App::perlbrew'); my $test_dir = App::Perlbrew::Path->new ($pb->root, qw/build test/); my $test_file = App::Perlbrew::Path->new ( $test_dir, 3 ); $test_dir->mkpath; open my $out, '>', $test_file or die "Couldn't create $test_file: $!"; ok -e $test_file, 'Test file 3 created'; my $extracted_dir = $pb->do_extract_tarball( App::Perlbrew::Path->new ($FindBin::Bin, 'test.tar.gz') ); diag $extracted_dir; is $extracted_dir->basename => 'test', 'Test tarball extracted as expected'; ok !-e $test_file, 'Test file 3 was unlinked by tar'; ok -e App::Perlbrew::Path->new ( $extracted_dir, $_ ), "Test file $_ exists" for 1..2; 08.error_install_blead.t000644001750001750 117114465441602 20361 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Exception; use App::perlbrew; { no warnings 'redefine'; sub App::perlbrew::http_download { return "ERROR" } } throws_ok( sub { my $app = App::perlbrew->new("install", "perl-blead"); $app->run; }, qr[ERROR: Failed to download https://.+/blead\.tar\.gz] ); throws_ok( sub { my $app = App::perlbrew->new("install", "blead"); $app->run; }, qr[ERROR: Failed to download https://.+/blead\.tar\.gz] ); done_testing; test.tar.gz000644001750001750 22114465441602 16021 0ustar00gugodgugod000000000000App-perlbrew-0.98/tQQ1 A en:39"6n;`墐B&x1I.ݸQ͛j=v5ޥnkt^>T#7m\4'rouM.(README000644001750001750 1371414465441602 14403 0ustar00gugodgugod000000000000App-perlbrew-0.98NAME App::perlbrew - Manage perl installations in your $HOME SYNOPSIS # Installation curl -L https://install.perlbrew.pl | bash # Initialize perlbrew init # See what is available perlbrew available # Install some Perls perlbrew install 5.32.1 perlbrew install perl-5.28.3 perlbrew install perl-5.33.6 # See what were installed perlbrew list # Swith to an installation and set it as default perlbrew switch perl-5.32.1 # Temporarily use another version only in current shell. perlbrew use perl-5.28.3 perl -v # Turn it off and go back to the system perl. perlbrew off # Turn it back on with 'switch', or 'use' perlbrew switch perl-5.32.1 perlbrew use perl-5.32.1 # Exec something with all perlbrew-ed perls perlbrew exec -- perl -E 'say $]' DESCRIPTION perlbrew is a program to automate the building and installation of perl in an easy way. It provides multiple isolated perl environments, and a mechanism for you to switch between them. Everything are installed unter ~/perl5/perlbrew. You then need to include a bashrc/cshrc provided by perlbrew to tweak the PATH for you. You then can benefit from not having to run sudo commands to install cpan modules because those are installed inside your HOME too. For the documentation of perlbrew usage see perlbrew command on MetaCPAN , or by running perlbrew help, or by visiting perlbrew's official website . The following documentation features the API of App::perlbrew module, and may not be remotely close to what your want to read. INSTALLATION It is the simplest to use the perlbrew installer, just paste this statement to your terminal: curl -L https://install.perlbrew.pl | bash Or this one, if you have fetch (default on FreeBSD): fetch -o- https://install.perlbrew.pl | sh After that, perlbrew installs itself to ~/perl5/perlbrew/bin, and you should follow the instruction on screen to modify your shell rc file to put it in your PATH. The installed perlbrew command is a standalone executable that can be run with system perl. The minimum required version of system perl is 5.8.0, which should be good enough for most of the OSes these days. A fat-packed version of patchperl is also installed to ~/perl5/perlbrew/bin, which is required to build old perls. The directory ~/perl5/perlbrew will contain all install perl executables, libraries, documentations, lib, site_libs. In the documentation, that directory is referred as perlbrew root. If you need to set it to somewhere else because, say, your HOME has limited quota, you can do that by setting PERLBREW_ROOT environment variable before running the installer: export PERLBREW_ROOT=/opt/perl5 curl -L https://install.perlbrew.pl | bash As a result, different users on the same machine can all share the same perlbrew root directory (although only original user that made the installation would have the permission to perform perl installations.) You may also install perlbrew from CPAN: cpan App::perlbrew In this case, the perlbrew command is installed as /usr/bin/perlbrew or /usr/local/bin/perlbrew or others, depending on the location of your system perl installation. Please make sure not to run this with one of the perls brewed with perlbrew. It's the best to turn perlbrew off before you run that, if you're upgrading. perlbrew off cpan App::perlbrew You should always use system cpan (like /usr/bin/cpan) to install App::perlbrew because it will be installed under a system PATH like /usr/bin, which is not affected by perlbrew switch or use command. The self-upgrade command will not upgrade the perlbrew installed by cpan command, but it is also easy to upgrade perlbrew by running cpan App::perlbrew again. PROJECT DEVELOPMENT perlbrew project uses github https://github.com/gugod/App-perlbrew/issues for issue tracking. Issues sent to these two systems will eventually be reviewed and handled. To participate, you need a github account. Please briefly read the short instructions about how to get your work released to CPAN: https://github.com/gugod/App-perlbrew/blob/develop/CONTRIBUTING.md AUTHOR Kang-min Liu COPYRIGHT Copyright (c) 2023 Kang-min Liu . LICENCE The MIT License DISCLAIMER OF WARRANTY BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 00.load.t000644001750001750 15014465441602 15236 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use Test::More tests => 1; use lib qw(lib); use_ok('App::perlbrew'); command-install-cpanm.t000644001750001750 157114465441602 20307 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/cpanm$/, "GET cpanm url: $url"; return "#!/usr/bin/env perl\n# The content of cpanm"; } } describe "App::perlbrew->install_cpanm" => sub { it "should produce 'cpanm' in the bin dir" => sub { my $app = App::perlbrew->new("install-cpanm", "-q"); $app->run(); my $cpanm = App::Perlbrew::Path->new ($perlbrew_root, "bin", "cpanm"); ok -f $cpanm, "cpanm is produced. $cpanm"; ok -x $cpanm, "cpanm should be an executable."; }; }; runtests unless caller; 02.format_perl_version.t000644001750001750 127214465441602 20426 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use English qw( -no_match_vars ); use Test::More; use App::perlbrew; use Test::NoWarnings; my @test_cases = ( { raw => q{5.008008}, parsed => q{5.8.8}, }, { raw => q{5.010001}, parsed => q{5.10.1}, }, { raw => q{5.012002}, parsed => q{5.12.2}, }, { raw => q{5.008}, parsed => q{5.8.0}, }, ); plan tests => scalar @test_cases + 1; { my $app = App::perlbrew->new(); TEST: foreach my $test (@test_cases) { is( $app->format_perl_version( $test->{raw} ), $test->{parsed}, "$test->{raw} -> $test->{parsed}" ); } } 19.find_similar_commands.t000644001750001750 145414465441602 20702 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use warnings; use Test::More; use App::perlbrew; use File::Temp qw( tempdir ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); my $app = App::perlbrew->new; diag join ", ", sort $app->commands; subtest "exact result", sub { my @commands = $app->find_similar_commands( "install" ); is 0+@commands, 1; is $commands[0], "install"; }; subtest "one result", sub { my @commands = $app->find_similar_commands( "instali" ); is 0+@commands, 1; is $commands[0], "install"; }; subtest "two result", sub { my @commands = $app->find_similar_commands( "install-cpam" ); is 0+@commands, 2; is $commands[0], "install-cpanm"; is $commands[1], "install-cpm"; }; done_testing; installation-perlbrew.t000644001750001750 552414465441602 20454 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Capture::Tiny qw( capture_stdout ); note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; subtest "`perlbrew self-install` initialize the required dir structure under PERLBREW_ROOT", sub { my $app = App::perlbrew->new('--quiet', 'self-install'); $app->run; ok -d dir($ENV{PERLBREW_ROOT}, "bin"); ok -d dir($ENV{PERLBREW_ROOT}, "etc"); ok -d dir($ENV{PERLBREW_ROOT}, "perls"); ok -d dir($ENV{PERLBREW_ROOT}, "dists"); ok -d dir($ENV{PERLBREW_ROOT}, "build"); ok -f file($ENV{PERLBREW_ROOT}, "bin", "perlbrew"); ok -f file($ENV{PERLBREW_ROOT}, "etc", "bashrc"); ok -f file($ENV{PERLBREW_ROOT}, "etc", "cshrc"); ok -f file($ENV{PERLBREW_ROOT}, "etc", "csh_reinit"); ok -f file($ENV{PERLBREW_ROOT}, "etc", "csh_set_path"); ok -f file($ENV{PERLBREW_ROOT}, "etc", "csh_wrapper"); }; subtest "Works with bash", sub { if ($ENV{PERLBREW_SHELLRC_VERSION}) { plan skip_all => "PERLBREW_SHELLRC_VERSION is defined, thus this subtest makes little sense."; return; } my $out = capture_stdout { my $app = App::perlbrew->new('self-install'); $app->current_shell("bash"); $app->run; }; like($out, qr| export PERLBREW_HOME=\S+|); like($out, qr| source \S+/etc/bashrc|); }; subtest "Works with fish", sub { if ($ENV{PERLBREW_SHELLRC_VERSION}) { plan skip_all => "PERLBREW_SHELLRC_VERSION is defined, thus this subtest makes little sense."; return; } my $out = capture_stdout { my $app = App::perlbrew->new('self-install'); $app->current_shell("fish"); $app->run; }; like($out, qr| set -x PERLBREW_HOME \S+|); like($out, qr| . \S+/etc/perlbrew.fish|); }; subtest "Works with zsh", sub { if ($ENV{PERLBREW_SHELLRC_VERSION}) { plan skip_all => "PERLBREW_SHELLRC_VERSION is defined, thus this subtest makes little sense."; return; } my $out = capture_stdout { my $app = App::perlbrew->new('self-install'); $app->current_shell("zsh4"); $app->run; }; like($out, qr| export PERLBREW_HOME=\S+|); like($out, qr| source \S+/etc/bashrc|); }; subtest "Exports PERLBREW_HOME when needed", sub { if ($ENV{PERLBREW_SHELLRC_VERSION}) { plan skip_all => "PERLBREW_SHELLRC_VERSION is defined, thus this subtest makes little sense."; return; } my $out = capture_stdout { local $App::perlbrew::PERLBREW_HOME = App::Perlbrew::Path->new ($ENV{HOME}, ".perlbrew"); my $app = App::perlbrew->new('self-install'); $app->current_shell("bash"); $app->run; }; unlike($out, qr|PERLBREW_HOME=\S+|); like($out, qr| source \S+/etc/bashrc|); }; done_testing; 13.perl_release.t000644001750001750 301414465441602 17007 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; use CPAN::Perl::Releases; use JSON::PP qw(encode_json); describe "App::perlbrew#perl_release method" => sub { describe "given a valid perl version" => sub { it "returns the perl dist tarball file name, and its download url" => sub { my $app = App::perlbrew->new; for my $version (qw(5.14.2 5.10.1 5.10.0 5.004_05)) { my ($ball, $url) = $app->perl_release($version); like $ball, qr/perl-?${version}.tar.(bz2|gz)/; like $url, qr/${ball}$/; } }; }; describe "when the given versionis not found is CPAN::Perl::Releases" => sub { no warnings 'redefine'; my $version = "5.14.2"; my $orig_sub = \&CPAN::Perl::Releases::perl_tarballs; *App::perlbrew::http_get = sub { return encode_json({hits => {hits => [{_source => {download_url => "https://cpan.metacpan.org/authors/id/SOMEONE/perl-${version}.tar.gz"} }]}}); }; *CPAN::Perl::Releases::perl_tarballs = sub {}; my $app = App::perlbrew->new; my ($ball, $url) = $app->perl_release($version); like $ball, qr/^perl-?${version}.tar.(bz2|gz)$/, $ball; like $url, qr#^https?://cpan\.metacpan\.org/authors/id/SOMEONE/${ball}$#, $url; *CPAN::Perl::Releases::perl_tarballs = $orig_sub; }; }; runtests unless caller; Root.pm000644001750001750 104614465441602 20723 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrew/Pathuse strict; use warnings; package App::Perlbrew::Path::Root; use App::Perlbrew::Path (); use App::Perlbrew::Path::Installations (); our @ISA = qw( App::Perlbrew::Path ); sub bin { shift->child(bin => @_); } sub build { shift->child(build => @_); } sub dists { shift->child(dists => @_); } sub etc { shift->child(etc => @_); } sub perls { my ($self, @params) = @_; my $return = $self->_child('App::Perlbrew::Path::Installations', 'perls'); $return = $return->child(@params) if @params; return $return; } 1; 06.installed_perls.t000644001750001750 102314465441602 17531 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use App::perlbrew; my $app = App::perlbrew->new(); my @perls = $app->installed_perls; unless(@perls) { plan skip_all => "No perl installation under PERLBREW_ROOT"; exit; } for my $perl (@perls) { is ref($perl), 'HASH'; ok defined $perl->{name}, "Name: $perl->{name}"; ok defined $perl->{version}, "Version: $perl->{version}"; ok defined $perl->{is_current}, "Current?: " . ($perl->{is_current} ? "true" : "false"); } done_testing; curl000644001750001750 23414465441602 16263 0ustar00gugodgugod000000000000App-perlbrew-0.98/t/fake-bin#!/bin/sh exit 127 # This fake curl script is created to avoid # App::perlbrew::http_user_agent_program() from selecting "curl" as # the http ua program. unit-files-are-the-same.t000644001750001750 75614465441602 20442 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use Test::More; use App::Perlbrew::Util qw(files_are_the_same); use FindBin qw($RealBin); my @test_files = (<$RealBin/*.t>)[0..9]; for my $i (0..$#test_files) { my $t = $test_files[$i]; my $u = $test_files[$i - 1]; my $should_be_same = files_are_the_same($t, $t); my $should_not_be_same = files_are_the_same($t, $u); ok ($^O eq 'MSWin32' xor $should_be_same); # should return false on win32 ok !$should_not_be_same; } done_testing; do_system.t000644001750001750 104614465441602 16134 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More tests => 2; # test that 'do_system' wraps 'system' correctly our @system; BEGIN { *CORE::GLOBAL::system = sub { @system = @_; }; } use App::perlbrew; # don't actually run() it, we just want to call do_system my $app = App::perlbrew->new('list'); $app->do_system(qw(perl -E), 'say 42'); is_deeply \@system, [qw(perl -E), 'say 42'], 'passed all arguments to system()'; $app->do_system("perl -e 'say 42'"); is_deeply \@system, ["perl -e 'say 42'"], 'passed single string to system()'; LICENSE000644001750001750 224114465441602 14501 0ustar00gugodgugod000000000000App-perlbrew-0.98This software is Copyright (c) 2023 by Kang-min Liu C<< >>. This is free software, licensed under: The MIT (X11) License The MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. util-find-similar-tokens.t000644001750001750 144514465441602 20763 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse strict; use warnings; use Test::More tests => 3; use App::Perlbrew::Util qw( find_similar_tokens ); my @tokens = ( "apple", "pie", "orange", "tree", "maple", "leaves", ); subtest "exact result", sub { my $similar_tokens = find_similar_tokens( "orange", \@tokens ); is 0+@$similar_tokens, 1; is $similar_tokens->[0], "orange"; }; subtest "one result", sub { my $similar_tokens = find_similar_tokens( "appli", \@tokens ); is 0+@$similar_tokens, 1; is $similar_tokens->[0], "apple"; }; subtest "two results", sub { my $similar_tokens = find_similar_tokens( "aple", \@tokens ); is 0+@$similar_tokens, 2; @$similar_tokens = sort @$similar_tokens; is $similar_tokens->[0], "apple"; is $similar_tokens->[1], "maple"; }; done_testing; HTTP.pm000644001750001750 744514465441602 17674 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrewpackage App::Perlbrew::HTTP; use strict; use warnings; use 5.008; use Exporter 'import'; our @EXPORT_OK = qw(http_user_agent_program http_user_agent_command http_get http_download); our $HTTP_VERBOSE = 0; our $HTTP_USER_AGENT_PROGRAM; my %commands = ( curl => { test => '--version >/dev/null 2>&1', get => '--silent --location --fail -o - {url}', download => '--silent --location --fail -o {output} {url}', order => 1, # Exit code is 22 on 404s etc die_on_error => sub { die 'Page not retrieved; HTTP error code 400 or above.' if ($_[ 0 ] >> 8 == 22); }, }, wget => { test => '--version >/dev/null 2>&1', get => '--quiet -O - {url}', download => '--quiet -O {output} {url}', order => 2, # Exit code is not 0 on error die_on_error => sub { die 'Page not retrieved: fetch failed.' if ($_[ 0 ]); }, }, fetch => { test => '--version >/dev/null 2>&1', get => '-o - {url}', download => '-o {output} {url}', order => 3, # Exit code is 8 on 404s etc die_on_error => sub { die 'Server issued an error response.' if ($_[ 0 ] >> 8 == 8); }, } ); sub http_user_agent_program { $HTTP_USER_AGENT_PROGRAM ||= do { my $program; for my $p (sort {$commands{$a}{order}<=>$commands{$b}{order}} keys %commands) { my $code = system("$p $commands{$p}->{test}") >> 8; if ($code != 127) { $program = $p; last; } } unless ($program) { die "[ERROR] Cannot find a proper http user agent program. Please install curl or wget.\n"; } $program; }; die "[ERROR] Unrecognized http user agent program: $HTTP_USER_AGENT_PROGRAM. It can only be one of: ".join(",", keys %commands)."\n" unless $commands{$HTTP_USER_AGENT_PROGRAM}; return $HTTP_USER_AGENT_PROGRAM; } sub http_user_agent_command { my ($purpose, $params) = @_; my $ua = http_user_agent_program; my $cmd = $commands{ $ua }->{ $purpose }; for (keys %$params) { $cmd =~ s!{$_}!\Q$params->{$_}\E!g; } if ($HTTP_VERBOSE) { unless ($ua eq "fetch") { $cmd =~ s/(silent|quiet)/verbose/; } } $cmd = $ua . " " . $cmd; return ($ua, $cmd) if wantarray; return $cmd; } sub http_download { my ($url, $path) = @_; if (-e $path) { die "ERROR: The download target < $path > already exists.\n"; } my $partial = 0; local $SIG{TERM} = local $SIG{INT} = sub { $partial++ }; my $download_command = http_user_agent_command(download => { url => $url, output => $path }); my $status = system($download_command); if ($partial) { $path->unlink; return "ERROR: Interrupted."; } unless ($status == 0) { $path->unlink; if ($? == -1) { return "ERROR: Failed to execute the command\n\n\t$download_command\n\nReason:\n\n\t$!"; } elsif ($? & 127) { return "ERROR: The command died with signal " . ($? & 127) . "\n\n\t$download_command\n\n"; } else { return "ERROR: The command finished with error\n\n\t$download_command\n\nExit code:\n\n\t" . ($? >> 8); } } return 0; } sub http_get { my ($url, $header, $cb) = @_; if (ref($header) eq 'CODE') { $cb = $header; $header = undef; } my ($program, $command) = http_user_agent_command(get => { url => $url }); open my $fh, '-|', $command or die "open() pipe for '$command': $!"; local $/; my $body = <$fh>; close $fh; # check if the download has failed and die automatically $commands{ $program }{ die_on_error }->($?); return $cb ? $cb->($body) : $body; } 1; Changes000644001750001750 6117414465441602 15021 0ustar00gugodgugod000000000000App-perlbrew-0.980.98 - Released at 2023-08-11T22:54:38+0900 - Remove the support of cperl from `available` and `install` command. Github PR: #777. cperl can still be installed by specifying the tarball, just not by their short names. - new command: make-shim - new command: make-pp. 0.97 - Released at 2023-05-12T22:33:42+0900 - Thanks to our contributors: Elvin Aslanov, Graham Knop, Shoichi Kaji, Tomasz Konojacki, brian greenfield - The documentation of `clone-module` and `list-modules` are improved. - No longer depends on Pod::Parser. Github PR #760 - Bugfix for csh users: Github PR #770 0.96 - Released at 2022-07-31T15:42:39+0900 - Thanks to our contributors: Rolf Stöckli - `install-cpm` is now properly documented. Thanks to Tekki. - Let `install` hint for `init` when PERLBREW_ROOT does not exist. .RT #57669. - Reveal the actual error code of curl/wget etc. Github issue #748. 0.95 - Released at 2022-05-15T22:59:11+0800 - Thanks to our contributors: Leon Timmermans - Now we use metacpan api for fetching perl versions and for downloading. Github PR #743 - `--verbose` flag now also enable verbosity of underlying curl/wget commands. Github PR #740. - Avoid perl test errors when NO_COLOR is set. Github PR #738 0.94 - Released at 2021-12-05T08:39:16+0900 - Let `self-upgrade` print version numbers when doing upgrades. Github issue #678. 0.93 - Released at 2021-11-22T23:09:25+0900 - Let `clone-modules` takes just one arguments and mean 'cloning modules from that perl'. - Let `list-modules` and `clone-modules` map certain output to their representative module name. Github issue #722 - `exec` command now takes aliases explicitly specified in `--with` args and run commands with those aliases -- even if that would run the same thing twice. Github issue #725 0.92 - Released at 2021-04-15T23:53:55+0900 - Thanks to our contributors: chee - Fix a message mentioning fish config. GitHub PR #712 - Fetch cperl releases from https://github.com/perl11/cperl/releases instead - Let `clone-modules` command accept `--notest` and skip running module tests 0.91 - Released at 2021-01-31T17:10:27+0900 - Fix META info included in 0.90. No other feature changes. 0.90 - Released at 2021-01-29T09:43:17+0900 - Thanks to our contributors: Mose Schmiedel, gucchisk - The output of 'available' command is split into sections of different type of distributions. Github issue #646. - Let the output of `perlbrew -h` be the short usage. Github issue #647 - Unbreak env script for fish users. GitHub PR #698 and #708 - Prefer https URLs of www.cpan.org 0.89 - Released at 2020-10-19T09:26:19+0900 - Thanks to our contributors: Håkon Hægland, Nicolas R, Peter Tripp - Make the bashrc compatible with 'bash -u'. Github PR #694 - Prevent build directory from being overwritten. Github PR #683 0.88 - Released at 2020-01-29T21:40:07+0900 - Thanks to our contributors: Dave Rolsky, Gil Magno, Zhu Sheng Li - `install` command now shows errors message from http_downlod. Github PR #681. - Fix: The .tar.bz2 suffix are removed from the output ouf `available` PR #685 0.87 - Released at 2019-10-25T22:55:40+0900 - Thanks to our contributors: Branislav Zahradník, Christopher Chavez, Jon Jacobson, Konstantin S. Uvarin, Pali, Shoichi Kaji, Tomasz Konojacki, jkjacobson, rage311 - Use the new official repo url for fetching perl blead. Github issue #677 - Add `--min` and `--max` options to `exec` command. Github PR #656 - Fix "ERROR: Cannot find the tarball for perl-$version". Github PR #669 - Fix calling patchperl on readonly files. Github PR #674 - Fix installation from local tarbal files. See https://rt.cpan.org/Ticket/Display.html?id=129871 - Internal refactoring. Github PR #667, #662 - Various corrections of documentation. Github PR #676, #660 0.86 - Released at 2019-01-19T09:39:55+0900 - Thanks to our contributors: Olaf Alders, Paul Cochrane - Fix an error from 'install' command. https://rt.cpan.org/Public/Bug/Display.html?id=128083 - Tweak the separater characters of 'exec' command: See https://github.com/gugod/App-perlbrew/issues/648 0.85 - Released at 2018-12-15T23:24:15+0900 - Thanks to our contributors: Branislav Zahradník, Guido Flohr, Joelle Maslak, Luca Ferrari, rage311 - Fix the behaviour of 'clone-modules' - Various internal refactoring 0.84 - Released at 2018-06-24T08:26:14+0900 - Thanks to our contributors: Joelle Maslak - Unbreak 'available' command after some updates from cpan.org web site. - Unbreak the installation -- which missed "perlbrew" command due to a mistake when using mbtiny. 0.83 - Released at 2018-05-30T08:04:43+0900 - Thanks to our contributors: Alceu Rodrigues de Freitas Junior, Dan Book, Luca Ferrari, María Inés Parnisari, Mohammad S Anwar, Shoichi Kaji, sylints - my respect to search.cpan.org - MAKE env var can now be used to specify the "make" program. - New command: install-cpm - "install" command now has a "--builddir" option for specifying a work directory - "list" command now takes "--verbose" option. - "clone-modules" command is now better documented. 0.82 - Released at 2017-12-17T09:53:00+0900 - Thanks to our contributors: Alceu Rodrigues de Freitas Junior, Paul Cochrane - Fix regression of 'perlbrew install blead' 0.81 - Released at 2017-12-09T15:12:04+0900 - Thanks to our contributors: Luca Ferrari, Zac Bentley, perlancar, Nicolas R, gregor herrmann, Paul Cochrane - New command: clone-modules - Recognize tarball in .tar.xz extension - The output of "availables" is now sorted by versions - Unbreak the integration with cperl releases - Make `perlbrew install` runs correctly on AIX - support the current perl blead (5.28) 0.80 - Released at 2017-06-30T07:40:45+0200 - Fix version in META.yml in CPAN distribution. See: https://rt.cpan.org/Public/Bug/Display.html?id=122279 0.79 - Released at 2017-06-25T23:40:45+0200 - deal with perl-5.26 change about @INC in Makefile.PL - "available" command now also shows the URLs 0.78 - Released at 2016-11-20T22:59:55+0100 - Thanks to our contributors: Manuel Streuhofer, Sergey Aleynikov - More fixes to accomodate changes on perl5.git.perl.org 0.77 - Released at 2016-11-12T06:42:45+0100 - Thanks to our contributors: Dennis Kaarsemaker, Roel Harbers - The "uninstall" command now requires confirmation. - Fix bug with csh when PATH entries contain spaces - Accommodate git commit abbrivation changes on perl5.git.perl.org. See GH #524 https://github.com/gugod/App-perlbrew/pull/524 0.76 - Released at 2016-06-21T23:02:44+0200 - Start supporting cperl installation. - cperl releases are sourced from: https://github.com/perl11/cperl/releases - Deal with a regex warning when testing perlbrew with perl-5.25. See RT: https://rt.cpan.org/Ticket/Display.html?id=114871 0.75 - Released at 2016-03-16T23:41:41+0100 - Thanks to our contributors: Dave Cross, Dean Hamstead, Mark J. Reed, Mohammed El-Afifi, - Add '--no-patchperl' install option for skip running patchperl. - Add '--destdir' install option. - "uninstall" command now also delete associated libs. - "mirror" command is removed. - "config" command is removed. 0.74 - Released at 2015-11-24T20:55:02+0100 - A big thanks for our contributers: Aristotle Pagaltzis, Dave Jacoby, Dylan Cali, John Krull, Kevin Johnson, Nathan Day, Paul Cochrane, Tudor Constantin, Yanick Champoux, tm604 - support PERLBREW_LIB_PREFIX. https://github.com/gugod/App-perlbrew/commit/c29813cd4633683bd049964178a9ac96647986bc - prefer https and remove insecure download cli flags. https://github.com/gugod/App-perlbrew/commit/f49a908c1702942006de4654107edf77a48ead52 - perlbrew now dies when switching to/use a lib that does not exist. https://github.com/gugod/App-perlbrew/issues/432 - RHEL vendorlib fix https://github.com/gugod/App-perlbrew/issues/409 - improvements with fish integration. - unbreak when running with perl 5.14 or earlier: "list" command now correctly display lib names. - retaining flags in upgrade-perl. https://github.com/gugod/App-perlbrew/commit/b8d466670bbfc8e214a9d3ff2e889a4860060d84 - variour document clean up and improvements. 0.73 - Released at 2015-02-01T09:59:45+0100 - fixes and improvements from Manuel Streuhofer, Aristotle Pagaltzis, Sebastian Willert, David Hand, Eric Enns, Peter Roberts, Thomas Sibley, Ivan Baidakou, thanks! - fix 'perlbrew user' for fish users https://github.com/gugod/App-perlbrew/pull/429 - fix sub-shell for bash users https://github.com/gugod/App-perlbrew/pull/435 - clarify the 'perlbrew use' output: https://github.com/gugod/App-perlbrew/issues/439 0.72 - Released at 2014-10-27T21:38:19+0100 - Fix 0.71 breakage on MacOSX when the shell is bash or zsh - Fix spelling mistake. by @gregoa++ 0.71 - Released at 2014-09-13T19:59:15+0200 - Fix a few bugs of having unwanted values in PERL5LIB when switching between libs 0.70 - Released at 2014-09-02T20:41:15+0900 - download the fatpacked perlbrew from an http:// url. - protect fatpacked perlbrew from PERL5LIB, thanks to dagolden++ - avoid several warnings, thanks to DabeDotCom++ - making perlbrew a bit friendlier to init.d script, thanks to maxhq++ . see also https://github.com/gugod/App-perlbrew/pull/404 - make it possible to override PERLBREWURL before invoking installers 0.69 - Released at 2014-06-10T23:32:05+0200 - fix 'perlbrew env' breakage by just avoiding bad local::lib versions. 0.68 - Released at 2014-06-07T15:08:00+0200 - disable SSL cert checks. GH #385. - "perlbrew download stable" works as on expects. GH #383 - Many fish shell fixes. GH #376 #378 #379 - make 5.21 installable. GH #396 - various documentation fixes. 0.67 - Released at 2013-11-20T08:40:52+0100 - Support fish shell. Thanks to @yenzie++ - `info` command now takes an optional module name and show information for it. Thanks to @trcjr++ - doc/bug fixes from @mmcclimon++, @mperry2++, and markstos++ 0.66 - Released at 2013-08-03T00:22:29+0200 - fix a bug the made download failed with curl program. 0.65 - Released at 2013-08-01T07:19:03+0200 - exec command: error hadndling improvements. Thanks to @vsespb. - install command: add "--clang" option. Thanks to @salva - various bug fixes. thanks to @ironcamel and @gottreu 0.64 - Released at 2013-06-02T09:44:59+0200 - The build directory is removed before a new build. - New command: `install-multiple` - `clean` command now also removes tarballs - `install` command has many extra convienent flags. - Use "http://www.cpan.org" as the default CPAN mirror instead of "http://search.cpan.org/CPAN" - Remove the --insecure/--no-check-certificate command bflags when invoking curl/wget. 0.63 - Released at 2013-05-06T16:53:48+0200 - Remove `install-ack` command. - Due to the new architecture of ack2, it does not make sense to install the standalone executable anymore. Thus it's better not to do the installation with perlbrew. - Fix the `use` and `switch` command when switching between binary incompatible perl installations. See GH #297 0.62 - Released at 2013-04-07T17:43:58+0800 - Fix `list-modules` under lib env. It lists all modules in the lib, and in the base. - Use the original grep command to prevent aliases from breaking the content of init. GH #307 - `perlbrew alias help` is now the same as `perlbrew help alias` - `perlbrew exec --with ...` now preserve the order of specified names. 0.61 - Fix bashrc on various OS/shell. See GH #302 0.60 - Released at 2013-03-17T21:44:12+0100 - Exit status handling in bash function. See ed29288ab50a15d7df86d69cfcbddf108674eb07 for more details. - Fix compatibility with recent local::lib version. - Delay the loading of server modules. - Fix warnings when runing `perlbrew off` 0.59 - Released at 2013-02-17T12:34:10+0100 - New feature: "perlbrew install --switch $perl" - New feature: "perlbrew install stable" - Fix "--quiet" options for "exec" command - Fix mulitple test failures and warnings 0.58 - Released at 2012-11-16T08:45:18+0100 - Fix infinite re-exec loop as identified in #263 - Fix a case where PERL5LIB still contains previous entries after deactivating or activating other ones. 0.57 - Released at 2012-11-13T19:57:03+0100 - Fix an infinite re-exec loop 0.56 - Released at 2012-11-11T23:10:30+0100 - Fix GH #261, which breaks `off` and `swich-off` commands. 0.55 - Revert the requirement of 5.8.8. Now require 5.8 - Add PERLBREW_CPAN_MIRROR environment variable - Deal with a minor local::lib path problem. See GH #254. 0.54 - Released at 2012-10-24T21:21:25+0200 - Now requires perl 5.8.8 - Fix an issue with list-module command listing extra modules See GH #245 - Tweak default Configure options for pre-5.6 versions - Fix an issue with warning messagse in 'upgrade-perl' command. 0.53 - Released at 2012-10-14T17:41:17+0200 - New command: `info`. - requires CPAN::Perl::Releases 0.76 for 5.14.3 info. - Skip "." in @INC to deal with a `list-module` issue. GH #245. - Environment variable cleanups and minor bashrc rewrite. 0.52 - Released at 2012-10-04T21:30:40+0200 - userelocatableinc is no longer default. Meanwhile PERLBREW_CONFIGURE_FLAGS can still be used. - Fix GH #197 again. Also make sure perlbrew-unrelated PERL5LIB values are preserved. - Fix an issue that MANPATH contains unwanted values even after switch/use/off. 0.51 - Released at 2012-09-29T09:17:14+0200 - Fix a start-up warning message from bashrc when perlbrew is not active - Fix a breakage on CentOS due to the use of `manpath` command. 0.50 - Released at 2012-09-01T11:25:41+0200 - properly remove perlbrew-related PERL5LIB entries. GH #197 - minor documentation tweak. 0.49 - Released at 2012-08-25T22:32:22+0200 - Fix the build for perl-5.12 and 5.14 -- userelocatableinc are not working properly. https://github.com/gugod/App-perlbrew/issues/232 0.48 - Released at 2012-08-24T07:07:52+0200 - The build log output "build.log" is now named after the installation name for easier reference. - Fix the invokation configure command to actually contains -Duserelocatableinc - Experimental: bash/zsh users may put this to shell init instead: eval "$(~/perl5/perlbrew/bin/perlbrew init -)" - A few output message updates 0.47 - Released at 2012-08-23T07:59:53+0200 - New command: download. - New env var: PERLBREW_CONFIGURE_FLAGS - userelocatableinc is enabled by default when the installing perl version is greater than or equals to 5.8.9. It should make some use cases easier. In particular, you can move PERLBREW_ROOT directory to another place. - fix https://github.com/gugod/App-perlbrew/issues/216 for bash users and zsh users 0.46 - fix: The deprecation warning when running `self-upgrde` - fix: system MANPATH detection - improvement: Specifying multiple perl: `exec --with perl-5.14.2,perl-5.16.0` 0.45 - New command: install-ack . This install the standalone version of ack under $PERLBREW_ROOT/bin - New command: list-modules - `exec` command now also iterates thourgh all the libs - Documented the `--with` argument of exec command. See `perlbrew help exec` 0.44 - Notice: "self-install" command now alters the shebang to use system perl - Notice: "install-patchperl" command now alters the shebang to use system perl. - some documentation tweaks - fix: `perlbrew use` to/from a lib has not been working properly. 0.43 - cpantester-error fixes - csh support. Big thanks to matzsoft. - support 'fetch' command on FreeBSD. - Fix a bug that perlbrew failed to resolve version number when dist path contain "perl5" 0.42 - Improvement: die when running perlbrew (use|switch) with unknown installation name. - clean 'build.log' on install. ref: RT #69168. 0.41 - Fix installation issue when the specified version is not listed in CPAN::Perl::Releases - Fix sub-shell invocation for 'switch' and 'use' command. This is particularly for csh users, but it should also work for bash users. 0.40 - Make the stanalone perlbrew program smaller by using Perl::Strip - use CPAN::Perl::Releases to decide the location of perl tarball -- less HTTP hits - Prefer $PERLBREW_ROOT/bin/patchperl if it is there. 0.39 - Fix GH #179. lib naming are more consistent. - Fix GH #171. bash users are suggestted to upgrad to this version. - Fix GH #152. 0.38 - fix deps 0.37 - fix ENV mess after switching to diffirent libs multiple times - add --sitecustomize option 0.36 - fix test errors on freebsd that makes it uninstallable 0.35 - fixes for cpantester failures - requiers local::lib version 1.008 0.34 - Fix: remove duplicated items from the output of `perlbrew list`. - New Command: self-install. - This is actually renamed from an undocumented command `install-perlbrew` - Plus it gets documented. - Provide aditional bash completion control helper commands. - Documentation fixes / typo corrections. - alter MANPATHs, see GH #173 - Allow the representation like '@lib' te mean "a lib name under current perl.". See GH #153 0.33 - Remove Text::Levenshtein from the standalone executable. - Rearrange documentation so all perlbrew command usage document can be found in `perldoc perlbrew` - In the future, App::perlbrew POD should only contain the API doc for the module. 0.32 - A hotfix release: local::lib was not bundled in the previous release. 0.31 - NOTICE: Remove $PERLBREW_ROOT/Conf.pm if it's there, and re-run `perlbrew mirror` - perlbrew help system is changing. `perlbrew help ` now displays brief documentation for the command. - Add a global `--root` argument for all commands that can be used as a quick alternative to set PERLBREW_ROOT env var. - Avoid display paths to external/system perl in the output of `perlbrew list` - Replace Text::Levenshtein with a minimal implementation -- the standalone executable get to be smaller. 0.30 - New command: lib - local::lib integration is done with this command. - New command: install-patchperl - skip runs of 'exec' on aliases https://github.com/gugod/App-perlbrew/pull/135 - Respect -f flag when installing to replace an already installed perl. - Redefine the default value of -q flag to be false, and define it's meaning to be "complete silent" 0.29 - The installer now honors $TMPDIR (RT #70850) - Fixd GH #108. `perlbrew use` has a fallback for users that does not use bash/csh -compitable shell. - Deprecate the command 'perlbrew use system' simply use 'perlbrew off' or 'perlbrew switch-off' instead. - Deprecate the special case of `perlbrew use /path/to/bin/perl` and `perlbrew switch /path/to/bin/perl - perlbrew no longer cast magic to external perls. But there will be an alternative. 0.28 - fixes for cpantester - Fix 'switch' and 'use' for bash users, by Woody2143++ - The standalone `perlbrew` file is now packed with fatpacker, by running `dev-bin/build.sh`. `perl Makefile.PL` does no trigger a re-build anymore. - Update the installer to grab patchperl 0.46 0.27 - Hotfix for `perlbrew install` command 0.26 - Fix GH #119 - Fix t/08.exit_status.t for cpantesters - Fix several bugs in `exec` command - Implement GH #103 - install -v shows build.log - Add -Dusedevel when installing blead perl 0.25 - suggest when user types wrong commands. hoelzro++ - Improvements about self-upgrade by hoelzro++ - exit with non-zero status code when there's some sort of error. by punytan++ - Added verification of existing alias before attempting unalias. johncm++ - Fix `install-cpanm` for due to a recent github cert update. kanetann++ 0.24 - Done GH #92 -- Show error messages on network errors. - Fix GH #82 -- deduplicate items in PATH for the `list` command. - Tests for various commands and methods. 0.23 - dependency fixes - Fix auto-detection of curl - Support OpenBSD pdksh. The provided bashrc should be compatible with pdksh. - Small improvement of 'exec' command. `perlbrew exec perl -v` now works. 0.22 - Fix ccache support on Linux with bash.. GH #87. - `install` command no longer clobbers existing installations. - New commands: uninstall, alias, self-upgrade - See more on http://perlbrew.pl/Release-0.22.html 0.21 - oylenshpeegul++ Let version numbers alone mean installation names. For example, 5.12.3 means perl-5.12.3 - audreyt++ fixed `perlbrew install ` that might installs to a wrong path. - Fix RT #68241 - Improve `perlbrew list` command output - Improve `perlbrew install` command. Now it takes a local .tar.gz filename - See more detail in http://perlbrew.pl/Release-0.21.html 0.20 - For more detail release note, see https://github.com/gugod/App-perlbrew/wiki/Relesae-0.20 - doherty++ FIX: stop when user specified an invalid perl version that cannot be found on cpan. - doherty++ specialized version installation: perlbrew install perl-blead / - am0c++ FIX: `perlbrew intsall /path/to/git/src/dir` 0.19 - Auto run 'perlbrew init' after an install (or upgrade) - Symlink dev versions of executables. For example,'perl5.13.11' to 'perl', 'prove5.13.11' to 'prove'. - Automatically apply patches necessary to make older perls build again on modern platforms with the help of Devel::PatchPerl. - A command "perlbrew available" to list recently available perls to build by trcjr 0.18 - Spotted and fixed by chad.a.davis++, an issue when bash set "noclobber" option, which breaks the creation of ~/.perlbrew/init. See https://rt.cpan.org/Ticket/Display.html?id=66518 - A simple `perlbrew clean` command to clean build dir. - delegate `-j` arg value to `make test_harness`. by dagolden++ - $HOME is replaced with "~" in many messages. https://rt.cpan.org/Ticket/Display.html?id=57668 0.17 - UPDATE NOTES: you need to init, off and switch back to the version you want; - Fix "perlbrew use" to work even if we are switched to a specific version - Fix "perlbrew env" to use current version, sets PERLBREW_PERL and proper PATH - Feature: "perlbrew use" shows current version in use - Feature: "perlbrew switch /path/to/special/perl name-of-special-perl" names for adhoc perl's - 'perlbrew exec' now excludes those non-brewed perl by frankcuny++ according to the discussion here: https://github.com/gugod/App-perlbrew/pull/43 0.16 - Use 'test_harness' for perl >= 5.7.3. avar++ - Use gtar on Solaris - RT #61042. doherty++ - Fix "perlbrew -f switch" by dalinaum++ 0.15 - DEPRECATE and REMOVE 'perlbrew installed' command. - Intrudoce a 'perlbrew exec' command - 'perlbrew use system' can be used to locally turn off perlbrew. yibe++ 0.14 - DEPRECATE `get_current_perl` function. Use `current_perl` instead - Show versions of non-perlbrew perls in the output of `perlbrew list`. Thanks to trcjr++ - bashrc fixes from yibe++ - Let help, -h and --help do the same thing -- showing full pod. 0.13 - 'installed' command is renamed to 'list', and will be deprecated soon. - Requires curl or wget from now -- to fetch https URLs. polettix++ 0.12 - Fix: missing init file generation. 0.11 - Avoid warning messages. Thanks Anno Siegel for the bug report and patch. - `-A` arguments are passed thru, thanks to gfx++. - Unbreak tests for older perls with older Test::Simple. Thanks to zaphod42++ - Better bash Integration, no more 'hash -r' - New command for bash and zsh: 'perlbrew use' - Deprecating 'installed'. use 'list' instead. 0.10 - Use File::Path::Tiny to avoid the api incompatibility of File::Path. - yanick++ and castaway++ fixes docmentation - gfx++ made it accept -Dopt style flags as Perl Configurate does. - (Danijel Tasov)++ added '-n' option -- no test! - xsawyerx++ fixes RT #57672, #60123, and GH #9 - Fixes #59729 0.09 - Use the proxy set in $ENV{http_proxy} if available. - Bypasses '-U' option to to configure. Thanks to chromatic++ 0.08 - Conf file + CPAN mirror support - Strip invalid dependency lines out of the makefile in older perl versions, to make them work with newer gcc versions - Add rudimentary pure-perl introspection, jrockway++ - Documentation, castaway++ 0.07 - Document about PERLBREW_ROOT and the issue installing it with CPAN. - Handle an edge case whn the tarball is not found on the http server. Thanks to sekimura++ - Improves 'switch' and 'off' command message. Thanks to Justin Davis. - PERL5OPT PERL5LIB are removed while configuring and testing a new perl. Thanks to Andrew Rodland. - fix a expression precedence bug. Thanks to Jesse Luehrs. 0.06 - Fix -as option. Thanks to doy++ and jasonmay++ 0.05 - Now it brews from git. jasonmay++ - Fix the uses of mkpath on various versions of perls. - Support the building of 5.13, and future developement versions 0.04 - Use File::Path::mkpath instead of make_path to make in runnable with older versions of Perl - a few document typo fixes. 0.03 - Fixed a bug that switch fail after 'off' 0.02 - Officially prepare a standalone program for quick download. - The 'installed' command now also lists all the 'perl' found in your PATH - The 'switch' command can take an executable like /usr/bin/perl - Various program options by Chris Prather - Fixes from Tatsuhiko Miyagawa 0.01 - First release. Installs perl-5.11.[12345] on my mac. 16.release-detail.t000644001750001750 163714465441602 17241 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use App::perlbrew; use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; use Test::More; subtest 'parse "perl-5.18.2"' => sub { my $app = App::perlbrew->new(); my $rd = $app->release_detail("perl-5.18.2"); ok defined( $rd->{type} ); ok defined( $rd->{version} ); ok defined( $rd->{tarball_url} ); ok defined( $rd->{tarball_name} ); is $rd->{type}, "perl"; is $rd->{version}, "5.18.2"; }; subtest 'parse "5.18.2"' => sub { my $app = App::perlbrew->new(); my $rd = $app->release_detail("5.18.2"); ok defined( $rd->{type} ); ok defined( $rd->{version} ); ok defined( $rd->{tarball_url} ); ok defined( $rd->{tarball_name} ); is $rd->{type}, "perl"; is $rd->{version}, "5.18.2"; }; done_testing; MANIFEST000644001750001750 364114465441602 14632 0ustar00gugodgugod000000000000App-perlbrew-0.98.perltidyrc Build.PL CONTRIBUTING.md Changes LICENSE MANIFEST META.json META.yml README cpanfile lib/App/Perlbrew/HTTP.pm lib/App/Perlbrew/Path.pm lib/App/Perlbrew/Path/Installation.pm lib/App/Perlbrew/Path/Installations.pm lib/App/Perlbrew/Path/Root.pm lib/App/Perlbrew/Util.pm lib/App/perlbrew.pm script/perlbrew t/00.load.t t/01.options.t t/02.format_perl_version.t t/03.test_get_available_versions.t t/04.find_available_perls.t t/05.get_current_perl.t t/06.installed_perls.t t/07.argv.t t/08.error_available.t t/08.error_install.t t/08.error_install_blead.t t/08.error_install_cpanm.t t/08.error_install_cpm.t t/09.exit_status.t t/10.resolve.t t/11.editdist.t t/11.root_from_arg.t t/12.destdir.t t/12.sitecustomize.t t/13.perl_release.t t/14.perl_version_parsing.t t/15.no-reuse-build-dir.t t/16.release-detail.t t/18.release-detail-perl-local.t t/18.release-detail-perl-remote.t t/19.find_similar_commands.t t/app-perlbrew-path-installation.t t/app-perlbrew-path.t t/bashrc_content.t t/builddir.t t/command-alias.t t/command-available.t t/command-clone-modules.t t/command-compgen.t t/command-display-rc.t t/command-env.t t/command-exec.t t/command-help.t t/command-info.t t/command-install-cpanm.t t/command-install-cpm.t t/command-install-from-archive.t t/command-install-patchperl.t t/command-install.t t/command-lib.t t/command-list.t t/command-make-shim.t t/current_perl.t t/current_shell.t t/do_system.t t/error-http_download-exec-error.t t/error-http_download-exit-nonzero.t t/error-http_download-param-validation.t t/error-install-before-init.t t/failure-command-install-cpanm.t t/failure-command-install-cpm.t t/failure-command-install-patchperl.t t/fake-bin/curl t/home.t t/http-program-control.t t/http-ua-detect-non-curl.t t/http-ua-detect.t t/http.t t/installation-perlbrew.t t/installation.t t/installation2.t t/installation3.t t/list_modules.t t/test.tar.gz t/test_helpers.pl t/unit-files-are-the-same.t t/util-find-similar-tokens.t installation2.t000644001750001750 577214465441602 16723 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; use Test::Exception; require 'test_helpers.pl'; use Test::Spec; ## setup ## note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; describe "App::perlbrew" => sub { describe "->do_install_url method" => sub { it "should accept an URL to perl tarball, and download the tarball." => sub { my $app = App::perlbrew->new; my @expectations; push @expectations, App::perlbrew->expects("http_download")->returns(0); push @expectations, $app->expects("do_extract_tarball")->returns(""); push @expectations, $app->expects("do_install_this")->returns(""); $app->do_install_url("http://example.com/perl-5.14.0.tar.gz"); for(@expectations) { ok $_->verify; } pass; } }; describe "->do_install_archive method" => sub { it "accepts a path to perl tarball and perform installation process." => sub { my $app = App::perlbrew->new; my $e1 = $app->expects("do_extract_tarball")->returns(App::Perlbrew::Path->new ("/a/fake/path/to/perl-5.12.3")); my $e2 = $app->expects("do_install_this")->returns(""); $app->do_install_archive(App::Perlbrew::Path->new ("/a/fake/path/to/perl-5.12.3.tar.gz")); ok $e1->verify, "do_extract_tarball is called"; ok $e2->verify, "do_install_this is called"; pass; } }; describe "->do_install_this method" => sub { it "should log successful brews to the log_file." => sub { my $app = App::perlbrew->new; $app->{dist_extracted_dir} = ''; $app->{dist_name} = ''; my %expectations = ( 'do_system' => $app->expects("do_system")->returns(1), ); $app->do_install_this('', '5.12.3', 'perl-5.12.3'); open(my $log_handle, '<', $app->{log_file}); like(<$log_handle>, qr/##### Brew Finished #####/, 'Success message shows in log'); foreach my $sub_name (keys %expectations) { ok $expectations{$sub_name}->verify, "$sub_name is called"; } }; it "should log brew failure to the log_file if system call fails." => sub { my $app = App::perlbrew->new; $app->{dist_extracted_dir} = ''; $app->{dist_name} = ''; my %expectations = ( 'do_system' => $app->expects("do_system")->returns(0), ); throws_ok( sub {$app->do_install_this('', '5.12.3', 'perl-5.12.3')}, qr/Installation process failed/); open(my $log_handle, '<', $app->{log_file}); like(<$log_handle>, qr/##### Brew Failed #####/, 'Failure message shows in log'); foreach my $sub_name (keys %expectations) { ok $expectations{$sub_name}->verify, "$sub_name is called"; } }; } }; runtests unless caller; command-install-cpm.t000644001750001750 153614465441602 17771 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/cpm$/, "GET cpm url: $url"; return "#!/usr/bin/env perl\n# The content of cpm"; } } describe "App::perlbrew->install_cpm" => sub { it "should produce 'cpm' in the bin dir" => sub { my $app = App::perlbrew->new("install-cpm", "-q"); $app->run(); my $cpm = App::Perlbrew::Path->new($perlbrew_root, "bin", "cpm"); ok -f $cpm, "cpm is produced. $cpm"; ok -x $cpm, "cpm should be an executable."; }; }; runtests unless caller; 07.argv.t000644001750001750 76614465441602 15302 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use App::perlbrew; { my $app = App::perlbrew->new("-Dcc=ccache gcc"); is $app->{D}[0], 'cc=ccache gcc'; } { my $app = App::perlbrew->new("-Dcc=ccache gcc", "-Dld=gcc"); is $app->{D}[0], 'cc=ccache gcc'; is $app->{D}[1], 'ld=gcc'; } { my $app = App::perlbrew->new("install", "-v", "perl-5.14.0", "-Dcc=ccache gcc", "-Dld=gcc"); is $app->{D}[0], 'cc=ccache gcc'; is $app->{D}[1], 'ld=gcc'; } done_testing; 12.sitecustomize.t000644001750001750 556314465441602 17266 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use Capture::Tiny qw/capture/; use IO::All; use App::perlbrew; use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; use Test::More; ## mock no warnings 'redefine'; sub App::perlbrew::do_system { my ($self, $cmd) = @_; if ($cmd =~ /sitelib/) { print "sitelib='$ENV{PERLBREW_ROOT}/perls/perl-5.14.2/lib/site_perl/5.14.2';"; return 1; } elsif ($cmd =~ /Configure/) { # pretend to succeed return 1; } else { # fail to run $? = 1<<8; $! = "Could not run '$cmd'"; return 0; } } sub App::perlbrew::do_install_release { my ($self, $dist) = @_; my ($dist_name, $dist_version) = $dist =~ m/^(.*)-([\d.]+(?:-RC\d+)?)$/; my $name = $dist; $name = $self->{as} if $self->{as}; my $root = App::Perlbrew::Path->new ($ENV{PERLBREW_ROOT}); my $installation_dir = $root->child("perls", $name); $installation_dir->mkpath; $root->child("perls", $name, "bin")->mkpath; my $perl = $root->child("perls", $name, "bin")->child("perl"); io($perl)->print("#!/bin/sh\nperl \"\$@\";\n"); chmod 0755, $perl; # fake the install $self->do_install_this("/tmp/fake-src/perl-5.14.2", $dist_version, $dist); } use warnings; ## main note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; subtest "No perls yet installed" => sub { my $app = App::perlbrew->new; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 0, "no perls installed"; }; subtest "--sitecustomize option can be set" => sub { my $app = App::perlbrew->new('install', 'perl-5.14.2', '--sitecustomize=mysitecustomize.pl' ); is join(' ', $app->args), join(' ', qw(install perl-5.14.2)), "post-option args correct"; is $app->{sitecustomize}, 'mysitecustomize.pl', '--sitecustomize set as expected'; }; subtest "mock installing" => sub { my $sitefile = File::Temp->new; print $sitefile "use strict;\n"; close $sitefile; my $app = App::perlbrew->new('install', 'perl-5.14.2', "--sitecustomize=$sitefile" ); my ($output,$error) = capture { $app->run }; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 1, "found 1 installed perl"; is $installed[0]->{name}, "perl-5.14.2", "found expected perl"; my $root = App::Perlbrew::Path->new ($ENV{PERLBREW_ROOT}); my $perldir = $root->child("perls", "perl-5.14.2"); my $installedsite = $perldir->child('lib', 'site_perl', '5.14.2', 'sitecustomize.pl'); ok( -f $installedsite, "sitecustomize.pl installed" ); my $guts = do { local (@ARGV, $/) = $installedsite; <> }; is( $guts, "use strict;\n", "sitecustomize.pl contents correct" ); }; done_testing; # vim: ts=4 sts=4 sw=4 et: 14.perl_version_parsing.t000644001750001750 1024714465441602 20626 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use App::perlbrew; use App::Perlbrew::Util qw(perl_version_to_integer); use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; # # This test checks if the sorting order of parsed version is the same as # the order of @versions array defined below. # my @versions = qw( 5.003_07 5.004 5.004_01 5.004_02 5.004_03 5.004_04 5.004_05 5.005 5.005_01 5.005_02 5.005_03 5.005_04 5.6.0 5.6.1-TRIAL1 5.6.1-TRIAL2 5.6.1-TRIAL3 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.7.3 5.8.0 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.10.0-RC1 5.10.0-RC2 5.10.0 5.10.1 5.11.0 5.11.1 5.11.2 5.11.3 5.11.4 5.11.5 5.12.0 5.12.1-RC1 5.12.1-RC2 5.12.1 5.12.2-RC1 5.12.2 5.12.3 5.12.4-RC1 5.12.4-RC2 5.12.4 5.13.0 5.13.1 5.13.2 5.13.3 5.13.4 5.13.5 5.13.6 5.13.7 5.13.8 5.13.9 5.13.10 5.13.11 5.14.0-RC1 5.14.0-RC2 5.14.0-RC3 5.14.0 5.14.1-RC1 5.14.1 5.14.2-RC1 5.14.2 5.14.3-RC1 5.14.3-RC2 5.14.3 5.15.0 5.15.1 5.15.2 5.15.3 5.15.4 5.15.5 5.15.6 5.15.7 5.15.8 5.15.9 5.16.0-RC0 5.16.0-RC1 5.16.0-RC2 5.16.0 5.16.1-RC1 5.16.1 5.16.2-RC1 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 ); use Test::More; subtest "perl_version_to_integer" => sub { plan tests => (@versions - 1); my @versions_i = map { perl_version_to_integer($_) } @versions; for my $i (0 .. $#versions_i-1) { ok( $versions_i[$i] < $versions_i[$i+1], "$versions[$i] < $versions[$i+1]"); } }; subtest "comparable_perl_version" => sub { plan tests => 0+@versions; for my $v (@versions) { my $n = App::perlbrew->comparable_perl_version($v); like($n, qr/\-? [0-9]+/x, "can build comparable version from: $v"); } }; subtest "blead is the biggest" => sub { plan tests => 0+@versions; my $b = perl_version_to_integer("blead"); for my $v (@versions) { my $n = perl_version_to_integer($v); ok $b > $n, "blead is bigger than $v"; } }; done_testing; 08.error_install.t000644001750001750 141114465441602 17227 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use Test::Exception; use File::Temp qw(tempdir); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; App::Perlbrew::Path->new ($ENV{PERLBREW_ROOT})->child ("perls")->mkpath; App::Perlbrew::Path->new ($ENV{PERLBREW_ROOT})->child ("build")->mkpath; App::Perlbrew::Path->new ($ENV{PERLBREW_ROOT})->child ("dists")->mkpath; no warnings 'redefine'; sub App::perlbrew::http_download { return "ERROR" } throws_ok( sub { my $app = App::perlbrew->new("install", "perl-5.12.3"); $app->run; }, qr[ERROR: Failed to download .*perl-5.12.3.*] ); done_testing; failure-command-install-cpanm.t000644001750001750 207114465441602 21730 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/cpanm$/, "GET cpanm url: $url"; return "404 not found."; } } describe "App::perlbrew->install_cpanm" => sub { it "should no produced 'cpanm' in the bin dir, if the downloaded content seems to be invalid." => sub { my $error; my $error_produced = 0; eval { my $app = App::perlbrew->new("install-cpanm", "-q"); $app->run(); } or do { $error = $@; $error_produced = 1; }; my $cpanm = App::Perlbrew::Path->new($perlbrew_root, "bin", "cpanm"); ok $error_produced, "generated an error: $error"; ok !(-f $cpanm), "cpanm is not produced. $cpanm"; }; }; runtests unless caller; 18.release-detail-perl-local.t000644001750001750 126014465441602 21263 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use App::perlbrew; use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; use Test::More; my $app = App::perlbrew->new(); $app->cpan_mirror("https://www.cpan.org"); my $rd = { type => "perl", "version" => "5.18.2" }; my ($error, undef) = $app->release_detail_perl_local("perl-5.18.2", $rd); ok !$error; ok defined( $rd->{tarball_url} ); ok defined( $rd->{tarball_name} ); is $rd->{tarball_url}, "https://www.cpan.org/authors/id/R/RJ/RJBS/perl-5.18.2.tar.bz2"; is $rd->{tarball_name}, "perl-5.18.2.tar.bz2"; done_testing; current_shell.t000644001750001750 152014465441602 16774 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse warnings; use strict; use Test::More tests => 6; use App::perlbrew; my $current_shell = (split("/", $ENV{SHELL}))[-1]; my $self = App::perlbrew->new(); is($self->current_shell(), $current_shell, 'current_shell gives the expected shell based on $SHELL environment variable') or diag("\$SHELL = $ENV{SHELL}"); is($self->current_shell('foobar'), 'foobar', 'current_shell setups and returns anything passed as parameter'); for my $shell (qw(bash zsh)) { note("Testing with $shell"); $self->current_shell($shell); ok($self->current_shell_is_bashish(), 'current_shell_is_bashish() returns true if the current shell is Bash or based on it'); } for my $shell (qw(ksh sh)) { note("Testing with $shell"); $self->current_shell($shell); ok( (! $self->current_shell_is_bashish()), 'current_shell_is_bashish() returns false'); } 03.test_get_available_versions.t000644001750001750 25262614465441602 22171 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use App::perlbrew; { no warnings 'redefine'; my $html_metacpan = read_metacpan_json(); sub App::perlbrew::http_get { my $url = shift; if ($url =~ m/fastapi\.metacpan\.org/) { return $html_metacpan; } else { return ''; } } } plan tests => 12; my $app = App::perlbrew->new(); my $dists = $app->available_perl_distributions(); my @vers = $app->sort_perl_versions(keys %$dists); is scalar( @vers ), 11, "Correct number of releases found"; my @known_perl_versions = ( 'perl-5.28.0', 'perl-5.26.2', 'perl-5.24.4', 'perl-5.22.4', 'perl-5.20.3', 'perl-5.18.4', 'perl-5.16.3', 'perl-5.14.4', 'perl-5.13.11', 'perl-5.12.5', 'perl-5.10.1', 'perl-5.8.9', 'perl-5.6.2', 'perl5.005_04', 'perl5.004_05', 'perl5.003_07' ); for my $perl_version ( @vers ) { ok grep( $_ eq $perl_version, @known_perl_versions ), "$perl_version found"; } sub read_metacpan_json { return <<'EOF'; { "releases" : [ { "authorized" : true, "version" : "5.028000", "maturity" : "released", "status" : "latest", "name" : "perl-5.28.0", "date" : "2018-06-23T02:05:28", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.28.0.tar.gz", "author" : "XSAWYERX" }, { "name" : "perl-5.28.0-RC4", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.028000", "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.28.0-RC4.tar.gz", "date" : "2018-06-19T20:45:05" }, { "date" : "2018-06-18T22:47:34", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.28.0-RC3.tar.gz", "author" : "XSAWYERX", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.28.0-RC3", "version" : "5.028000", "authorized" : true }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.28.0-RC2", "version" : "5.028000", "authorized" : true, "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.28.0-RC2.tar.gz", "date" : "2018-06-06T12:34:00" }, { "version" : "5.028000", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.28.0-RC1", "date" : "2018-05-21T13:12:00", "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.28.0-RC1.tar.gz" }, { "version" : "5.027011", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.27.11", "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.27.11.tar.gz", "date" : "2018-04-20T15:10:52" }, { "date" : "2018-04-14T11:27:18", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.26.2.tar.gz", "author" : "SHAY", "name" : "perl-5.26.2", "maturity" : "released", "status" : "cpan", "authorized" : true, "version" : "5.026002" }, { "date" : "2018-04-14T11:25:22", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.4.tar.gz", "version" : "5.024004", "authorized" : true, "name" : "perl-5.24.4", "status" : "cpan", "maturity" : "released" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.26.2-RC1", "version" : "5.026002", "authorized" : true, "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.26.2-RC1.tar.gz", "date" : "2018-03-24T19:37:40" }, { "version" : "5.024004", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.24.4-RC1", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.4-RC1.tar.gz", "author" : "SHAY", "date" : "2018-03-24T19:33:50" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.27.10", "version" : "5.027010", "authorized" : true, "date" : "2018-03-20T21:08:53", "download_url" : "https://cpan.metacpan.org/authors/id/T/TO/TODDR/perl-5.27.10.tar.gz", "author" : "TODDR" }, { "date" : "2018-02-20T20:46:45", "download_url" : "https://cpan.metacpan.org/authors/id/R/RE/RENEEB/perl-5.27.9.tar.gz", "author" : "RENEEB", "name" : "perl-5.27.9", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.027009" }, { "authorized" : true, "version" : "5.027008", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.27.8", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.27.8.tar.gz", "author" : "ABIGAIL", "date" : "2018-01-20T03:17:50" }, { "date" : "2017-12-20T22:58:25", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.27.7.tar.gz", "author" : "BINGOS", "version" : "5.027007", "authorized" : true, "name" : "perl-5.27.7", "status" : "cpan", "maturity" : "developer" }, { "download_url" : "https://cpan.metacpan.org/authors/id/E/ET/ETHER/perl-5.27.6.tar.gz", "author" : "ETHER", "date" : "2017-11-20T22:39:31", "name" : "perl-5.27.6", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.027006" }, { "name" : "perl-5.27.5", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.027005", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.27.5.tar.gz", "author" : "SHAY", "date" : "2017-10-20T22:08:15" }, { "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.26.1.tar.bz2", "author" : "SHAY", "date" : "2017-09-22T21:30:18", "authorized" : true, "version" : "5.026001", "status" : "latest", "maturity" : "released", "name" : "perl-5.26.1" }, { "date" : "2017-09-22T21:29:50", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.3.tar.gz", "authorized" : true, "version" : "5.024003", "status" : "cpan", "maturity" : "released", "name" : "perl-5.24.3" }, { "author" : "GENEHACK", "download_url" : "https://cpan.metacpan.org/authors/id/G/GE/GENEHACK/perl-5.27.4.tar.bz2", "date" : "2017-09-20T21:44:22", "version" : "5.027004", "authorized" : true, "name" : "perl-5.27.4", "status" : "cpan", "maturity" : "developer" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.26.1-RC1", "version" : "5.026001", "authorized" : true, "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.26.1-RC1.tar.bz2", "date" : "2017-09-10T15:38:22" }, { "authorized" : true, "version" : "5.024003", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.24.3-RC1", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.3-RC1.tar.bz2", "date" : "2017-09-10T15:37:08" }, { "author" : "WOLFSAGE", "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.27.3.tar.bz2", "date" : "2017-08-21T20:43:51", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.27.3", "authorized" : true, "version" : "5.027003" }, { "name" : "perl-5.27.2", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.027002", "date" : "2017-07-20T19:28:36", "author" : "ARC", "download_url" : "https://cpan.metacpan.org/authors/id/A/AR/ARC/perl-5.27.2.tar.bz2" }, { "version" : "5.024002", "authorized" : true, "name" : "perl-5.24.2", "maturity" : "released", "status" : "cpan", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.2.tar.gz", "date" : "2017-07-15T17:29:00" }, { "date" : "2017-07-15T17:26:52", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.4.tar.bz2", "author" : "SHAY", "authorized" : true, "version" : "5.022004", "maturity" : "released", "status" : "cpan", "name" : "perl-5.22.4" }, { "version" : "5.024002", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.24.2-RC1", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.2-RC1.tar.bz2", "author" : "SHAY", "date" : "2017-07-01T21:50:55" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.22.4-RC1", "authorized" : true, "version" : "5.022004", "date" : "2017-07-01T21:50:24", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.4-RC1.tar.gz" }, { "name" : "perl-5.27.1", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.027001", "download_url" : "https://cpan.metacpan.org/authors/id/E/EH/EHERMAN/perl-5.27.1.tar.bz2", "author" : "EHERMAN", "date" : "2017-06-20T06:39:54" }, { "maturity" : "developer", "status" : "backpan", "name" : "perl-5.27.0", "version" : "5.027000", "authorized" : true, "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.27.0.tar.gz", "date" : "2017-05-31T21:11:57" }, { "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.26.0.tar.bz2", "author" : "XSAWYERX", "date" : "2017-05-30T19:42:51", "authorized" : true, "version" : "5.026000", "status" : "cpan", "maturity" : "released", "name" : "perl-5.26.0" }, { "name" : "perl-5.26.0-RC2", "maturity" : "developer", "status" : "backpan", "authorized" : true, "version" : "5.026000", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.26.0-RC2.tar.gz", "author" : "XSAWYERX", "date" : "2017-05-23T23:19:34" }, { "name" : "perl-5.26.0-RC1", "status" : "backpan", "maturity" : "developer", "authorized" : true, "version" : "5.026000", "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.26.0-RC1.tar.bz2", "date" : "2017-05-11T17:07:17" }, { "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.25.12.tar.gz", "date" : "2017-04-20T19:32:05", "maturity" : "developer", "status" : "backpan", "name" : "perl-5.25.12", "version" : "5.025012", "authorized" : true }, { "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.25.11.tar.gz", "date" : "2017-03-20T20:56:49", "version" : "5.025011", "authorized" : true, "maturity" : "developer", "status" : "backpan", "name" : "perl-5.25.11" }, { "date" : "2017-02-20T21:21:01", "author" : "RENEEB", "download_url" : "https://cpan.metacpan.org/authors/id/R/RE/RENEEB/perl-5.25.10.tar.gz", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.25.10", "version" : "5.025010", "authorized" : true }, { "name" : "perl-5.25.9", "maturity" : "developer", "status" : "cpan", "version" : "5.025009", "authorized" : true, "date" : "2017-01-20T15:25:43", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.25.9.tar.gz", "author" : "ABIGAIL" }, { "authorized" : true, "version" : "5.024001", "name" : "perl-5.24.1", "status" : "cpan", "maturity" : "released", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1.tar.bz2", "date" : "2017-01-14T20:04:30" }, { "date" : "2017-01-14T20:04:05", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3.tar.gz", "maturity" : "released", "status" : "cpan", "name" : "perl-5.22.3", "version" : "5.022003", "authorized" : true }, { "date" : "2017-01-02T18:57:38", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1-RC5.tar.bz2", "authorized" : true, "version" : "5.024001", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.24.1-RC5" }, { "authorized" : true, "version" : "5.022003", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.22.3-RC5", "date" : "2017-01-02T18:54:51", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3-RC5.tar.bz2", "author" : "SHAY" }, { "authorized" : true, "version" : "5.025008", "name" : "perl-5.25.8", "status" : "backpan", "maturity" : "developer", "date" : "2016-12-20T19:14:33", "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.25.8.tar.gz" }, { "name" : "perl-5.25.7", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.025007", "date" : "2016-11-20T21:20:07", "author" : "EXODIST", "download_url" : "https://cpan.metacpan.org/authors/id/E/EX/EXODIST/perl-5.25.7.tar.bz2" }, { "date" : "2016-10-20T15:44:55", "author" : "ARC", "download_url" : "https://cpan.metacpan.org/authors/id/A/AR/ARC/perl-5.25.6.tar.bz2", "version" : "5.025006", "authorized" : true, "name" : "perl-5.25.6", "status" : "cpan", "maturity" : "developer" }, { "authorized" : true, "version" : "5.024001", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.24.1-RC4", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1-RC4.tar.bz2", "date" : "2016-10-12T21:40:57" }, { "authorized" : true, "version" : "5.022003", "name" : "perl-5.22.3-RC4", "status" : "cpan", "maturity" : "developer", "date" : "2016-10-12T21:39:57", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3-RC4.tar.bz2" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.25.5", "authorized" : true, "version" : "5.025005", "date" : "2016-09-20T17:45:06", "author" : "STEVAN", "download_url" : "https://cpan.metacpan.org/authors/id/S/ST/STEVAN/perl-5.25.5.tar.bz2" }, { "date" : "2016-08-20T20:25:19", "author" : "BINGOS", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.25.4.tar.bz2", "version" : "5.025004", "authorized" : true, "name" : "perl-5.25.4", "maturity" : "developer", "status" : "cpan" }, { "date" : "2016-08-11T23:50:29", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1-RC3.tar.bz2", "author" : "SHAY", "version" : "5.024001", "authorized" : true, "name" : "perl-5.24.1-RC3", "status" : "cpan", "maturity" : "developer" }, { "authorized" : true, "version" : "5.022003", "name" : "perl-5.22.3-RC3", "status" : "cpan", "maturity" : "developer", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3-RC3.tar.bz2", "author" : "SHAY", "date" : "2016-08-11T23:47:40" }, { "authorized" : true, "version" : "5.024001", "name" : "perl-5.24.1-RC2", "maturity" : "developer", "status" : "cpan", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1-RC2.tar.bz2", "date" : "2016-07-25T13:01:21" }, { "version" : "5.022003", "authorized" : true, "name" : "perl-5.22.3-RC2", "status" : "cpan", "maturity" : "developer", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3-RC2.tar.bz2", "date" : "2016-07-25T12:58:33" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.25.3", "version" : "5.025003", "authorized" : true, "date" : "2016-07-20T16:22:41", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.25.3.tar.bz2", "author" : "SHAY" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.24.1-RC1", "version" : "5.024001", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.24.1-RC1.tar.bz2", "author" : "SHAY", "date" : "2016-07-17T22:29:08" }, { "version" : "5.022003", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.22.3-RC1", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.3-RC1.tar.bz2", "author" : "SHAY", "date" : "2016-07-17T22:27:32" }, { "author" : "WOLFSAGE", "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.25.2.tar.bz2", "date" : "2016-06-20T21:02:44", "name" : "perl-5.25.2", "maturity" : "developer", "status" : "cpan", "version" : "5.025002", "authorized" : true }, { "author" : "XSAWYERX", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.25.1.tar.bz2", "date" : "2016-05-20T21:33:43", "name" : "perl-5.25.1", "status" : "backpan", "maturity" : "developer", "authorized" : true, "version" : "5.025001" }, { "date" : "2016-05-09T12:02:53", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.25.0.tar.bz2", "author" : "RJBS", "version" : "5.025000", "authorized" : true, "name" : "perl-5.25.0", "maturity" : "developer", "status" : "cpan" }, { "authorized" : true, "version" : "5.024000", "maturity" : "released", "status" : "cpan", "name" : "perl-5.24.0", "date" : "2016-05-09T11:35:29", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0.tar.bz2", "author" : "RJBS" }, { "name" : "perl-5.24.0-RC5", "status" : "cpan", "maturity" : "developer", "version" : "5.024000", "authorized" : true, "date" : "2016-05-04T22:27:57", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0-RC5.tar.bz2", "author" : "RJBS" }, { "version" : "5.024000", "authorized" : true, "name" : "perl-5.24.0-RC4", "maturity" : "developer", "status" : "cpan", "date" : "2016-05-02T14:41:03", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0-RC4.tar.bz2" }, { "date" : "2016-04-29T21:39:25", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.2.tar.bz2", "version" : "5.022002", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.22.2" }, { "version" : "5.024000", "authorized" : true, "name" : "perl-5.24.0-RC3", "maturity" : "developer", "status" : "cpan", "date" : "2016-04-27T01:02:55", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0-RC3.tar.bz2" }, { "authorized" : true, "version" : "5.024000", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.24.0-RC2", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0-RC2.tar.bz2", "date" : "2016-04-23T20:56:14" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.24.0-RC1", "version" : "5.024000", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.24.0-RC1.tar.bz2", "author" : "RJBS", "date" : "2016-04-14T03:27:48" }, { "authorized" : true, "version" : "5.022002", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.22.2-RC1", "date" : "2016-04-10T17:29:04", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.2-RC1.tar.bz2" }, { "date" : "2016-03-20T16:45:40", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.23.9.tar.bz2", "author" : "ABIGAIL", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.23.9", "authorized" : true, "version" : "5.023009" }, { "authorized" : true, "version" : "5.023008", "status" : "backpan", "maturity" : "developer", "name" : "perl-5.23.8", "date" : "2016-02-20T21:56:31", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.23.8.tar.bz2", "author" : "XSAWYERX" }, { "name" : "perl-5.23.7", "maturity" : "developer", "status" : "cpan", "version" : "5.023007", "authorized" : true, "date" : "2016-01-20T21:52:22", "download_url" : "https://cpan.metacpan.org/authors/id/S/ST/STEVAN/perl-5.23.7.tar.bz2", "author" : "STEVAN" }, { "date" : "2015-12-21T22:40:27", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAGOLDEN/perl-5.23.6.tar.bz2", "author" : "DAGOLDEN", "name" : "perl-5.23.6", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.023006" }, { "version" : "5.022001", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.22.1", "date" : "2015-12-13T19:48:31", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.1.tar.gz", "author" : "SHAY" }, { "version" : "5.022001", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.22.1-RC4", "date" : "2015-12-08T21:34:05", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.1-RC4.tar.bz2", "author" : "SHAY" }, { "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.1-RC3.tar.bz2", "author" : "SHAY", "date" : "2015-12-02T22:07:35", "version" : "5.022001", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.22.1-RC3" }, { "authorized" : true, "version" : "5.023005", "name" : "perl-5.23.5", "maturity" : "developer", "status" : "cpan", "author" : "ABIGAIL", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.23.5.tar.bz2", "date" : "2015-11-20T17:09:38" }, { "date" : "2015-11-15T15:15:03", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.1-RC2.tar.bz2", "author" : "SHAY", "authorized" : true, "version" : "5.022001", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.22.1-RC2" }, { "date" : "2015-10-31T18:42:58", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.22.1-RC1.tar.bz2", "author" : "SHAY", "authorized" : true, "version" : "5.022001", "name" : "perl-5.22.1-RC1", "status" : "cpan", "maturity" : "developer" }, { "date" : "2015-10-20T22:17:48", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.23.4.tar.bz2", "author" : "SHAY", "authorized" : true, "version" : "5.023004", "name" : "perl-5.23.4", "maturity" : "developer", "status" : "cpan" }, { "version" : "5.023003", "authorized" : true, "name" : "perl-5.23.3", "maturity" : "developer", "status" : "cpan", "date" : "2015-09-21T02:47:16", "author" : "PCM", "download_url" : "https://cpan.metacpan.org/authors/id/P/PC/PCM/perl-5.23.3.tar.bz2" }, { "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.3.tar.bz2", "author" : "SHAY", "date" : "2015-09-12T19:09:14", "version" : "5.020003", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.20.3" }, { "date" : "2015-08-29T22:02:43", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.3-RC2.tar.bz2", "authorized" : true, "version" : "5.020003", "name" : "perl-5.20.3-RC2", "status" : "cpan", "maturity" : "developer" }, { "version" : "5.020003", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.20.3-RC1", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.3-RC1.tar.bz2", "date" : "2015-08-22T22:12:34" }, { "date" : "2015-08-20T15:36:45", "author" : "WOLFSAGE", "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.23.2.tar.bz2", "name" : "perl-5.23.2", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.023002" }, { "authorized" : true, "version" : "5.023001", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.23.1", "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.23.1.tar.bz2", "author" : "WOLFSAGE", "date" : "2015-07-20T19:26:31" }, { "version" : "5.023000", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.23.0", "date" : "2015-06-20T20:22:32", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.23.0.tar.bz2" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.22.0.tar.bz2", "date" : "2015-06-01T17:51:59", "version" : "5.022000", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.22.0" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.22.0-RC2.tar.bz2", "date" : "2015-05-21T23:03:22", "name" : "perl-5.22.0-RC2", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.022000" }, { "date" : "2015-05-19T14:12:19", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.22.0-RC1.tar.bz2", "author" : "RJBS", "version" : "5.022000", "authorized" : true, "name" : "perl-5.22.0-RC1", "maturity" : "developer", "status" : "cpan" }, { "authorized" : true, "version" : "5.021011", "name" : "perl-5.21.11", "maturity" : "developer", "status" : "cpan", "date" : "2015-04-20T21:28:37", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.21.11.tar.bz2", "author" : "SHAY" }, { "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.21.10.tar.bz2", "author" : "SHAY", "date" : "2015-03-20T18:30:20", "version" : "5.021010", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.21.10" }, { "date" : "2015-02-21T05:27:09", "download_url" : "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/perl-5.21.9.tar.bz2", "author" : "XSAWYERX", "name" : "perl-5.21.9", "maturity" : "developer", "status" : "backpan", "authorized" : true, "version" : "5.021009" }, { "authorized" : true, "version" : "5.020002", "name" : "perl-5.20.2", "status" : "cpan", "maturity" : "released", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.2.tar.bz2", "author" : "SHAY", "date" : "2015-02-14T18:26:43" }, { "date" : "2015-02-01T03:07:56", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.2-RC1.tar.bz2", "version" : "5.020002", "authorized" : true, "name" : "perl-5.20.2-RC1", "status" : "cpan", "maturity" : "developer" }, { "date" : "2015-01-20T20:20:05", "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.21.8.tar.bz2", "author" : "WOLFSAGE", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.21.8", "version" : "5.021008", "authorized" : true }, { "author" : "CORION", "download_url" : "https://cpan.metacpan.org/authors/id/C/CO/CORION/perl-5.21.7.tar.bz2", "date" : "2014-12-20T17:34:57", "name" : "perl-5.21.7", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.021007" }, { "date" : "2014-11-20T23:39:06", "author" : "BINGOS", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.21.6.tar.bz2", "authorized" : true, "version" : "5.021006", "name" : "perl-5.21.6", "maturity" : "developer", "status" : "cpan" }, { "version" : "5.021005", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.21.5", "date" : "2014-10-20T16:54:20", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.21.5.tar.bz2", "author" : "ABIGAIL" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.4.tar.bz2", "author" : "RJBS", "date" : "2014-10-02T00:48:31", "status" : "cpan", "maturity" : "released", "name" : "perl-5.18.4", "version" : "5.018004", "authorized" : true }, { "version" : "5.018003", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.18.3", "date" : "2014-10-01T13:22:50", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.3.tar.bz2", "author" : "RJBS" }, { "date" : "2014-09-27T12:54:08", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.3-RC2.tar.bz2", "version" : "5.018003", "authorized" : true, "name" : "perl-5.18.3-RC2", "maturity" : "developer", "status" : "cpan" }, { "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.21.4.tar.bz2", "date" : "2014-09-20T13:33:14", "name" : "perl-5.21.4", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.021004" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.3-RC1.tar.bz2", "author" : "RJBS", "date" : "2014-09-17T20:29:53", "name" : "perl-5.18.3-RC1", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.018003" }, { "authorized" : true, "version" : "5.020001", "maturity" : "released", "status" : "cpan", "name" : "perl-5.20.1", "date" : "2014-09-14T13:11:14", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.1.tar.bz2" }, { "date" : "2014-09-07T17:01:11", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.1-RC2.tar.bz2", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.20.1-RC2", "version" : "5.020001", "authorized" : true }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.20.1-RC1", "authorized" : true, "version" : "5.020001", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.1-RC1.tar.bz2", "date" : "2014-08-25T18:10:32" }, { "version" : "5.021003", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.21.3", "author" : "PCM", "download_url" : "https://cpan.metacpan.org/authors/id/P/PC/PCM/perl-5.21.3.tar.bz2", "date" : "2014-08-21T02:26:13" }, { "author" : "ABIGAIL", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.21.2.tar.bz2", "date" : "2014-07-20T13:48:02", "version" : "5.021002", "authorized" : true, "name" : "perl-5.21.2", "status" : "cpan", "maturity" : "developer" }, { "download_url" : "https://cpan.metacpan.org/authors/id/W/WO/WOLFSAGE/perl-5.21.1.tar.bz2", "author" : "WOLFSAGE", "date" : "2014-06-20T15:31:10", "version" : "5.021001", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.21.1" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.21.0", "authorized" : true, "version" : "5.021000", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.21.0.tar.bz2", "author" : "RJBS", "date" : "2014-05-27T14:32:18" }, { "version" : "5.020000", "authorized" : true, "name" : "perl-5.20.0", "maturity" : "released", "status" : "cpan", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.20.0.tar.bz2", "author" : "RJBS", "date" : "2014-05-27T01:35:13" }, { "name" : "perl-5.20.0-RC1", "maturity" : "developer", "status" : "cpan", "version" : "5.020000", "authorized" : true, "date" : "2014-05-17T00:16:49", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.20.0-RC1.tar.bz2" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.19.11", "version" : "5.019011", "authorized" : true, "date" : "2014-04-20T15:47:12", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.19.11.tar.bz2", "author" : "SHAY" }, { "version" : "5.019010", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.19.10", "date" : "2014-03-20T20:40:26", "author" : "ARC", "download_url" : "https://cpan.metacpan.org/authors/id/A/AR/ARC/perl-5.19.10.tar.bz2" }, { "version" : "5.019009", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.19.9", "download_url" : "https://cpan.metacpan.org/authors/id/T/TO/TONYC/perl-5.19.9.tar.bz2", "author" : "TONYC", "date" : "2014-02-20T04:24:45" }, { "date" : "2014-01-20T21:59:04", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.19.8.tar.bz2", "author" : "RJBS", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.8", "version" : "5.019008", "authorized" : true }, { "maturity" : "released", "status" : "cpan", "name" : "perl-5.18.2", "version" : "5.018002", "authorized" : true, "date" : "2014-01-07T01:52:57", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.2.tar.bz2" }, { "date" : "2013-12-22T03:30:43", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.2-RC4.tar.bz2", "author" : "RJBS", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.18.2-RC4", "authorized" : true, "version" : "5.018002" }, { "author" : "ABIGAIL", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.19.7.tar.bz2", "date" : "2013-12-20T20:55:37", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.7", "authorized" : true, "version" : "5.019007" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.2-RC3.tar.bz2", "author" : "RJBS", "date" : "2013-12-19T21:27:42", "name" : "perl-5.18.2-RC3", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.018002" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.2-RC2.tar.bz2", "date" : "2013-12-07T13:55:43", "version" : "5.018002", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.18.2-RC2" }, { "authorized" : true, "version" : "5.018002", "name" : "perl-5.18.2-RC1", "status" : "cpan", "maturity" : "developer", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.2-RC1.tar.bz2", "date" : "2013-12-02T22:36:49" }, { "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.19.6.tar.bz2", "author" : "BINGOS", "date" : "2013-11-20T20:37:20", "version" : "5.019006", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.19.6" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.5", "version" : "5.019005", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.19.5.tar.bz2", "author" : "SHAY", "date" : "2013-10-20T13:25:55" }, { "name" : "perl-5.19.4", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.019004", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.19.4.tar.bz2", "date" : "2013-09-20T15:58:20" }, { "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.19.3.tar.bz2", "date" : "2013-08-20T16:09:42", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.3", "authorized" : true, "version" : "5.019003" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.1.tar.bz2", "date" : "2013-08-12T14:31:08", "maturity" : "released", "status" : "cpan", "name" : "perl-5.18.1", "authorized" : true, "version" : "5.018001" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.18.1-RC3", "authorized" : true, "version" : "5.018001", "date" : "2013-08-09T02:28:00", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.1-RC3.tar.bz2" }, { "authorized" : true, "version" : "5.018001", "name" : "perl-5.18.1-RC2", "status" : "cpan", "maturity" : "developer", "date" : "2013-08-04T12:34:33", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.1-RC2.tar.bz2" }, { "date" : "2013-08-02T03:09:02", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.1-RC1.tar.bz2", "author" : "RJBS", "version" : "5.018001", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.18.1-RC1" }, { "download_url" : "https://cpan.metacpan.org/authors/id/A/AR/ARISTOTLE/perl-5.19.2.tar.bz2", "author" : "ARISTOTLE", "date" : "2013-07-22T05:59:35", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.19.2", "version" : "5.019002", "authorized" : true }, { "author" : "DAGOLDEN", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAGOLDEN/perl-5.19.1.tar.bz2", "date" : "2013-06-21T01:24:18", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.1", "authorized" : true, "version" : "5.019001" }, { "authorized" : true, "version" : "5.019000", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.19.0", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.19.0.tar.bz2", "date" : "2013-05-20T13:12:38" }, { "date" : "2013-05-18T13:33:49", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.0.tar.bz2", "author" : "RJBS", "version" : "5.018000", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.18.0" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.0-RC4.tar.bz2", "date" : "2013-05-16T02:53:44", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.18.0-RC4", "version" : "5.018000", "authorized" : true }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.0-RC3.tar.bz2", "author" : "RJBS", "date" : "2013-05-14T01:32:05", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.18.0-RC3", "authorized" : true, "version" : "5.018000" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.0-RC2.tar.bz2", "author" : "RJBS", "date" : "2013-05-12T23:14:51", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.18.0-RC2", "authorized" : true, "version" : "5.018000" }, { "date" : "2013-05-11T12:29:53", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.18.0-RC1.tar.bz2", "name" : "perl-5.18.0-RC1", "status" : "cpan", "maturity" : "developer", "version" : "5.018000", "authorized" : true }, { "version" : "5.017011", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.17.11", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.17.11.tar.bz2", "date" : "2013-04-21T00:52:16" }, { "version" : "5.017010", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.17.10", "author" : "CORION", "download_url" : "https://cpan.metacpan.org/authors/id/C/CO/CORION/perl-5.17.10.tar.bz2", "date" : "2013-03-21T23:11:03" }, { "date" : "2013-03-11T21:08:33", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.3.tar.bz2", "author" : "RJBS", "version" : "5.016003", "authorized" : true, "maturity" : "released", "status" : "cpan", "name" : "perl-5.16.3" }, { "author" : "DAPM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.14.4.tar.bz2", "date" : "2013-03-10T23:47:40", "name" : "perl-5.14.4", "maturity" : "released", "status" : "cpan", "version" : "5.014004", "authorized" : true }, { "author" : "DAPM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.14.4-RC2.tar.bz2", "date" : "2013-03-07T19:52:52", "authorized" : true, "version" : "5.014004", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.14.4-RC2" }, { "version" : "5.016003", "authorized" : true, "name" : "perl-5.16.3-RC1", "status" : "cpan", "maturity" : "developer", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.3-RC1.tar.bz2", "date" : "2013-03-07T16:03:14" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.14.4-RC1", "version" : "5.014004", "authorized" : true, "date" : "2013-03-05T17:03:49", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.14.4-RC1.tar.bz2", "author" : "DAPM" }, { "date" : "2013-02-20T22:21:02", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.17.9.tar.bz2", "author" : "BINGOS", "name" : "perl-5.17.9", "status" : "cpan", "maturity" : "developer", "version" : "5.017009", "authorized" : true }, { "date" : "2013-01-20T18:48:45", "download_url" : "https://cpan.metacpan.org/authors/id/A/AR/ARC/perl-5.17.8.tar.bz2", "author" : "ARC", "name" : "perl-5.17.8", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.017008" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.17.7", "version" : "5.017007", "authorized" : true, "date" : "2012-12-18T21:50:28", "download_url" : "https://cpan.metacpan.org/authors/id/D/DR/DROLSKY/perl-5.17.7.tar.bz2", "author" : "DROLSKY" }, { "version" : "5.017006", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.17.6", "date" : "2012-11-21T00:08:12", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.17.6.tar.bz2", "author" : "RJBS" }, { "maturity" : "released", "status" : "cpan", "name" : "perl-5.12.5", "version" : "5.012005", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.12.5.tar.bz2", "author" : "DOM", "date" : "2012-11-10T14:02:17" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.12.5-RC2", "version" : "5.012005", "authorized" : true, "author" : "DOM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.12.5-RC2.tar.bz2", "date" : "2012-11-08T21:12:17" }, { "name" : "perl-5.12.5-RC1", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.012005", "author" : "DOM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.12.5-RC1.tar.bz2", "date" : "2012-11-03T17:27:59" }, { "name" : "perl-5.16.2", "status" : "cpan", "maturity" : "released", "authorized" : true, "version" : "5.016002", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.2.tar.bz2", "date" : "2012-11-01T13:44:07" }, { "authorized" : true, "version" : "5.016002", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.16.2-RC1", "date" : "2012-10-27T01:23:09", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.2-RC1.tar.bz2" }, { "version" : "5.017005", "authorized" : true, "name" : "perl-5.17.5", "status" : "cpan", "maturity" : "developer", "author" : "FLORA", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.17.5.tar.bz2", "date" : "2012-10-20T16:31:11" }, { "maturity" : "released", "status" : "cpan", "name" : "perl-5.14.3", "version" : "5.014003", "authorized" : true, "date" : "2012-10-12T20:24:43", "author" : "DOM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.14.3.tar.bz2" }, { "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.14.3-RC2.tar.bz2", "author" : "DOM", "date" : "2012-10-10T19:46:29", "version" : "5.014003", "authorized" : true, "name" : "perl-5.14.3-RC2", "status" : "cpan", "maturity" : "developer" }, { "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOM/perl-5.14.3-RC1.tar.bz2", "author" : "DOM", "date" : "2012-09-26T22:15:57", "authorized" : true, "version" : "5.014003", "name" : "perl-5.14.3-RC1", "maturity" : "developer", "status" : "cpan" }, { "date" : "2012-09-20T00:40:48", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.17.4.tar.bz2", "author" : "FLORA", "authorized" : true, "version" : "5.017004", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.17.4" }, { "name" : "perl-5.17.3", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.017003", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.17.3.tar.bz2", "date" : "2012-08-20T14:12:28" }, { "date" : "2012-08-08T22:30:11", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.1.tar.bz2", "author" : "RJBS", "authorized" : true, "version" : "5.016001", "name" : "perl-5.16.1", "maturity" : "released", "status" : "cpan" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.1-RC1.tar.bz2", "author" : "RJBS", "date" : "2012-08-03T18:59:23", "version" : "5.016001", "authorized" : true, "name" : "perl-5.16.1-RC1", "status" : "cpan", "maturity" : "developer" }, { "name" : "perl-5.17.2", "status" : "cpan", "maturity" : "developer", "version" : "5.017002", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/T/TO/TONYC/perl-5.17.2.tar.bz2", "author" : "TONYC", "date" : "2012-07-20T14:27:59" }, { "version" : "5.017001", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.17.1", "date" : "2012-06-20T17:38:46", "download_url" : "https://cpan.metacpan.org/authors/id/D/DO/DOY/perl-5.17.1.tar.bz2", "author" : "DOY" }, { "author" : "ZEFRAM", "download_url" : "https://cpan.metacpan.org/authors/id/Z/ZE/ZEFRAM/perl-5.17.0.tar.bz2", "date" : "2012-05-26T16:24:02", "name" : "perl-5.17.0", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.017000" }, { "date" : "2012-05-20T22:51:12", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.0.tar.bz2", "author" : "RJBS", "version" : "5.016000", "authorized" : true, "maturity" : "released", "status" : "cpan", "name" : "perl-5.16.0" }, { "version" : "5.016000", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.16.0-RC2", "date" : "2012-05-16T03:22:59", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.0-RC2.tar.bz2" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.0-RC1.tar.bz2", "date" : "2012-05-15T02:51:48", "authorized" : true, "version" : "5.016000", "name" : "perl-5.16.0-RC1", "maturity" : "developer", "status" : "cpan" }, { "date" : "2012-05-11T03:41:02", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.16.0-RC0.tar.bz2", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.16.0-RC0", "version" : "5.016000", "authorized" : true }, { "date" : "2012-03-20T19:01:29", "download_url" : "https://cpan.metacpan.org/authors/id/A/AB/ABIGAIL/perl-5.15.9.tar.bz2", "author" : "ABIGAIL", "name" : "perl-5.15.9", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.015009" }, { "download_url" : "https://cpan.metacpan.org/authors/id/C/CO/CORION/perl-5.15.8.tar.bz2", "author" : "CORION", "date" : "2012-02-20T22:38:13", "authorized" : true, "version" : "5.015008", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.15.8" }, { "authorized" : true, "version" : "5.015007", "name" : "perl-5.15.7", "status" : "cpan", "maturity" : "developer", "date" : "2012-01-20T20:08:28", "author" : "BINGOS", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.15.7.tar.bz2" }, { "download_url" : "https://cpan.metacpan.org/authors/id/D/DR/DROLSKY/perl-5.15.6.tar.bz2", "author" : "DROLSKY", "date" : "2011-12-20T17:55:58", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.15.6", "version" : "5.015006", "authorized" : true }, { "name" : "perl-5.15.5", "maturity" : "developer", "status" : "cpan", "version" : "5.015005", "authorized" : true, "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.15.5.tar.bz2", "date" : "2011-11-20T20:40:34" }, { "date" : "2011-10-20T21:17:45", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.15.4.tar.bz2", "author" : "FLORA", "name" : "perl-5.15.4", "maturity" : "developer", "status" : "cpan", "version" : "5.015004", "authorized" : true }, { "version" : "5.014002", "authorized" : true, "maturity" : "released", "status" : "cpan", "name" : "perl-5.14.2", "author" : "FLORA", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.14.2.tar.bz2", "date" : "2011-09-26T14:56:49" }, { "author" : "STEVAN", "download_url" : "https://cpan.metacpan.org/authors/id/S/ST/STEVAN/perl-5.15.3.tar.bz2", "date" : "2011-09-21T03:05:05", "authorized" : true, "version" : "5.015003", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.15.3" }, { "date" : "2011-09-19T11:25:31", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.14.2-RC1.tar.bz2", "author" : "FLORA", "name" : "perl-5.14.2-RC1", "maturity" : "developer", "status" : "cpan", "version" : "5.014002", "authorized" : true }, { "date" : "2011-08-21T00:05:23", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.15.2.tar.bz2", "author" : "RJBS", "version" : "5.015002", "authorized" : true, "name" : "perl-5.15.2", "status" : "cpan", "maturity" : "developer" }, { "version" : "5.015001", "authorized" : true, "name" : "perl-5.15.1", "status" : "cpan", "maturity" : "developer", "date" : "2011-07-20T21:15:08", "author" : "ZEFRAM", "download_url" : "https://cpan.metacpan.org/authors/id/Z/ZE/ZEFRAM/perl-5.15.1.tar.bz2" }, { "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAGOLDEN/perl-5.15.0.tar.bz2", "author" : "DAGOLDEN", "date" : "2011-06-20T23:19:05", "authorized" : true, "version" : "5.015000", "name" : "perl-5.15.0", "status" : "cpan", "maturity" : "developer" }, { "name" : "perl-5.12.4", "maturity" : "released", "status" : "cpan", "version" : "5.012004", "authorized" : true, "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl-5.12.4.tar.bz2", "date" : "2011-06-20T10:41:26" }, { "version" : "5.014001", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.14.1", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.1.tar.bz2", "date" : "2011-06-17T02:42:01" }, { "version" : "5.012004", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.12.4-RC2", "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl-5.12.4-RC2.tar.bz2", "date" : "2011-06-15T17:00:36" }, { "version" : "5.014001", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.14.1-RC1", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.1-RC1.tar.bz2", "date" : "2011-06-09T23:48:04" }, { "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl-5.12.4-RC1.tar.bz2", "date" : "2011-06-08T13:19:36", "authorized" : true, "version" : "5.012004", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.12.4-RC1" }, { "status" : "cpan", "maturity" : "released", "name" : "perl-5.14.0", "version" : "5.014000", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.0.tar.bz2", "author" : "JESSE", "date" : "2011-05-14T20:34:05" }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.0-RC3.tar.bz2", "author" : "JESSE", "date" : "2011-05-11T15:49:42", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.14.0-RC3", "version" : "5.014000", "authorized" : true }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.0-RC2.tar.bz2", "author" : "JESSE", "date" : "2011-05-04T16:42:27", "name" : "perl-5.14.0-RC2", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.014000" }, { "name" : "perl-5.14.0-RC1", "maturity" : "developer", "status" : "cpan", "version" : "5.014000", "authorized" : true, "date" : "2011-04-20T11:53:32", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.14.0-RC1.tar.bz2" }, { "authorized" : true, "version" : "5.013011", "name" : "perl-5.13.11", "maturity" : "developer", "status" : "cpan", "date" : "2011-03-20T19:49:16", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.13.11.tar.bz2", "author" : "FLORA" }, { "name" : "perl-5.13.10", "status" : "cpan", "maturity" : "developer", "version" : "5.013010", "authorized" : true, "download_url" : "https://cpan.metacpan.org/authors/id/A/AV/AVAR/perl-5.13.10.tar.bz2", "author" : "AVAR", "date" : "2011-02-20T19:18:02" }, { "maturity" : "released", "status" : "cpan", "name" : "perl-5.12.3", "authorized" : true, "version" : "5.012003", "date" : "2011-01-22T03:35:35", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.12.3.tar.bz2", "author" : "RJBS" }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.13.9.tar.bz2", "author" : "JESSE", "date" : "2011-01-21T01:42:07", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.13.9", "authorized" : true, "version" : "5.013009" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.12.3-RC3", "authorized" : true, "version" : "5.012003", "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.12.3-RC3.tar.bz2", "date" : "2011-01-18T02:13:17" }, { "name" : "perl-5.12.3-RC2", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.012003", "date" : "2011-01-15T04:05:30", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.12.3-RC2.tar.bz2", "author" : "RJBS" }, { "date" : "2011-01-10T02:12:53", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.12.3-RC1.tar.bz2", "author" : "RJBS", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.12.3-RC1", "version" : "5.012003", "authorized" : true }, { "date" : "2010-12-19T23:06:25", "download_url" : "https://cpan.metacpan.org/authors/id/Z/ZE/ZEFRAM/perl-5.13.8.tar.bz2", "author" : "ZEFRAM", "name" : "perl-5.13.8", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.013008" }, { "authorized" : true, "version" : "5.013007", "name" : "perl-5.13.7", "maturity" : "developer", "status" : "cpan", "date" : "2010-11-21T01:14:06", "download_url" : "https://cpan.metacpan.org/authors/id/B/BI/BINGOS/perl-5.13.7.tar.bz2", "author" : "BINGOS" }, { "authorized" : true, "version" : "5.013006", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.13.6", "date" : "2010-10-21T01:41:01", "download_url" : "https://cpan.metacpan.org/authors/id/M/MI/MIYAGAWA/perl-5.13.6.tar.bz2", "author" : "MIYAGAWA" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.13.5", "authorized" : true, "version" : "5.013005", "date" : "2010-09-19T21:22:47", "author" : "SHAY", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.13.5.tar.bz2" }, { "version" : "5.012002", "authorized" : true, "maturity" : "released", "status" : "cpan", "name" : "perl-5.12.2", "date" : "2010-09-07T01:41:31", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.2.tar.bz2", "author" : "JESSE" }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.2-RC1.tar.bz2", "author" : "JESSE", "date" : "2010-08-31T16:48:01", "authorized" : true, "version" : "5.012002", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.12.2-RC1" }, { "author" : "FLORA", "download_url" : "https://cpan.metacpan.org/authors/id/F/FL/FLORA/perl-5.13.4.tar.bz2", "date" : "2010-08-20T15:39:07", "version" : "5.013004", "authorized" : true, "name" : "perl-5.13.4", "status" : "cpan", "maturity" : "developer" }, { "authorized" : true, "version" : "5.013003", "name" : "perl-5.13.3", "status" : "cpan", "maturity" : "developer", "date" : "2010-07-20T10:23:23", "author" : "DAGOLDEN", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAGOLDEN/perl-5.13.3.tar.bz2" }, { "date" : "2010-06-22T21:39:26", "author" : "MSTROUT", "download_url" : "https://cpan.metacpan.org/authors/id/M/MS/MSTROUT/perl-5.13.2.tar.bz2", "authorized" : true, "version" : "5.013002", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.13.2" }, { "author" : "RJBS", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.13.1.tar.bz2", "date" : "2010-05-20T14:03:45", "version" : "5.013001", "authorized" : true, "name" : "perl-5.13.1", "maturity" : "developer", "status" : "cpan" }, { "name" : "perl-5.12.1", "status" : "cpan", "maturity" : "released", "authorized" : true, "version" : "5.012001", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.1.tar.bz2", "date" : "2010-05-16T22:40:16" }, { "date" : "2010-05-13T22:31:41", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.1-RC2.tar.bz2", "name" : "perl-5.12.1-RC2", "status" : "cpan", "maturity" : "developer", "version" : "5.012001", "authorized" : true }, { "authorized" : true, "version" : "5.012001", "name" : "perl-5.12.1-RC1", "status" : "cpan", "maturity" : "developer", "date" : "2010-05-10T02:43:48", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.1-RC1.tar.bz2" }, { "name" : "perl-5.13.0", "status" : "cpan", "maturity" : "developer", "version" : "5.013000", "authorized" : true, "date" : "2010-04-20T20:06:02", "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl-5.13.0.tar.bz2" }, { "version" : "5.012000", "authorized" : true, "status" : "cpan", "maturity" : "released", "name" : "perl-5.12.0", "date" : "2010-04-12T22:38:37", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0.tar.bz2", "author" : "JESSE" }, { "date" : "2010-04-10T03:46:04", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC5.tar.bz2", "author" : "JESSE", "name" : "perl-5.12.0-RC5", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.012000" }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC4.tar.bz2", "author" : "JESSE", "date" : "2010-04-07T05:39:46", "version" : "5.012000", "authorized" : true, "name" : "perl-5.12.0-RC4", "status" : "cpan", "maturity" : "developer" }, { "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC3.tar.bz2", "author" : "JESSE", "date" : "2010-04-03T02:40:48", "version" : "5.012000", "authorized" : true, "name" : "perl-5.12.0-RC3", "status" : "cpan", "maturity" : "developer" }, { "authorized" : true, "version" : "5.012000", "name" : "perl-5.12.0-RC2", "maturity" : "developer", "status" : "cpan", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC2.tar.bz2", "author" : "JESSE", "date" : "2010-04-01T02:38:12" }, { "date" : "2010-03-29T18:29:49", "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC1.tar.bz2", "name" : "perl-5.12.0-RC1", "status" : "cpan", "maturity" : "developer", "authorized" : true, "version" : "5.012000" }, { "author" : "JESSE", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.12.0-RC0.tar.gz", "date" : "2010-03-21T20:41:11", "status" : "backpan", "maturity" : "developer", "name" : "perl-5.12.0-RC0", "authorized" : true, "version" : "5.012000" }, { "date" : "2010-02-21T00:45:26", "download_url" : "https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.11.5.tar.bz2", "author" : "SHAY", "authorized" : true, "version" : "5.011005", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.11.5" }, { "date" : "2010-01-20T16:48:28", "download_url" : "https://cpan.metacpan.org/authors/id/R/RJ/RJBS/perl-5.11.4.tar.bz2", "author" : "RJBS", "authorized" : true, "version" : "5.011004", "name" : "perl-5.11.4", "status" : "cpan", "maturity" : "developer" }, { "date" : "2009-12-21T04:49:14", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.11.3.tar.bz2", "author" : "JESSE", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.11.3", "version" : "5.011003", "authorized" : true }, { "date" : "2009-11-20T07:20:52", "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl-5.11.2.tar.bz2", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.11.2", "authorized" : true, "version" : "5.011002" }, { "date" : "2009-10-20T17:51:38", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.11.1.tar.bz2", "author" : "JESSE", "authorized" : true, "version" : "5.011001", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.11.1" }, { "date" : "2009-10-02T20:51:46", "download_url" : "https://cpan.metacpan.org/authors/id/J/JE/JESSE/perl-5.11.0.tar.bz2", "author" : "JESSE", "version" : "5.011000", "authorized" : true, "name" : "perl-5.11.0", "status" : "cpan", "maturity" : "developer" }, { "version" : "5.010001", "authorized" : true, "name" : "perl-5.10.1", "maturity" : "released", "status" : "cpan", "date" : "2009-08-23T14:21:38", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.10.1.tar.bz2", "author" : "DAPM" }, { "author" : "DAPM", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.10.1-RC2.tar.bz2", "date" : "2009-08-18T23:45:03", "authorized" : true, "version" : "5.010001", "name" : "perl-5.10.1-RC2", "maturity" : "developer", "status" : "cpan" }, { "date" : "2009-08-06T16:11:03", "download_url" : "https://cpan.metacpan.org/authors/id/D/DA/DAPM/perl-5.10.1-RC1.tar.bz2", "author" : "DAPM", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.10.1-RC1", "authorized" : true, "version" : "5.010001" }, { "date" : "2008-12-14T23:08:28", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.9.tar.bz2", "author" : "NWCLARK", "authorized" : true, "version" : "5.008009", "name" : "perl-5.8.9", "status" : "cpan", "maturity" : "released" }, { "name" : "perl-5.8.9-RC2", "status" : "cpan", "maturity" : "developer", "version" : "5.008009", "authorized" : true, "date" : "2008-12-06T22:50:35", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.9-RC2.tar.bz2" }, { "version" : "5.008009", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.8.9-RC1", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.9-RC1.tar.bz2", "date" : "2008-11-10T23:14:59" }, { "name" : "perl-5.10.0", "maturity" : "released", "status" : "cpan", "version" : "5.010000", "authorized" : true, "date" : "2007-12-18T17:41:41", "author" : "RGARCIA", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.10.0.tar.gz" }, { "version" : "5.010000", "authorized" : true, "name" : "perl-5.10.0-RC2", "maturity" : "developer", "status" : "backpan", "date" : "2007-11-25T18:22:18", "author" : "RGARCIA", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.10.0-RC2.tar.gz" }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.10.0-RC1.tar.gz", "author" : "RGARCIA", "date" : "2007-11-17T15:31:20", "maturity" : "developer", "status" : "backpan", "name" : "perl-5.10.0-RC1", "version" : "5.009005", "authorized" : true }, { "date" : "2007-07-07T16:13:57", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.9.5.tar.gz", "author" : "RGARCIA", "authorized" : true, "version" : "5.009005", "name" : "perl-5.9.5", "maturity" : "developer", "status" : "cpan" }, { "name" : "perl-0.0017", "maturity" : "developer", "status" : "backpan", "authorized" : true, "version" : "0.0017", "date" : "2007-05-01T10:37:34", "download_url" : "https://cpan.metacpan.org/authors/id/H/HO/HOOO/perl-0.0017.tar.gz", "author" : "HOOO" }, { "authorized" : true, "version" : "5.009004", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.9.4", "author" : "RGARCIA", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.9.4.tar.gz", "date" : "2006-08-15T13:48:30" }, { "date" : "2006-02-01T00:00:59", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.8.tar.bz2", "authorized" : true, "version" : "5.008008", "status" : "cpan", "maturity" : "released", "name" : "perl-5.8.8" }, { "maturity" : "developer", "status" : "cpan", "name" : "perl-5.9.3", "version" : "5.009003", "authorized" : true, "date" : "2006-01-28T11:11:38", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.9.3.tar.gz", "author" : "RGARCIA" }, { "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.8-RC1.tar.bz2", "date" : "2006-01-20T10:09:18", "authorized" : true, "version" : "5.008008", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.8.8-RC1" }, { "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.7.tar.bz2", "date" : "2005-05-30T22:19:23", "name" : "perl-5.8.7", "maturity" : "released", "status" : "cpan", "authorized" : true, "version" : "5.008007" }, { "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.7-RC1.tar.bz2", "author" : "NWCLARK", "date" : "2005-05-18T16:35:37", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.8.7-RC1", "version" : "5.008007", "authorized" : true }, { "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.9.2.tar.gz", "author" : "RGARCIA", "date" : "2005-04-01T09:53:24", "name" : "perl-5.9.2", "maturity" : "developer", "status" : "cpan", "authorized" : true, "version" : "5.009002" }, { "version" : "5.008006", "authorized" : true, "maturity" : "released", "status" : "cpan", "name" : "perl-5.8.6", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.6.tar.bz2", "author" : "NWCLARK", "date" : "2004-11-27T23:56:17" }, { "date" : "2004-11-11T19:56:33", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.6-RC1.tar.bz2", "status" : "cpan", "maturity" : "developer", "name" : "perl-5.8.6-RC1", "version" : "5.008006", "authorized" : true }, { "name" : "perl-5.8.5", "maturity" : "released", "status" : "cpan", "authorized" : true, "version" : "5.008005", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.5.tar.bz2", "author" : "NWCLARK", "date" : "2004-07-19T21:56:20" }, { "authorized" : true, "version" : "5.008005", "maturity" : "developer", "status" : "cpan", "name" : "perl-5.8.5-RC2", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.5-RC2.tar.bz2", "date" : "2004-07-08T21:55:05" }, { "authorized" : true, "version" : "5.008005", "name" : "perl-5.8.5-RC1", "status" : "cpan", "maturity" : "developer", "date" : "2004-07-06T21:41:21", "author" : "NWCLARK", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.5-RC1.tar.bz2" }, { "authorized" : true, "version" : "5.008003", "maturity" : "released", "status" : "cpan", "name" : "perl-5.8.4", "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.4.tar.bz2", "author" : "NWCLARK", "date" : "2004-04-21T23:03:10" }, { "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.4-RC2.tar.bz2", "author" : "NWCLARK", "date" : "2004-04-15T22:59:51", "version" : "5.008003", "authorized" : true, "status" : "cpan", "maturity" : "developer", "name" : "perl-5.8.4-RC2" }, { "download_url" : "https://cpan.metacpan.org/authors/id/N/NW/NWCLARK/perl-5.8.4-RC1.tar.bz2", "author" : "NWCLARK", "date" : "2004-04-05T21:27:48", "version" : "5.008003", "authorized" : true, "maturity" : "developer", "status" : "cpan", "name" : "perl-5.8.4-RC1" }, { "status" : "cpan", "maturity" : "developer", "name" : "perl-5.9.1", "version" : "5.009001", "authorized" : true, "author" : "RGARCIA", "download_url" : "https://cpan.metacpan.org/authors/id/R/RG/RGARCIA/perl-5.9.1.tar.gz", "date" : "2004-03-16T19:35:25" }, { "date" : "2004-02-23T14:02:10", "author" : "LBROCARD", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl5.005_04.tar.gz", "status" : "cpan", "maturity" : "released", "name" : "perl5.005_04", "authorized" : true, "version" : "5.005" }, { "name" : "perl5.005_04-RC2", "maturity" : "developer", "status" : "backpan", "authorized" : true, "version" : "5.005", "download_url" : "https://cpan.metacpan.org/authors/id/L/LB/LBROCARD/perl5.005_04-RC2.tar.gz", "author" : "LBROCARD", "date" : "2004-02-18T14:20:15" } ], "took" : 30, "total" : 418 } EOF } http-program-control.t000644001750001750 210514465441602 20225 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::Perlbrew::HTTP qw(http_user_agent_command); use Test::More; use Test::Exception; for my $prog (qw(curl wget fetch)) { local $App::Perlbrew::HTTP::HTTP_USER_AGENT_PROGRAM = $prog; for my $verbose (0, 1) { local $App::Perlbrew::HTTP::HTTP_VERBOSE = $verbose; subtest "UA should be $prog, verbosity should be $verbose", sub { my ($ua, $cmd) = http_user_agent_command( "get" => { "url" => "https://perlbrew.pl" }); is $ua, $prog, "UA Program can be set to: $prog"; unless ($prog eq "fetch") { my ($cmd_verbosity) = $cmd =~ m/\s(--verbose)\s/; is !!$cmd_verbosity, !!$verbose, "verbosity matches: [$cmd]"; } } }; } subtest "something not supported", sub { local $App::Perlbrew::HTTP::HTTP_USER_AGENT_PROGRAM = "something-that-is-not-recognized"; dies_ok { http_user_agent_program(); } "should die when asked to use unrecognized http UA program"; }; done_testing; CONTRIBUTING.md000644001750001750 210314465441602 15722 0ustar00gugodgugod000000000000App-perlbrew-0.98Hi Hackers, perlbrew is open for anyone who are willing to contribute. Here's what you do to get your work released: - Fork the repository on github - Modify `lib/App/perlbrew.pm` or `script/perlbrew` if necessary. - Add tests so others do not break your feature. - If it seems pulsable, update `Changes` too. Put a gist of the change in the beginning of the file. - Send a pull request to @gugod and make an offer that he cannot reject (optional :-) Notice that the "master" branch is a stable branch, while the "develop" branch is the default target for pull requests. The master branch should only be moved forward on CPAN releases and there should also be a corresponding git tag for each release, which is the part only @gugod has to worry about. It is suggested, but not required, that you create your own topic branch first and work on the feature, this way it makes it a little bit easier when there are conflicts. Last, DO NOT edit the `./perlbrew` file directly, it is a standalone executable built with `dev-bin/build.sh`. Happy hacking! Sincerely, Kang-min Liu, aka @gugod 10.resolve.t000644001750001750 404714465441602 16030 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; use Test::Exception; mock_perlbrew_install("perl-5.8.9"); mock_perlbrew_install("perl-5.14.0"); mock_perlbrew_install("perl-5.8.9", "--as" => "5.8.9"); mock_perlbrew_install("perl-5.14.0", "--as" => "perl-shiny", "perl-5.14.0"); { no warnings 'redefine'; sub App::perlbrew::current_perl { "perl-5.14.0" } } ## spec describe "App::perlbrew->resolve_installation_name" => sub { my $app; before each => sub { $app = App::perlbrew->new; }; it "takes exactly one argument, which means the `shortname` that needs to be resolved to a `longname`", sub { ok $app->resolve_installation_name("5.8.9"); dies_ok { $app->resolve_installation_name; # no args }; }; it "returns the same value as the argument if there is an installation with exactly the same name", sub { is $app->resolve_installation_name("5.8.9"), "5.8.9"; is $app->resolve_installation_name("perl-5.8.9"), "perl-5.8.9"; is $app->resolve_installation_name("perl-5.14.0"), "perl-5.14.0"; }; it "returns `perl-\$shortname` if that happens to be a proper installation name.", sub { is $app->resolve_installation_name("5.14.0"), "perl-5.14.0"; is $app->resolve_installation_name("shiny"), "perl-shiny"; }; it "returns undef if no proper installation can be found", sub { is $app->resolve_installation_name("nihao"), undef; }; describe 'with lib names' => sub { it 'returns both perl version and libnames' => sub { my ($v, $l) = $app->resolve_installation_name('perl-5.14.0@soya'); is $v, "perl-5.14.0"; is $l, "soya"; }; it 'returns current perl version when only a libname is given' => sub { my ($v, $l) = $app->resolve_installation_name('@soya'); is $v, $app->current_perl; is $l, "soya"; }; }; }; runtests unless caller; command-exec.t000644001750001750 3145214465441602 16512 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::Spec; use Test::Output; mock_perlbrew_install("perl-5.12.3"); mock_perlbrew_install("perl-5.12.4"); mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.14.2"); describe 'perlbrew exec perl -E "say 42"' => sub { it "invokes all perls" => sub { my $app = App::perlbrew->new(qw(exec perl -E), "say 42"); my @perls = $app->installed_perls; $app->expects("do_system_with_exit_code")->exactly(4)->returns( sub { my ($self, @args) = @_; is_deeply \@args, ["perl", "-E", "say 42"]; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); my $perl_installation = shift @perls; is $perlbrew_bin_path, App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "bin"); is $perlbrew_perl_bin_path, App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", $perl_installation->{name}, "bin"), "perls/". $perl_installation->{name} . "/bin"; return 0; } ); $app->run; }; }; describe 'perlbrew exec --with perl-5.12.3 perl -E "say 42"' => sub { it "invokes perl-5.12.3/bin/perl" => sub { my $app = App::perlbrew->new(qw(exec --with perl-5.12.3 perl -E), "say 42"); $app->expects("do_system_with_exit_code")->returns( sub { my ($self, @args) = @_; is_deeply \@args, ["perl", "-E", "say 42"]; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); is $perlbrew_bin_path, App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "bin"); is $perlbrew_perl_bin_path, App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.12.3", "bin"); return 0; } ); $app->run; }; }; describe 'perlbrew exec --with perl-5.14.1,perl-5.12.3,perl-5.14.2 perl -E "say 42"' => sub { it "invokes each perl in the specified order" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1 perl-5.12.3 perl-5.14.2", qw(perl -E), "say 42"); my @perl_paths; $app->expects("do_system_with_exit_code")->exactly(3)->returns( sub { my ($self, @args) = @_; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); push @perl_paths, $perlbrew_perl_bin_path; return 0; } ); $app->run; is_deeply \@perl_paths, [ App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.1", "bin"), App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.12.3", "bin"), App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.2", "bin"), ]; }; }; describe 'perlbrew exec --with perl-5.14.1,perl-foobarbaz, ' => sub { it "ignore the unrecognized 'perl-foobarbaz'" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1 perl-foobarbaz", qw(perl -E), "say 42"); my @perl_paths; $app->expects("do_system_with_exit_code")->returns( sub { my ($self, @args) = @_; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); push @perl_paths, $perlbrew_perl_bin_path; return 0; } ); $app->run; is_deeply \@perl_paths, [ App::Perlbrew::Path->new ($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.1", "bin"), ]; }; }; describe 'perlbrew exec --with perl-5.14.1,5.14.1 ' => sub { it "exec 5.14.1 twice, since that is what is specified" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1 5.14.1", qw(perl -E), "say 42"); my @perl_paths; $app->expects("do_system_with_exit_code")->exactly(2)->returns( sub { my ($self, @args) = @_; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); push @perl_paths, $perlbrew_perl_bin_path; return 0; } ); $app->run; is_deeply \@perl_paths, [ App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.1", "bin"), App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.1", "bin"), ]; }; }; describe 'exec exit code' => sub { describe "logging" => sub { it "should work" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1", qw(perl -E), "somesub 42"); $app->expects("format_info_output")->exactly(1)->returns("format_info_output_value\n"); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(7<<8); stderr_is sub { eval { $app->run; 1; }; }, <<"OUT"; Command [perl -E 'somesub 42'] terminated with exit code 7 (\$? = 1792) under the following perl environment: format_info_output_value OUT }; it "should be quiet if asked" => sub { my $app = App::perlbrew->new(qw(exec --quiet --with), "perl-5.14.1", qw(perl -E), "somesub 42"); $app->expects("format_info_output")->exactly(0)->returns('should not be called!'); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(7<<8); stderr_is sub { eval { $app->run; 1; }; }, ''; }; it "should format info output for right perl" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1", qw(perl -E), "somesub 42"); $app->expects("format_info_output")->exactly(1)->returns(sub { my ($self) = @_; is $self->current_env, 'perl-5.14.1'; like $self->installed_perl_executable('perl-5.14.1'), qr/perl-5.14.1/; "format_info_output_value\n"; }); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(7<<8); eval { $app->run; 1; }; }; }; describe "no halt-on-error" => sub { it "should exit with success code when several perls ran" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1 perl-5.14.1", qw(perl -E), "say 42"); App::perlbrew->expects("do_exit_with_error_code")->never; $app->expects("do_system_with_exit_code")->exactly(2)->returns(0); $app->run; }; it "should exit with error code " => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1", qw(perl -E), "say 42"); $app->expects("format_info_output")->exactly(1)->returns(''); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { my ($self, $code) = @_; is $code, 1; # exit with error, but don't propogate exact failure codes die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(3<<8); ok !eval { $app->run; 1; }; is $@, "simulate exit\n"; }; it "should exit with error code when several perls ran" => sub { my $app = App::perlbrew->new(qw(exec --with), "perl-5.14.1 perl-5.14.1", qw(perl -E), "say 42"); $app->expects("format_info_output")->exactly(1)->returns(''); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { my ($self, $code) = @_; is $code, 1; # exit with error, but don't propogate exact failure codes die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(sub { $app->expects("do_system_with_exit_code")->exactly(1)->returns(sub { # make sure second call to exec is made 0; # second call is success }); 3<<8; # first exec failed }); ok !eval { $app->run; 1; }; is $@, "simulate exit\n"; }; }; describe "halt-on-error" => sub { it "should exit with success code " => sub { my $app = App::perlbrew->new(qw(exec --halt-on-error --with), "perl-5.14.1", qw(perl -E), "say 42"); App::perlbrew->expects("do_exit_with_error_code")->never; $app->expects("do_system_with_exit_code")->exactly(1)->returns(0); $app->run; }; it "should exit with error code " => sub { my $app = App::perlbrew->new(qw(exec --halt-on-error --with), "perl-5.14.1", qw(perl -E), "say 42"); $app->expects("format_info_output")->exactly(1)->returns(''); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { my ($self, $code) = @_; is $code, 3; die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(3<<8); ok !eval { $app->run; 1; }; is $@, "simulate exit\n"; }; it "should exit with code 255 if program terminated with signal or something" => sub { my $app = App::perlbrew->new(qw(exec --halt-on-error --with), "perl-5.14.1", qw(perl -E), "say 42"); $app->expects("format_info_output")->exactly(1)->returns(''); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { my ($self, $code) = @_; is $code, 255; die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(-1); ok !eval { $app->run; 1; }; is $@, "simulate exit\n"; }; it "should exit with error code when several perls ran" => sub { my $app = App::perlbrew->new(qw(exec --halt-on-error --with), "perl-5.14.1 perl-5.14.1", qw(perl -E), "say 42"); $app->expects("format_info_output")->exactly(1)->returns(''); App::perlbrew->expects("do_exit_with_error_code")->exactly(1)->returns(sub { my ($self, $code) = @_; is $code, 7; die "simulate exit\n"; }); $app->expects("do_system_with_exit_code")->exactly(1)->returns(sub { $app->expects("do_system_with_exit_code")->exactly(1)->returns(sub { 7<<8; }); 0; }); ok !eval { $app->run; 1; }; is $@, "simulate exit\n"; }; }; }; describe "minimal perl version" => sub { it "only executes the needed version" => sub { my @perl_paths; my $app = App::perlbrew->new(qw(exec --min 5.014), qw(perl -E), "say 42"); $app->expects("do_system_with_exit_code")->exactly(2)->returns(sub { my ($self, @args) = @_; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); push @perl_paths, $perlbrew_perl_bin_path; return 0; }); $app->run; # Don't care about the order, just the fact all of them were visited is_deeply [sort @perl_paths], [sort ( App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.2", "bin"), App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.14.1", "bin"), )]; }; }; describe "maximum perl version" => sub { it "only executes the needed version" => sub { my @perl_paths; my $app = App::perlbrew->new(qw(exec --max 5.014), qw(perl -E), "say 42"); $app->expects("do_system_with_exit_code")->exactly(2)->returns(sub { my ($self, @args) = @_; my ($perlbrew_bin_path, $perlbrew_perl_bin_path, @paths) = split(":", $ENV{PATH}); push @perl_paths, $perlbrew_perl_bin_path; return 0; }); $app->run; # Don't care about the order, just the fact all of them were visited is_deeply [sort @perl_paths], [sort ( App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.12.4", "bin"), App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT, "perls", "perl-5.12.3", "bin"), )]; }; }; runtests unless caller; http-ua-detect.t000644001750001750 65614465441602 16744 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use File::Which qw(which); use App::Perlbrew::HTTP qw(http_user_agent_program); use Test::More; my $expected_ua; if (which("curl")) { $expected_ua = "curl"; } elsif (which("wget")) { $expected_ua = "wget"; } elsif (which("fetch")) { $expected_ua = "fetch"; } my $detected_ua = http_user_agent_program(); is $detected_ua, $expected_ua, "UA: $detected_ua"; done_testing; error-http_download-exit-nonzero.t000644001750001750 132214465441602 22557 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More import => [ qw( done_testing like subtest ) ]; use File::Temp qw( tempdir ); my $actual_status_code = 42; BEGIN { *CORE::GLOBAL::system = sub { return $? = $actual_status_code << 8; }; } use App::Perlbrew::Path; use App::Perlbrew::HTTP qw(http_download); local $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); subtest "The exit status code of curl", sub { my $error = http_download( "https://example.com/whatever.tar.gz", App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT)->child("whatever.tar.gz") ); like $error, qr/^ERROR .+ Exit\ code: .+ ${actual_status_code}/xs; }; done_testing; 12.destdir.t000644001750001750 603414465441602 16007 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use Capture::Tiny qw/capture/; use IO::All; use App::perlbrew; use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; my $DESTDIR = tempdir( CLEANUP => 1 ); use Test::More; ## mock no warnings 'redefine'; sub App::perlbrew::do_system { my ($self, $cmd) = @_; if ($cmd =~ /sitelib/) { print "sitelib='$ENV{PERLBREW_ROOT}/perls/perl-5.14.2/lib/site_perl/5.14.2';\n"; print "installprefix='$ENV{PERLBREW_ROOT}/perls/perl-5.14.2';\n"; print "installstyle='lib';\n"; return 1; } elsif ($cmd =~ /Configure/) { # pretend to succeed return 1; } else { # fail to run $? = 1<<8; $! = "Could not run '$cmd'"; return 0; } } sub App::perlbrew::do_install_release { my ($self, $dist) = @_; my ($dist_name, $dist_version) = $dist =~ m/^(.*)-([\d.]+(?:-RC\d+)?)$/; my $name = $dist; $name = $self->{as} if $self->{as}; my $root = App::Perlbrew::Path->new ($DESTDIR, $ENV{PERLBREW_ROOT}); my $installation_dir = $root->child("perls", $name); $installation_dir->mkpath; $root->child("perls", $name, "bin")->mkpath; my $perl = $root->child("perls", $name, "bin")->child("perl"); io($perl)->print("#!/bin/sh\nperl \"\$@\";\n"); chmod 0755, $perl; # fake the install $self->do_install_this("/tmp/fake-src/perl-5.14.2", $dist_version, $dist); } use warnings; ## main note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; note "DESTDIR set to $DESTDIR"; subtest "No perls yet installed" => sub { my $app = App::perlbrew->new; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 0, "no perls installed"; }; subtest "--destdir option can be set" => sub { my $app = App::perlbrew->new('install', 'perl-5.14.2', '--destdir=/tmp/foo' ); is join(' ', $app->args), join(' ', qw(install perl-5.14.2)), "post-option args correct"; is $app->{destdir}, '/tmp/foo', '--destdir set as expected'; }; subtest "mock installing" => sub { my $sitefile = File::Temp->new; print $sitefile "use strict;\n"; close $sitefile; my $app = App::perlbrew->new('install', 'perl-5.14.2', "--destdir=$DESTDIR", "--sitecustomize=$sitefile" ); my ($output,$error) = capture { $app->run }; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 0, "found 0 installed perl (as it's installed in DESTDIR)"; my $root = App::Perlbrew::Path->new ($DESTDIR, $ENV{PERLBREW_ROOT}); my $perldir = $root->child("perls", "perl-5.14.2"); my $installedsite = $perldir->child('lib', 'site_perl', '5.14.2', 'sitecustomize.pl'); ok( -f $installedsite, "sitecustomize.pl installed in DESTDIR" ); my $guts = do { local (@ARGV, $/) = $installedsite; <> }; is( $guts, "use strict;\n", "sitecustomize.pl contents correct in DESTDIR" ); }; done_testing; # vim: ts=4 sts=4 sw=4 et: installation.t000644001750001750 272514465441602 16634 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Exception; ## main note "PERLBREW_ROOT set to $ENV{PERLBREW_ROOT}"; { my $app = App::perlbrew->new; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 0; } { my $app = App::perlbrew->new("install", "perl-5.14.0"); $app->run; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 1; is $installed[0]->{name}, "perl-5.14.0"; dies_ok { my $app = App::perlbrew->new("install", "perl-5.14.0"); $app->run; } "should die when doing install with existing distribution name."; } subtest "App::perlbrew#is_installed method." => sub { my $app = App::perlbrew->new; ok $app->can("is_installed"); ok $app->is_installed("perl-5.14.0"); ok !$app->is_installed("perl-5.13.0"); }; subtest "do not clobber exitsing user-specified name." => sub { my $app = App::perlbrew->new("install", "perl-5.14.0", "--as", "the-dude"); $app->run; my @installed = grep { !$_->{is_external} } $app->installed_perls; is 0+@installed, 2; ok grep { $_->{name} eq 'the-dude' } $app->installed_perls; dies_ok { my $app = App::perlbrew->new("install", "perl-5.14.0", "--as", "the-dude"); $app->run; } "should die when doing install with existing user-specified name."; }; done_testing; error-install-before-init.t000644001750001750 74014465441602 21104 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use Test::Exception; use File::Temp qw(tempdir); use App::perlbrew; use App::Perlbrew::Path; my $fakehome = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT = App::Perlbrew::Path->new($fakehome)->child("perl5")->stringify; throws_ok( sub { my $app = App::perlbrew->new("install", "perl-5.36.0"); $app->run; }, qr[ERROR: .*perlbrew init.*] ); done_testing; bashrc_content.t000644001750001750 332214465441602 17121 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse strict; use warnings; use App::perlbrew; use Test::Spec; local $App::perlbrew::PERLBREW_ROOT; local %ENV; sub describe_bashrc_content; describe "App::perlbrew->BASHRC_CONTENT()" => sub { context "should not export custom PERLBREW_ROOT" => sub { describe_bashrc_content "with default settings" => ( ); describe_bashrc_content "when set only via global variable" => ( PERLBREW_ROOT => 'perlbrew/root', ); }; context "should export custom PERLBREW_ROOT" => sub { describe_bashrc_content "when env variable PERLBREW_ROOT is set" => ( ENV_PERLBREW_ROOT => 'env/root', should_match => 'env/root', ); describe_bashrc_content "when provided via argument" => ( args => [qw[ --root arg/root ]], should_match => "arg/root", ); describe_bashrc_content "when provided via argument (favor over env)" => ( args => [qw[ --root arg/root ]], ENV_PERLBREW_ROOT => 'env/root', should_match => "arg/root", ); }; }; runtests unless caller; sub describe_bashrc_content { my ($title, %params) = @_; it $title => sub { local %ENV = ( HOME => 'default/home', (PERLBREW_ROOT => $params{ENV_PERLBREW_ROOT}) x!! exists $params{ENV_PERLBREW_ROOT}, ); local $App::perlbrew::PERLBREW_ROOT = $params{PERLBREW_ROOT} || $ENV{PERLBREW_ROOT}; my $app = App::perlbrew->new (@{ $params{args} || [] }); return ok $app->BASHRC_CONTENT =~ m{^export PERLBREW_ROOT=\Q$params{should_match}\E}m if $params{should_match}; return ok $app->BASHRC_CONTENT !~ m{^export PERLBREW_ROOT=}m; }; } 04.find_available_perls.t000644001750001750 1127414465441602 20521 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More; use App::perlbrew; plan tests => 52; my $html = <
ReleaseFileTypeAge
5.135.13.11perl-5.13.11.tar.gz, perl-5.13.11.tar.bz2devel14 days
5.125.12.3perl-5.12.3.tar.gz, perl-5.12.3.tar.bz2maint2 months, 11 days
5.105.10.1perl-5.10.1.tar.gz, perl-5.10.1.tar.bz2maint1 year, 7 months
5.85.8.9perl-5.8.9.tar.gz, perl-5.8.9.tar.bz2maint2 years, 3 months
5.65.6.2perl-5.6.2.tar.gzmaint7 years, 4 months
5.55.5.4perl5.005_04.tar.gzmaint7 years, 1 month
5.45.4.5perl5.004_05.tar.gzmaint11 years, 11 months
5.35.3.7perl5.003_07.tar.gzmaint14 years, 5 months

(A year is 365.2425 days and a month is 30.436875 days.)

HERE my @expected_releases = ( { 'file' => 'perl-5.13.11.tar.gz', 'type' => 'devel', 'release' => '5.13.11', 'age' => '14 days', 'branch' => '5.13' }, { 'file' => 'perl-5.12.3.tar.gz', 'type' => 'maint', 'release' => '5.12.3', 'age' => '2 months, 11 days', 'branch' => '5.12' }, { 'file' => 'perl-5.10.1.tar.gz', 'type' => 'maint', 'release' => '5.10.1', 'age' => '1 year, 7 months', 'branch' => '5.10' }, { 'file' => 'perl-5.8.9.tar.gz', 'type' => 'maint', 'release' => '5.8.9', 'age' => '2 years, 3 months', 'branch' => '5.8' }, { 'file' => 'perl-5.6.2.tar.gz', 'type' => 'maint', 'release' => '5.6.2', 'age' => '7 years, 4 months', 'branch' => '5.6' }, { 'file' => 'perl5.005_04.tar.gz', 'type' => 'maint', 'release' => '5.5.4', 'age' => '7 years, 1 month', 'branch' => '5.5' }, { 'file' => 'perl5.004_05.tar.gz', 'type' => 'maint', 'release' => '5.4.5', 'age' => '11 years, 11 months', 'branch' => '5.4' }, { 'file' => 'perl5.003_07.tar.gz', 'type' => 'maint', 'release' => '5.3.7', 'age' => '14 years, 5 months', 'branch' => '5.3' }, { 'file' => 'perl5.003_07.tar.gz', 'type' => 'maint', 'release' => '5.3.7', 'age' => '14 years, 5 months', 'branch' => '5.3' }, { 'file' => 'perl5.003_07.tar.gz', 'type' => 'maint', 'release' => '5.3.7', 'age' => '14 years, 5 months', 'branch' => '5.3' }, { 'file' => 'perl5.003_07.tar.gz', 'type' => 'maint', 'release' => '5.3.7', 'age' => '14 years, 5 months', 'branch' => '5.3' } ); my $app = App::perlbrew->new(); my @releases = (); for my $line ( split "\n", $html ) { $line =~ m|(.*)(.*).*(.*)(.*)|; push @releases, { branch => $1, release => $2, file => $3, type => $4, age => $5 } if ( $1 && $2 && $3 && $4 && $5 ); } is @releases => 11, 'found 11 releases'; is $releases[0]->{branch} => 5.13, '5.13 branch'; #is $releases[0]->{release} => 5.13, '5.13 branch'; TEST: for my $i ( 0 .. scalar @releases - 1 - 1 ) { is $releases[$i]->{branch} => $expected_releases[$i]->{branch}, "branch " . $releases[$i]->{branch} . " found"; is $releases[$i]->{release} => $expected_releases[$i]->{release}, "release " . $releases[$i]->{release} . " found"; is $releases[$i]->{file} => $expected_releases[$i]->{file}, "file " . $releases[$i]->{file} . " found"; is $releases[$i]->{type} => $expected_releases[$i]->{type}, "type " . $releases[$i]->{type} . " found"; is $releases[$i]->{age} => $expected_releases[$i]->{age}, "age " . $releases[$i]->{age} . " found"; } app-perlbrew-path.t000644001750001750 2123414465441602 17501 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use File::Temp qw[]; use Test::Spec; use Test::Exception; use Test::Deep; use App::Perlbrew::Path; sub looks_like_perlbrew_path; sub arrange_testdir; describe "App::Perlbrew::Path" => sub { describe "new()" => sub { it "should accept one parameter" => sub { my $path = App::Perlbrew::Path->new("foo/bar/baz"); cmp_deeply $path, looks_like_perlbrew_path "foo/bar/baz"; }; it "should concatenate multiple parameters into single path" => sub { my $path = App::Perlbrew::Path->new("foo", "bar/baz"); cmp_deeply $path, looks_like_perlbrew_path "foo/bar/baz"; }; it "should die with undefined element" => sub { throws_ok { App::Perlbrew::Path->new('foo', undef, 'bar') } qr/^Received an undefined entry as a parameter/, ''; }; it "should concatenate long (root) path" => sub { my $path = App::Perlbrew::Path->new('', qw(this is a long path to check if it is joined ok)); cmp_deeply $path, looks_like_perlbrew_path '/this/is/a/long/path/to/check/if/it/is/joined/ok'; }; }; describe "basename()" => sub { it "should return basename" => sub { my $path = App::Perlbrew::Path->new("foo/bar/baz.tar.gz"); is $path->basename, "baz.tar.gz"; }; it "should trim provided suffix match" => sub { my $path = App::Perlbrew::Path->new("foo/bar/baz.tar.gz"); is $path->basename(qr/\.tar\.(?:gz|bz2|xz)$/), "baz"; }; }; describe "child()" => sub { it "should create direct child" => sub { my $path = App::Perlbrew::Path->new("foo/bar")->child(1); cmp_deeply $path, looks_like_perlbrew_path "foo/bar/1"; }; it "should accept multiple children" => sub { my $path = App::Perlbrew::Path->new("foo/bar")->child(1, 2); cmp_deeply $path, looks_like_perlbrew_path "foo/bar/1/2"; }; it "should return chainable object" => sub { my $path = App::Perlbrew::Path->new("foo/bar")->child(1, 2)->child(3); cmp_deeply $path, looks_like_perlbrew_path "foo/bar/1/2/3"; }; }; describe "children()" => sub { it "should return empty list on empty match" => sub { my $root = arrange_testdir; cmp_deeply [ $root->children ], []; }; it "should return Path instances" => sub { my $root = arrange_testdir; $root->child($_)->mkpath for qw[ aa ab ba ]; cmp_deeply [ $root->children ], [ looks_like_perlbrew_path ($root->child('aa')->stringify), looks_like_perlbrew_path ($root->child('ab')->stringify), looks_like_perlbrew_path ($root->child('ba')->stringify), ]; }; }; describe "mkpath()" => sub { it "should create recursive path" => sub { my $path = arrange_testdir ("foo/bar/baz"); $path->mkpath; ok -d $path; }; it "should not die when path already exists" => sub { my $path = arrange_testdir ("foo/bar/baz"); $path->mkpath; lives_ok { $path->mkpath }; }; it "should return self" => sub { my $path = arrange_testdir ("foo/bar/baz"); cmp_deeply $path->mkpath, looks_like_perlbrew_path "$path"; }; }; describe "readlink()" => sub { my $test_root; my $link; before each => sub { $test_root = arrange_testdir; $link = $test_root->child('link'); }; context "when path doesn't exist" => sub { it "should return undef" => sub { is $link->readlink, undef; }; }; context "when path isn't a symlink" => sub { before each => sub { $link->mkpath }; it "should return undef" => sub { is $link->readlink, undef; }; }; context "should return path object of link content" => sub { my $dest; before each => sub { $dest = $test_root->child('dest'); $dest->mkpath; symlink $dest, $link; }; it "should return link path" => sub { my $read = $link->readlink; cmp_deeply $read, looks_like_perlbrew_path "$dest"; }; }; }; describe "rmpath()" => sub { it "should remove path recursively" => sub { my $path = arrange_testdir ("foo"); my $child = $path->child("bar/baz"); $child->mkpath; $path->rmpath; ok ! -d $path; }; it "should not die when path doesn't exist" => sub { my $path = arrange_testdir ("foo"); lives_ok { $path->rmpath }; }; it "should return self" => sub { my $path = arrange_testdir ("foo/bar/baz"); cmp_deeply $path, looks_like_perlbrew_path "$path"; }; }; describe "stringify_with_tilde" => sub { it "should expand leading homedir" => sub { local $ENV{HOME} = "/home/perlbrew"; my $path = App::Perlbrew::Path->new("/home/perlbrew/.root"); is $path->stringify_with_tilde, "~/.root"; }; it "should not expand leading homedir prefix" => sub { local $ENV{HOME} = "/home/perlbrew"; my $path = App::Perlbrew::Path->new("/home/perlbrew-stable/.root"); is $path->stringify_with_tilde, "/home/perlbrew-stable/.root"; }; }; describe "symlink()" => sub { it "should create symlink" => sub { my $root = arrange_testdir; my $file = $root->child('file'); open my $fh, '>>', $file or die $!; my $symlink = $file->symlink($root->child('symlink')); unless ($symlink) { fail; diag "Symlink failed: $!"; return; } unless ($symlink eq $root->child("symlink")) { fail; diag "is should return symlink object"; diag "got : $symlink"; diag "expected: $root/symlink"; return; } my $readlink = $symlink->readlink; unless ($readlink eq $file) { fail; diag "it should point to origin file"; diag "got : $readlink"; diag "expected: $root/file"; return; } pass; }; it "should replace existing file in force mode" => sub { my $root = arrange_testdir; my $file = $root->child('file'); open my $fh, '>>', $file or die $!; $root->child('foo')->symlink($root->child('symlink')) or diag "init failed: $!"; my $symlink = $file->symlink($root->child('symlink'), 'force'); unless ($symlink) { fail; diag "Symlink failed: $!"; return; } unless ($symlink eq $root->child("symlink")) { fail; diag "is should return symlink object"; diag "got : $symlink"; diag "expected: $root/symlink"; return; } my $readlink = $symlink->readlink; unless ($readlink eq $file) { fail; diag "it should point to origin file"; diag "got : $readlink"; diag "expected: $root/file"; return; } pass; }; }; describe "unlink()" => sub { it "should not report failure if file doesn't exist" => sub { my $root = arrange_testdir; my $file = $root->child('file'); $file->unlink; ok ! -e $file; }; it "should remove file" => sub { my $root = arrange_testdir; my $file = $root->child('file'); open my $fh, '>>', $file or die $!; fail and diag ("file doesn't exist yet") and return unless -e $file; $file->unlink; ok ! -e $file; }; }; return; }; runtests unless caller; sub looks_like_perlbrew_path { my ($expected) = @_; all ( methods (stringify => $expected), obj_isa ('App::Perlbrew::Path'), ); } sub arrange_testdir { my (@path) = @_; App::Perlbrew::Path->new(File::Temp::tempdir (CLEANUP => 1), @path); } error-http_download-param-validation.t000644001750001750 103414465441602 23346 0ustar00gugodgugod000000000000App-perlbrew-0.98/tuse strict; use warnings; use Test::More; use Test::Exception; use File::Temp qw(tempdir); use IO::All; use App::Perlbrew::HTTP qw(http_download); subtest "http_download: dies when when the download target already exists" => sub { my $dir = tempdir( CLEANUP => 1 ); my $output = "$dir/whatever"; io($output)->print("so"); my $error; throws_ok { $error = http_download( "https://install.perlbrew.pl", $output ); } qr(^ERROR: The download target < \Q$output\E > already exists\.$); }; done_testing; failure-command-install-patchperl.t000644001750001750 217614465441602 22622 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use Path::Class; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/patchperl$/, "GET patchperl url: $url"; return "Some invalid piece of text"; } } describe "App::perlbrew->install_patchperl" => sub { it "should not produce 'patchperl' in the bin dir, if the downloaded content does not seem to be valid." => sub { my $patchperl = file($perlbrew_root, "bin", "patchperl")->absolute; my $error; my $produced_error = 0; eval { my $app = App::perlbrew->new("install-patchperl", "-q"); $app->run(); } or do { $error = $@; $produced_error = 1; }; ok $produced_error, "generated an error: $error"; ok !(-f $patchperl), "patchperl is *not* installed: $patchperl"; }; }; runtests unless caller; command-available.t000644001750001750 623414465441602 17466 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use Test::Output; use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); my %available_perl_dists = ( 'perl-5.27.4' => 'http://www.cpan.org/src/5.0/perl-5.27.4.tar.gz', 'perl-5.26.1' => 'http://www.cpan.org/src/5.0/perl-5.26.1.tar.gz', 'perl-5.24.3' => 'http://www.cpan.org/src/5.0/perl-5.24.3.tar.gz', 'perl-5.22.4' => 'http://www.cpan.org/src/5.0/perl-5.22.4.tar.gz', 'perl-5.20.3' => 'http://www.cpan.org/src/5.0/perl-5.20.3.tar.gz', 'perl-5.18.4' => 'http://www.cpan.org/src/5.0/perl-5.18.4.tar.gz', 'perl-5.16.3' => 'http://www.cpan.org/src/5.0/perl-5.16.3.tar.gz', 'perl-5.14.4' => 'http://www.cpan.org/src/5.0/perl-5.14.4.tar.gz', 'perl-5.12.5' => 'http://www.cpan.org/src/5.0/perl-5.12.5.tar.gz', 'perl-5.10.1' => 'http://www.cpan.org/src/5.0/perl-5.10.1.tar.gz', 'perl-5.8.9' => 'http://www.cpan.org/src/5.0/perl-5.8.9.tar.gz', 'perl-5.6.2' => 'http://www.cpan.org/src/5.0/perl-5.6.2.tar.gz', 'perl5.005_04' => 'http://www.cpan.org/src/5.0/perl5.005_04.tar.gz', 'perl5.004_05' => 'http://www.cpan.org/src/5.0/perl5.004_05.tar.gz', ); sub mocked_perlbrew { my $app = App::perlbrew->new( @_ ); $app->expects( 'available_perl_distributions' )->returns( \%available_perl_dists ); return $app; } describe "available command output, when nothing installed locally," => sub { it "should display a list of perl versions" => sub { my $app = mocked_perlbrew( "available", "--verbose" ); stdout_like sub { $app->run(); }, qr{ \A ( \# .+ \n ( \s{3,}c?perl-?\d\.\d{1,3}[_.]\d{1,2} \s+ available \s from \s+ \s*? \n )+ \n )+ \z }sx; }; }; describe "available command output, when something installed locally," => sub { it "should display a list of perl versions, with markers on installed versions" => sub { my $app = mocked_perlbrew( "available", "--verbose" ); my @installed_perls = ( { name => "perl-5.24.0" }, { name => "perl-5.20.3" } ); $app->expects("installed_perls")->returns(@installed_perls); stdout_like sub { $app->run(); }, qr{ \A ( \# .+ \n ( \s{3,}perl-?\d\.\d{1,3}[_.]\d{1,2} \s+ ( INSTALLED \s on \s .+ \s via | available \s from ) \s+ \s*? \n )+ \n )+ \z }sx; }; }; runtests unless caller; command-help.t000644001750001750 327414465441602 16477 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; my $bin_perlbrew = file(__FILE__)->dirname->dirname->child("script")->child("perlbrew"); my $perl = $^X; # # Doing `App::perlbrew->new("help")->run` will make this test program exit(), # that's why we use backtick to test. # describe "`perlbrew`" => sub { it "should print some nice message and instruct user to read help for individual commands" => sub { my $out = `$perl -Ilib $bin_perlbrew help`; like $out, qr/perlbrew help /si; }; }; describe "`perlbrew -h`" => sub { it "should print short version of help message and instruct user to read longer version" => sub { my $out1 = `$perl -Ilib $bin_perlbrew --help`; my $out2 = `$perl -Ilib $bin_perlbrew -h`; is $out2, $out1; like $out1, qr/^ See `perlbrew help` for the full documentation/m; unlike $out1, qr/^CONFIGURATION$/m; }; }; describe "`perlbrew help`" => sub { it "should should the lengthy version " => sub { my $out = `$perl -Ilib $bin_perlbrew help`; like $out, qr/^CONFIGURATION$/m; }; it "should instruct user to read help for individual commands." => sub { my $out = `$perl -Ilib $bin_perlbrew help`; like $out, qr/perlbrew help /si; }; }; describe "`help install`" => sub { it "should show the options for install command" => sub { my $out = `$perl -Ilib $bin_perlbrew help install`; like $out, qr/^Options for "install" command:/msi; like $out, qr/--force/si; like $out, qr/--notest/si; }; }; runtests unless caller; command-install-from-archive.t000644001750001750 660314465441602 21574 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec 0.49; # with_deep use Test::Deep; use FindBin; use lib $FindBin::Bin; use App::perlbrew; use Hash::Util; require 'test_helpers.pl'; sub arrange_file; sub arrange_available_perls; sub arrange_command_line; sub expect_dispatch_via; sub should_install_from_archive; sub is_path; describe "command install " => sub { should_install_from_archive "with perl source archive" => ( filename => 'perl-5.28.0.tar.gz', dist_version => '5.28.0', installation_name => 'perl-5.28.0', ); should_install_from_archive "with perfixed perl source archive" => ( filename => 'downloaded-perl-5.28.0.tar.gz', dist_version => '5.28.0', installation_name => 'perl-5.28.0', ); should_install_from_archive "with cperl source archive" => ( filename => 'cperl-5.28.0.tar.gz', dist_version => '5.28.0', installation_name => 'cperl-5.28.0', ); should_install_from_archive "with prefixed cperl source archive" => ( filename => 'downloaded-cperl-5.28.0.tar.gz', dist_version => '5.28.0', installation_name => 'cperl-5.28.0', ); }; runtests unless caller; sub should_install_from_archive { my ($title, %params) = @_; Hash::Util::lock_keys %params, 'filename', 'dist_version', 'installation_name', ; context $title => sub { my $file; before each => sub { $file = arrange_file name => $params{filename},, tempdir => 1, ; arrange_command_line install => $file; }; expect_dispatch_via method => 'do_install_archive', with_args => [ is_path (methods (basename => $params{filename})) ]; expect_dispatch_via method => 'do_extract_tarball', stubs => { do_install_this => '' }, with_args => [ is_path (methods (basename => $params{filename})) ]; expect_dispatch_via method => 'do_install_this', stubs => { do_extract_tarball => sub { $_[-1]->dirname->child('foo') } }, with_args => [ is_path (methods (basename => 'foo')), $params{dist_version}, $params{installation_name}, ]; }; }; sub is_path { my (@tests) = @_; all ( obj_isa ('App::Perlbrew::Path'), @tests, ); } sub arrange_file { my (%params) = @_; my $dir; $dir ||= $params{dir} if $params{dir}; $dir ||= tempdir (CLEANUP => 1) if $params{tempdir}; $dir ||= '.'; my $file = file ($dir, $params{name}); open my $fh, '>', $file; close $fh; return $file; } sub arrange_command_line { my (@command_line) = @_; share my %shared; # Enforce stringification $shared{app} = App::perlbrew->new(map "$_", @command_line); } sub expect_dispatch_via { my (%params) = @_; it "should dispatch via $params{method}()" => sub { share my %shared; App::perlbrew->stubs(%{ $params{stubs} }) if $params{stubs}; my $expectation = App::perlbrew->expects($params{method}); $expectation = $expectation->with_deep(@{ $params{with_args} }) if $params{with_args}; $shared{app}->run; ok $expectation->verify; }; } error-http_download-exec-error.t000644001750001750 122214465441602 22170 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::More import => [ qw( done_testing like subtest ) ]; use File::Temp qw( tempdir ); BEGIN { *CORE::GLOBAL::system = sub { return $? = -1 }; } use App::Perlbrew::Path; use App::Perlbrew::HTTP qw(http_download); local $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); subtest "The exit status code of curl", sub { my $error = http_download( "https://example.com/whatever.tar.gz", App::Perlbrew::Path->new($App::perlbrew::PERLBREW_ROOT)->child("whatever.tar.gz") ); like $error, qr/^ERROR: Failed to execute the command/; }; done_testing; app-perlbrew-path-installation.t000644001750001750 657714465441602 22175 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use File::Temp qw[]; use Test::Spec; use Test::Deep; use App::Perlbrew::Path::Root; use App::Perlbrew::Path::Installation; use App::Perlbrew::Path::Installations; sub looks_like_path;; sub looks_like_perl_installation; sub looks_like_perl_installations; sub arrange_root; sub arrange_installation; describe "App::Perlbrew::Path::Root" => sub { describe "perls()" => sub { context "without parameters" => sub { it "should return Instalations object" => sub { local $ENV{HOME}; my $path = arrange_root->perls; cmp_deeply $path, looks_like_perl_installations("~/.root/perls"); }; }; context "with one parameter" => sub { it "should return Installation object" => sub { local $ENV{HOME}; my $path = arrange_root->perls('blead'); cmp_deeply $path, looks_like_perl_installation("~/.root/perls/blead"); }; }; context "with multiple paramters" => sub { it "should return Path object" => sub { local $ENV{HOME}; my $path = arrange_root->perls('blead', '.version'); cmp_deeply $path, looks_like_path("~/.root/perls/blead/.version"); }; } }; }; describe "App::Perlbrew::Path::Installations" => sub { describe "list()" => sub { it "should list known installations" => sub { local $ENV{HOME}; my $root = arrange_root; arrange_installation 'perl-1'; arrange_installation 'perl-2'; my @list = $root->perls->list; cmp_deeply \@list, [ looks_like_perl_installation("~/.root/perls/perl-1"), looks_like_perl_installation("~/.root/perls/perl-2"), ]; }; }; }; describe "App::Perlbrew::Path::Installation" => sub { describe "name()" => sub { it "should return installation name" => sub { local $ENV{HOME}; my $installation = arrange_installation('foo-bar'); cmp_deeply $installation->name, 'foo-bar'; }; it "should provide path to perl" => sub { local $ENV{HOME}; my $perl = arrange_installation('foo-bar')->perl; cmp_deeply $perl->stringify_with_tilde, '~/.root/perls/foo-bar/bin/perl'; }; it "should provide path to version file" => sub { local $ENV{HOME}; my $file = arrange_installation('foo-bar')->version_file; cmp_deeply $file->stringify_with_tilde, '~/.root/perls/foo-bar/.version'; }; }; }; runtests unless caller; sub looks_like_path { my ($path, @tests) = @_; my $method = $path =~ m/^~/ ? 'stringify_with_tilde' : 'stringify' ; all( methods($method => $path), Isa('App::Perlbrew::Path'), @tests, ); } sub looks_like_perl_installation { looks_like_path(@_, Isa('App::Perlbrew::Path::Installation')); } sub looks_like_perl_installations { looks_like_path(@_, Isa('App::Perlbrew::Path::Installations')); } sub arrange_root { $ENV{HOME} ||= File::Temp::tempdir(CLEANUP => 1); App::Perlbrew::Path::Root->new($ENV{HOME}, '.root')->mkpath; } sub arrange_installation { my ($name) = @_; my $root = arrange_root; $root->perls($name)->mkpath; } installation3.t000644001750001750 162714465441602 16717 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; BEGIN { delete $ENV{PERLBREW_LIB}; } use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; { no warnings 'redefine'; sub App::perlbrew::available_perls { return map { "perl-$_" } qw<5.8.9 5.17.7 5.16.2 5.14.3 5.12.5 5.10.1>; } sub App::perlbrew::switch_to { shift->current_perl(shift); } } plan tests => 3; { my $app = App::perlbrew->new("install", "--switch", "perl-stable"); $app->run; my @installed = $app->installed_perls; is 0+@installed, 1, "install perl-stable installs one perl"; is $installed[0]{name}, "perl-5.16.2", "install perl-stable installs correct perl"; ok $installed[0]{is_current}, "install --switch automatically switches to the installed perl" or diag explain $installed[0]; } done_testing; Build.PL000644001750001750 16614465441602 14754 0ustar00gugodgugod000000000000App-perlbrew-0.98# This Build.PL for App-perlbrew was generated by mbtiny 0.041. use 5.008; use Module::Build::Tiny 0.039; Build_PL(); 11.root_from_arg.t000644001750001750 431514465441602 17207 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use File::Temp qw(tempdir); use Test::Deep qw[]; use Test::Spec; sub looks_like_perlbrew_root; local $App::perlbrew::PERLBREW_ROOT = '/perlbrew/root'; local $ENV{PERLBREW_ROOT} = '/env/root'; local $ENV{HOME} = '/home'; describe "App::perlbrew#root method" => sub { it "should return \$App::perlbrew::PERLBREW_ROOT if provided" => sub { my $app = App::perlbrew->new; looks_like_perlbrew_root $app->root, '/perlbrew/root'; }; it "should default to \$ENV{PERLBREW_ROOT} if provided" => sub { local $App::perlbrew::PERLBREW_ROOT; my $app = App::perlbrew->new; looks_like_perlbrew_root $app->root, '/env/root'; }; it "should default to \$ENV{HOME} subpath" => sub { local $App::perlbrew::PERLBREW_ROOT; local $ENV{PERLBREW_ROOT}; my $app = App::perlbrew->new; looks_like_perlbrew_root $app->root, '/home/perl5/perlbrew'; }; it "should return the instance property of 'root' if set" => sub { my $app = App::perlbrew->new; $app->root("/fnord"); looks_like_perlbrew_root $app->root, "/fnord"; }; }; describe "App::perlbrew->new" => sub { it "should accept --root args and treat it as the value of PERLBREW_ROOT for the instance" => sub { my $temp_perlbrew_root = tempdir( CLEANUP => 1); my $app = App::perlbrew->new("--root" => $temp_perlbrew_root); looks_like_perlbrew_root $app->root, $temp_perlbrew_root; }; }; runtests unless caller; sub looks_like_perlbrew_root { my ($got, $expected) = @_; my ($ok, $stack); ($ok, $stack) = Test::Deep::cmp_details "$got", "$expected"; unless ($ok) { fail; diag "Return value comparison failed"; diag Test::Deep::deep_diag $stack; return; } ($ok, $stack) = Test::Deep::cmp_details "$got", "$App::perlbrew::PERLBREW_ROOT"; unless ($ok) { fail; diag "Global \$PERLBREW_ROOT comparison failed"; diag Test::Deep::deep_diag $stack; return; } return Test::Deep::cmp_deeply $got, Isa ('App::Perlbrew::Path::Root'); } command-install-patchperl.t000644001750001750 165514465441602 21176 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/patchperl$/, "GET patchperl url: $url"; return "#!/usr/bin/env perl\n# The content of patchperl"; } } describe "App::perlbrew->install_patchperl" => sub { it "should produce 'patchperl' in the bin dir" => sub { my $app = App::perlbrew->new("install-patchperl", "-q"); $app->run(); my $patchperl = App::Perlbrew::Path->new ($perlbrew_root, "bin", "patchperl"); ok -f $patchperl, "patchperl is produced. $patchperl"; ok -x $patchperl, "patchperl should be an executable."; }; }; runtests unless caller; 05.get_current_perl.t000644001750001750 231314465441602 17712 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Output; mock_perlbrew_install("perl-5.12.3"); mock_perlbrew_install("perl-5.12.4"); mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.14.2"); subtest "perlbrew version" => sub { my $version = $App::perlbrew::VERSION; stdout_like( sub { my $app = App::perlbrew->new("version"); $app->run; } => qr{(?:\./)?\Qt/05.get_current_perl.t - App::perlbrew/$version\E\n} ); }; subtest "Current perl is decided from environment variable PERLBREW_PERL" => sub { for my $v (qw(perl-5.12.3 perl-5.12.3 perl-5.14.1 perl-5.14.2)) { local $ENV{PERLBREW_PERL} = $v; my $app = App::perlbrew->new; is $app->current_perl, $v; } }; subtest "Current perl can be decided from object attribute, which overrides env var." => sub { local $ENV{PERLBREW_PERL} = "perl-5.12.3"; for my $v (qw(perl-5.12.3 perl-5.12.3 perl-5.14.1 perl-5.14.2)) { my $app = App::perlbrew->new; $app->{current_perl} = $v; is $app->current_perl, $v; } }; done_testing; command-display-rc.t000644001750001750 117714465441602 17616 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); $ENV{PERLBREW_ROOT} = my $perlbrew_root = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_HOME} = my $perlbrew_home = tempdir( CLEANUP => 1 ); use App::perlbrew; describe "App::perlbrew" => sub { my $app; before each => sub { $app = App::perlbrew->new; }; it "should be able to run 'display-bashrc' command" => sub { ok $app->can("run_command_display_bashrc"); }; it "should be able to run 'display-cshrc' command" => sub { ok $app->can("run_command_display_cshrc"); }; }; runtests unless caller; Installation.pm000644001750001750 54114465441602 22420 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/App/Perlbrew/Pathuse strict; use warnings; package App::Perlbrew::Path::Installation; require App::Perlbrew::Path; our @ISA = qw( App::Perlbrew::Path ); sub name { $_[0]->basename; } sub bin { shift->child(bin => @_); } sub man { shift->child(man => @_); } sub perl { shift->bin('perl'); } sub version_file { shift->child('.version'); } 1; command-env.t000644001750001750 711714465441602 16337 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; BEGIN { $ENV{SHELL} = "/bin/bash" } use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; use Test::Output; use Config; mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_lib_create('perl-5.14.1@nobita'); describe "env command," => sub { before each => sub { delete $ENV{PERL_MB_OPT}; delete $ENV{PERL_MM_OPT}; delete $ENV{PERL_LOCAL_LIB_ROOT}; delete $ENV{PERLBREW_LIB}; delete $ENV{PERL5LIB}; delete $ENV{PERLBREW_LIB_PREFIX}; }; describe "when invoked with a perl installation name,", sub { it "displays environment variables that should be set to use the given perl." => sub { my $app = App::perlbrew->new("env", "perl-5.14.1"); stdout_is { $app->run; } <<"OUT"; unset PERL5LIB unset PERLBREW_LIB export PERLBREW_MANPATH="$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/man" export PERLBREW_PATH="$App::perlbrew::PERLBREW_ROOT/bin:$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/bin" export PERLBREW_PERL="perl-5.14.1" export PERLBREW_ROOT="$App::perlbrew::PERLBREW_ROOT" export PERLBREW_VERSION="$App::perlbrew::VERSION" unset PERL_LOCAL_LIB_ROOT OUT }; }; describe "when invoked with a perl installation name with lib name,", sub { it "displays local::lib-related environment variables that should be set to use the given perl." => sub { note 'perlbrew env perl-5.14.1@nobita'; my $PERL5LIB_maybe = $ENV{PERL5LIB} ? ":\$PERL5LIB" : ""; my $app = App::perlbrew->new("env", 'perl-5.14.1@nobita'); my $lib_dir = "$App::perlbrew::PERLBREW_HOME/libs/perl-5.14.1\@nobita"; stdout_is { $app->run; } <<"OUT"; export PERL5LIB="$lib_dir/lib/perl5${PERL5LIB_maybe}" export PERLBREW_LIB="nobita" export PERLBREW_MANPATH="$lib_dir/man:$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/man" export PERLBREW_PATH="$lib_dir/bin:$App::perlbrew::PERLBREW_ROOT/bin:$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/bin" export PERLBREW_PERL="perl-5.14.1" export PERLBREW_ROOT="$App::perlbrew::PERLBREW_ROOT" export PERLBREW_VERSION="$App::perlbrew::VERSION" export PERL_LOCAL_LIB_ROOT="$lib_dir" export PERL_MB_OPT="--install_base "$lib_dir"" export PERL_MM_OPT="INSTALL_BASE=$lib_dir" OUT } }; describe "when invoked with a perl installation name with lib name and PERLBREW_LIB_PREFIX set,", sub { it "displays PERL5LIB with PERLBREW_LIB_PREFIX value first." => sub { note 'perlbrew env perl-5.14.1@nobita'; $ENV{PERLBREW_LIB_PREFIX} = 'perlbrew_lib_prefix'; my $PERL5LIB_maybe = $ENV{PERL5LIB} ? ":\$PERL5LIB" : ""; my $app = App::perlbrew->new("env", 'perl-5.14.1@nobita'); my $lib_dir = "$App::perlbrew::PERLBREW_HOME/libs/perl-5.14.1\@nobita"; stdout_is { $app->run; } <<"OUT"; export PERL5LIB="$ENV{PERLBREW_LIB_PREFIX}:$lib_dir/lib/perl5${PERL5LIB_maybe}" export PERLBREW_LIB="nobita" export PERLBREW_MANPATH="$lib_dir/man:$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/man" export PERLBREW_PATH="$lib_dir/bin:$App::perlbrew::PERLBREW_ROOT/bin:$App::perlbrew::PERLBREW_ROOT/perls/perl-5.14.1/bin" export PERLBREW_PERL="perl-5.14.1" export PERLBREW_ROOT="$App::perlbrew::PERLBREW_ROOT" export PERLBREW_VERSION="$App::perlbrew::VERSION" export PERL_LOCAL_LIB_ROOT="$lib_dir" export PERL_MB_OPT="--install_base "$lib_dir"" export PERL_MM_OPT="INSTALL_BASE=$lib_dir" OUT } } }; runtests unless caller; META.yml000644001750001750 312514465441602 14747 0ustar00gugodgugod000000000000App-perlbrew-0.98--- abstract: 'Manage perl installations in your C<$HOME>' author: - 'Kang-min Liu C<< >>' build_requires: File::Which: '1.21' IO::All: '0.51' Path::Class: '0.33' Test::Exception: '0.32' Test::More: '1.001002' Test::NoWarnings: '1.04' Test::Output: '1.03' Test::Simple: '1.001002' Test::Spec: '0.49' Test::TempDir::Tiny: '0.016' configure_requires: Module::Build::Tiny: '0.039' dynamic_config: 0 generated_by: 'App::ModuleBuildTiny version 0.041, CPAN::Meta::Converter version 2.150010' license: mit meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: App-perlbrew provides: App::Perlbrew::HTTP: file: lib/App/Perlbrew/HTTP.pm App::Perlbrew::Path: file: lib/App/Perlbrew/Path.pm App::Perlbrew::Path::Installation: file: lib/App/Perlbrew/Path/Installation.pm App::Perlbrew::Path::Installations: file: lib/App/Perlbrew/Path/Installations.pm App::Perlbrew::Path::Root: file: lib/App/Perlbrew/Path/Root.pm App::Perlbrew::Util: file: lib/App/Perlbrew/Util.pm App::perlbrew: file: lib/App/perlbrew.pm version: '0.98' requires: CPAN::Perl::Releases: '5.20230720' Capture::Tiny: '0.48' Devel::PatchPerl: '2.08' ExtUtils::MakeMaker: '7.22' File::Copy: '0' File::Temp: '0.2304' JSON::PP: '0' Pod::Usage: '1.69' local::lib: '2.000014' resources: bugtracker: https://github.com/gugod/App-perlbrew/issues repository: https://github.com/gugod/App-perlbrew.git version: '0.98' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' x_spdx_expression: MIT x_static_install: '1' 18.release-detail-perl-remote.t000644001750001750 144214465441602 21466 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!perl use strict; use App::perlbrew; use File::Temp qw( tempdir ); $App::perlbrew::PERLBREW_ROOT = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = tempdir( CLEANUP => 1 ); $ENV{PERLBREW_ROOT} = $App::perlbrew::PERLBREW_ROOT; use Test::More; unless ($ENV{TEST_LIVE}) { plan skip_all => 'These tests send HTTP requests. Set env TEST_LIVE=1 to really run them.'; } my $app = App::perlbrew->new(); $app->cpan_mirror("https://www.cpan.org"); my $rd = { type => "perl", "version" => "5.18.2" }; my ($error, undef) = $app->release_detail_perl_remote("perl-5.18.2", $rd); ok !$error; ok defined( $rd->{tarball_url} ); ok defined( $rd->{tarball_name} ); is $rd->{tarball_url}, "https://www.cpan.org/src/5.0/perl-5.18.2.tar.bz2"; is $rd->{tarball_name}, "perl-5.18.2.tar.bz2"; done_testing; builddir.t000644001750001750 253014465441602 15723 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; sub looks_like_perlbrew_builddir; describe "App::perlbrew#builddir method" => sub { it "should return path in \$App::perlbrew::PERLBREW_ROOT normally" => sub { local $App::perlbrew::PERLBREW_ROOT = '/perlbrew/root'; my $app = App::perlbrew->new; looks_like_perlbrew_builddir $app->builddir, '/perlbrew/root/build'; }; it "should return path relative to root" => sub { my $app = App::perlbrew->new; $app->root("/fnord"); looks_like_perlbrew_builddir $app->builddir, "/fnord/build"; }; }; describe "App::perlbrew->new" => sub { it "should accept --builddir args" => sub { local $App::perlbrew::PERLBREW_ROOT = '/perlbrew/root'; my $app = App::perlbrew->new("--builddir" => "/perlbrew/buildroot"); looks_like_perlbrew_builddir $app->builddir, "/perlbrew/buildroot"; }; }; runtests unless caller; sub looks_like_perlbrew_builddir { my ($got, $expected) = @_; my ($ok, $stack); ($ok, $stack) = Test::Deep::cmp_details "$got", "$expected"; unless ($ok) { fail; diag Test::Deep::deep_diag $stack; return; } return Test::Deep::cmp_deeply $got, Isa ('App::Perlbrew::Path'); } 08.error_install_cpanm.t000644001750001750 62014465441602 20366 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Exception; no warnings 'redefine'; sub App::perlbrew::http_get { "" } throws_ok( sub { my $app = App::perlbrew->new("install-cpanm"); $app->run; }, qr[ERROR: Failed to retrieve cpanm executable.] ); done_testing; 08.error_install_cpm.t000644001750001750 61414465441602 20052 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Exception; no warnings 'redefine'; sub App::perlbrew::http_get { "" } throws_ok( sub { my $app = App::perlbrew->new("install-cpm"); $app->run; }, qr[ERROR: Failed to retrieve cpm executable.] ); done_testing; command-make-shim.t000644001750001750 432514465441602 17420 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use Test::Exception; use File::Temp qw( tempdir ); use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; mock_perlbrew_install("perl-5.36.1"); describe "App::perlbrew->make_shim()" => sub { it "should show usage", sub { mock_perlbrew_use("perl-5.36.1"); lives_ok { my $app = App::perlbrew->new("make-shim"); $app->expects("run_command_help")->returns("")->at_least_once; $app->run; }; }; }; describe "App::perlbrew->make_shim('foo')" => sub { it "should err when perlbrew is off" => sub { mock_perlbrew_off(); my $dir = tempdir(); chdir($dir); throws_ok { my $app = App::perlbrew->new("make-shim", "foo"); $app->run(); } qr(^ERROR:); ok ! -f "foo", "foo is not produced"; }; it "should err when 'foo' already exists" => sub { mock_perlbrew_use("perl-5.36.1"); my $dir = tempdir(); chdir($dir); io("foo")->print("hello"); throws_ok { my $app = App::perlbrew->new("make-shim", "foo"); $app->run(); } qr(^ERROR:); throws_ok { my $app = App::perlbrew->new("make-shim", "-o", "foo", "bar"); $app->run(); } qr(^ERROR:); }; it "should produce 'foo' in the current dir" => sub { mock_perlbrew_use("perl-5.36.1"); my $dir = tempdir(); chdir($dir); my $app = App::perlbrew->new("make-shim", "foo"); $app->run(); ok -f "foo", "foo is produced under current directory."; my $shim_content = io("foo")->slurp; diag "\nThe content of shim:\n----\n$shim_content\n----\n"; }; it "should produce 'foo' in the current dir" => sub { mock_perlbrew_use("perl-5.36.1"); my $dir = tempdir(); chdir($dir); my $app = App::perlbrew->new("make-shim", "-o", "foo", "bar"); $app->run(); ok -f "foo", "foo is produced under current directory."; my $shim_content = io("foo")->slurp; diag "\nThe content of shim:\n----\n$shim_content\n----\n"; }; }; runtests unless caller; perlbrew000644001750001750 5747314465441602 16606 0ustar00gugodgugod000000000000App-perlbrew-0.98/script#!/usr/bin/perl use strict; use App::perlbrew; my $app = App::perlbrew->new(@ARGV); $app->run(); __END__ =head1 NAME perlbrew - Perl environment manager. =head1 SYNOPSIS perlbrew command syntax: perlbrew [options] [arguments] Commands: init Initialize perlbrew environment. info Show useful information about the perlbrew installation install Install perl uninstall Uninstall the given installation available List perls available to install lib Manage local::lib directories. alias Give perl installations a new name upgrade-perl Upgrade the current perl list List perl installations use Use the specified perl in current shell off Turn off perlbrew in current shell switch Permanently use the specified perl as default switch-off Permanently turn off perlbrew (revert to system perl) exec Execute programs with specified perl environments. list-modules List installed CPAN modules for the current Perl version in use clone-modules Re-installs all CPAN modules from one installation to another self-install Install perlbrew itself under PERLBREW_ROOT/bin self-upgrade Upgrade perlbrew itself. install-patchperl Install patchperl install-cpanm Install cpanm, a friendly companion. install-cpm Install cpm, a faster but still friendly companion. install-multiple Install multiple versions and flavors of perl download Download the specified perl distribution tarball. clean Purge tarballs and build directories version Display version help Read more detailed instructions Generic command options: -q --quiet Be quiet on informative output message. -v --verbose Tell me more about it. See `perlbrew help` for the full documentation of perlbrew, or See `perlbrew help ` for detail description of the command. =head1 CONFIGURATION =over 4 =item PERLBREW_ROOT By default, perlbrew builds and installs perls into C<$ENV{HOME}/perl5/perlbrew> directory. To use a different directory, set this environment variable in your C to the directory in your shell RC before sourcing perlbrew's RC. It is possible to share one perlbrew root with multiple user account on the same machine. Therefore people do not have to install the same version of perl over an over. Let's say C is the directory we want to share. All users should be able append this snippet to their bashrc to make it effective: export PERLBREW_ROOT=/opt/perl5 source ${PERLBREW_ROOT}/etc/bashrc After doing so, everyone's PATH should include C and C. Each user can invoke C and C to independently switch to different perl environment of their choice. However, only the user with write permission to C<$PERLBREW_ROOT> may install CPAN modules. This is both good and bad depending on the working convention of your team. If you wish to install CPAN modules only for yourself, you should use the C command to construct a personal local::lib environment. local::lib environments are personal, and are not shared between different users. For more detail, read C and the documentation of L. If you want even a cooler module isolation and wish to install CPAN modules used for just one project, you should use L for this purpose. It is also possible to set this variable before installing perlbrew to make perlbrew install itself under the given PERLBREW_ROOT: export PERLBREW_ROOT=/opt/perl5 curl -L https://install.perlbrew.pl | bash After doing this, the perlbrew executable is installed as C =item PERLBREW_HOME By default, perlbrew stores per-user setting to C<$ENV{HOME}/.perlbrew> directory. To use a different directory, set this environment variable in your shell RC before sourcing perlbrew's RC. In some cases, say, your home directory is on NFS and shared across multiple machines, you may wish to have several different perlbrew setting per-machine. To do so, you can use the C environment variable to tell perlbrew where to look for the initialization file. Here's a brief bash snippet for the given scenario. if [ "$(hostname)" == "machine-a" ]; then export PERLBREW_HOME=~/.perlbrew-a elif [ "$(hostname)" == "machine-b" ]; then export PERLBREW_HOME=~/.perlbrew-b fi source ~/perl5/perlbrew/etc/bashrc =item PERLBREW_CONFIGURE_FLAGS This environment variable specify the list of command like flags to pass through to 'sh Configure'. By default it is '-de'. =item PERLBREW_CPAN_MIRROR The CPAN mirror url of your choice. By default, "https://cpan.metacpan.org" is used. =back =head1 COMMAND: INIT Usage: perlbrew init The C command should be manually invoked whenever you (the perlbrew user) upgrade or reinstall perlbrew. If the upgrade is done with C command, or by running the one-line installer manually, this command is invoked automatically. =head1 COMMAND: INFO =over 4 =item B [module] Usage: perlbrew info [ ] Display useful information about the perlbrew installation. If a module is given the version and location of the module is displayed. =back =head1 COMMAND: INSTALL Usage: perlbrew install [options] perlbrew install [options] /path/to/perl-5.14.0.tar.gz perlbrew install [options] /path/to/perl/git/checkout/dir perlbrew install [options] https://example.com/mirror/perl-5.12.3.tar.gz Build and install the wanted perl. The last argument can be a short string designating a specific version which can be known from the output of C, a path to a pre-downloaded tarball, a path to a git-checkout of perl5 repo, or a URL to a tarball. The format of looks like: =over 4 =item perl- =item perl-stable =item perl-blead =item =item stable =item blead =back Version numbers usually look like "5.x.xx", or "perl-5.xx.x-RCx" for release candidates. Version "stable" is a special token that means whatever the latest stable version is at the moment. Version "blead" is also a special token that means whatever the latest version in the repository, which is downloaded from this specific URL regardless of mirror settings: https://github.com/Perl/perl5/archive/blead.tar.gz The specified perl is downloaded from the official CPAN website or from the mirror site configured before. Version number alone without the "perl-" prefix means the official release provided by perl5 porters. Options for C command: -f --force Force installation -j $n Parallel building and testing. ex. C -n --notest Skip testing --switch Automatically switch to this Perl once successfully installed, as if with `perlbrew switch ` --as Install the given version of perl by a name. ex. C --noman Skip installation of manpages --thread Build perl with usethreads enabled --multi Build perl with usemultiplicity enabled --64int Build perl with use64bitint enabled --64all Build perl with use64bitall enabled --ld Build perl with uselongdouble enabled --debug Build perl with DEBUGGING enabled --clang Build perl using the clang compiler --no-patchperl Skip calling patchperl -D,-U,-A Switches passed to perl Configure script. ex. C --destdir $path Install perl as per 'make install DESTDIR=$path' --sitecustomize $filename Specify a file to be installed as sitecustomize.pl --mirror $URL Specify a CPAN-mirror URL. The default value of this is "https://www.cpan.org" By default, all installations are configured after their name like this: sh Configure -de -Dprefix=$PERLBREW_ROOT/perls/ =head1 COMMAND: INSTALL-MULTIPLE Usage: perlbrew install-multiple [options] ... Build and install the given versions of perl. C accepts the same set of options as the command C plus the following ones: --both $flavor Where $flavor is one of C, C, C, C<64int>, C<64all>, C and C. For every given perl version, install two flavors, one with the flag C<--$flavor> set and the other with out. C<--both> can be passed multiple times with different values and in that case, all the possible combinations are generated. --common-variations equivalent to C<--both thread --both ld --both 64int> --all-variations generates all the possible flavor combinations --append $string Appends the given string to the generated names For instance: perlbrew install-multiple 5.18.0 blead --both thread --both debug Installs the following perls: perl-blead perl-blead-debug perl-blead-thread-multi perl-blead-thread-multi-debug perl-5.18.0 perl-5.18.0-debug perl-5.18.0-thread-multi perl-5.18.0-thread-multi-debug (note that the C flavor is selected automatically because C requires it) Another example using custom compilation flags: perlbrew install-multiple 5.18.0 --both thread -Doptimize='-O3' --append='-O3' =head1 COMMAND: UNINSTALL Usage: perlbrew uninstall Uninstalls the given perl installation. The name is the installation name as in the output of `perlbrew list`. This effectively deletes the specified perl installation, and all libs associated with it. =head1 COMMAND: USE Usage: perlbrew B [perl- | | ] Use the given version perl in current shell. This will not effect newly opened shells. Without a parameter, shows the version of perl currently in use. =head1 COMMAND: SWITCH Usage: perlbrew switch [ ] Switch to the given version, and makes it the default for this and all future terminal sessions. Without a parameter, shows the version of perl currently selected. =head1 COMMAND: LIST Usage: perlbrew list List all perl installations inside perlbrew root specified by C<$PERLBREW_ROOT> environment variable. By default, the value is C<~/perl5/perlbrew>. If there are libs associated to some perl installations, they will be included as part of the name. The output items in this list can be the argument in various other commands. =head1 COMMAND: AVAILABLE Usage: perlbrew available [--all] List the recently available versions of perl on CPAN. By default, the latest sub-version of each stable versions are listed. To get a list of all perls ever released, inculding development and RC versions, run the command with C<--all> option. =head1 COMMAND: OFF Usage: perlbrew off Temporarily disable perlbrew in the current shell. Effectively re-enables the default system Perl, whatever that is. This command works only if you add the statement of `source $PERLBREW_ROOT/etc/bashrc` in your shell initialization (bashrc / zshrc). =head1 COMMAND: SWITCH-OFF Usage: perlbrew switch-off Permananently disable perlbrew. Use C command to re-enable it. Invoke C command to enable it only in the current shell. Re-enables the default system Perl, whatever that is. =head1 COMMAND: ALIAS Usage: perlbrew alias [-f] create Create an alias for the installation named . Usage: perlbrew alias [-f] rename Rename the alias to a new name. Usage: perlbrew alias delete Delete the given alias. =head1 COMMAND: EXEC Usage: perlbrew exec [options] Options for C command: --with perl-version,... - only use these versions --min n.nnnnn - minimum perl version (format is the same as in 'use 5.012') --max n.nnnnn - maximum perl version --halt-on-error - stop on first nonzero exit status Execute command for each perl installations, one by one. For example, run a Hello program: perlbrew exec perl -e 'print "Hello from $]\n"' The output looks like this: perl-5.12.2 ========== Hello word from perl-5.012002 perl-5.13.10 ========== Hello word from perl-5.013010 perl-5.14.0 ========== Hello word from perl-5.014000 Notice that the command is not executed in parallel. When C<--with> argument is provided, the command will be only executed with the specified perl installations. The following command install Moose module into perl-5.12, regardless the current perl: perlbrew exec --with perl-5.12 cpanm Moose Multiple installation names can be provided: perlbrew exec --with perl-5.12,perl-5.12-debug,perl-5.14.2 cpanm Moo They are split by either spaces or commas. When spaces are used, it is required to quote the whole specification as one argument, but then commas can be used in the installation names: perlbrew exec --with '5.12 5.12,debug 5.14.2@nobita @shizuka' cpanm Moo As demonstrated above, "perl-" prefix can be omitted, and lib names can be specified too. Lib names can appear without a perl installation name, in such cases it is assumed to be "current perl". At the moment, any specified names that fails to be resolved as a real installation names are silently ignored in the output. Also, the command exit status are not populated back. =head1 COMMAND: ENV Usage: perlbrew env [ ] Low-level command. Invoke this command to see the list of environment variables that are set by C itself for shell integration. The output is something similar to this (if your shell is bash/zsh): export PERLBREW_ROOT=/Users/gugod/perl5/perlbrew export PERLBREW_VERSION=0.31 export PERLBREW_PATH=/Users/gugod/perl5/perlbrew/bin:/Users/gugod/perl5/perlbrew/perls/current/bin export PERLBREW_PERL=perl-5.14.1 tcsh / csh users should see 'setenv' statements instead of `export`. =head1 COMMAND: SYMLINK-EXECUTABLES Usage: perlbrew symlink-executables [ ] Low-level command. This command is used to create the C executable symbolic link to, say, C. This is only required for development version of perls. You don't need to do this unless you have been using old perlbrew to install perls, and you find yourself confused because the perl that you just installed appears to be missing after invoking `use` or `switch`. perlbrew changes its installation layout since version 0.11, which generates symlinks to executables in a better way. If you just upgraded perlbrew (from 0.11 or earlier versions) and C failed to work after you switch to a development release of perl, say, perl-5.13.6, run this command: perlbrew symlink-executables perl-5.13.6 This essentially creates this symlink: ${PERLBREW_ROOT}/perls/perl-5.13.6/bin/perl -> ${PERLBREW_ROOT}/perls/perl-5.13.6/bin/perl5.13.6 Newly installed perls, whether they are development versions or not, does not need manually treatment with this command. =head1 COMMAND: INSTALL-CPANM Usage: perlbrew install-cpanm Install the C standalone executable in C<$PERLBREW_ROOT/bin>. For more rationale about the existence of this command, read Usage: perlbrew install-cpm Install the C standalone executable in C<$PERLBREW_ROOT/bin>. =head1 COMMAND: INSTALL-PATCHPERL Usage: perlbrew install-patchperl Install the C standalone executable in C<$PERLBREW_ROOT/bin>. This is automatically invoked if your perlbrew installation is done with the installer, but not with cpan. For more rationale about the existence of this command, read =head1 COMMAND: SELF-UPGRADE Usage: perlbrew self-upgrade This command upgrades Perlbrew to its latest version. =head1 COMMAND: SELF-INSTALL Usage: perlbrew self-install NOTICE: You should not need to run this command in your daily routine. This command installs perlbrew itself to C<$PERLBREW_ROOT/bin>. It is intended to be used by the perlbrew installer. However, you could manually do the following to re-install only the C executable: curl https://raw.githubusercontent.com/gugod/App-perlbrew/master/perlbrew -o perlbrew perl ./perlbrew self-install It is slightly different from running the perlbrew installer because C is not installed in this case. =head1 COMMAND: CLEAN Usage: perlbrew clean Removes all previously downloaded Perl tarballs and build directories. =head1 COMMAND: VERSION Usage: perlbrew version Show the version of perlbrew. =head1 COMMAND: LIB Usage: perlbrew lib perlbrew lib list perlbrew lib create perlbrew lib delete The `lib` command is used to manipulate local::lib roots inside perl installations. Effectively it is similar to `perl -Mlocal::lib=/path/to/lib-name`, but a little bit more than just that. A lib name can be a short name, containing alphanumeric, like 'awesome', or a full name, prefixed by a perl installation name and a '@' sign, for example, 'perl-5.14.2@awesome'. Here are some a brief examples to invoke the `lib` command: # Create lib perl-5.12.3@shizuka perlbrew lib create perl-5.12.3@shizuka # Create lib perl-5.14.2@nobita and perl-5.14.2@shizuka perlbrew use perl-5.14.2 perlbrew lib create nobita perlbrew lib create shizuka # See the list of use/switch targets perlbrew list # Activate a lib in current shell perlbrew use perl-5.12.3@shizuka perlbrew use perl-5.14.2@nobita perlbrew use perl-5.14.2@shizuka # Activate a lib as default perlbrew switch perl-5.12.3@shizuka perlbrew switch perl-5.14.2@nobita perlbrew switch perl-5.14.2@shizuka # Delete lib perl-5.14.2@nobita and perl-5.14.2@shizuka perlbrew use perl-5.14.2 perlbrew lib delete nobita perlbrew lib delete shizuka # Delete lib perl-5.12.3@shizuka perlbrew lib delete perl-5.12.3@shizuka Short lib names are local to current perl. A lib name 'nobita' can refer to 'perl-5.12.3@nobita' or 'perl-5.14.2@nobita', whichever is activated in the current shell. When Cing or Cing to a lib, always provide the long name. A simple rule: the argument to C or C command should appear in the output of C. =head1 COMMAND: UPGRADE-PERL Usage: perlbrew upgrade-perl Running this command upgrades the currently activated perl to its latest released brothers. If you have a shell with 5.32.0 activated, it upgrades it to 5.32.1. Minor Perl releases (ex. 5.x.*) are binary compatible with one another, so this command offers you the ability to upgrade older perlbrew environments in place. =head1 COMMAND: DOWNLOAD Usage: perlbrew download Examples: perlbrew download perl-5.14.2 perlbrew download perl-5.16.1 perlbrew download perl-5.17.3 Download the specified version of perl distribution tarball under the directory C<< $PERLBREW_ROOT/dists/ >>. The argument C should be one of the items from C command. =head1 COMMAND: LIST-MODULES Usage: perlbrew list-modules List all installed cpan modules for the current perl. This command can be used in conjunction with `perlbrew exec` to migrate your module installation to different perl. The following command re-installs all modules under perl-5.16.0: perlbrew list-modules | perlbrew exec --with perl-5.16.0 cpanm Note that this installs the I versions of the Perl modules on the new perl, which are not necessarily the I module versions you had installed previously. =head1 COMMAND: CLONE-MODULES Usage: perlbrew clone-modules [options] perlbrew clone-modules [options] Options: --notest Skip all module tests This command re-installs all CPAN modules found from one installation to another. For example, this lists all modules under '5.26.1' and re-installs them under '5.27.7': perlbrew clone-modules 5.26.1 5.27.7 The argument "source" is optional and defaults to the currently activated one. However if none is activated (perlbrew is switched off), it it an error. Note that this does not guarantee that the versions of modules stay the same in the destination. =head1 COMMAND: MAKE-SHIM Usage: perlbrew make-shim perlbrew make-shim -o perlbrew make-shim --output This commands produce an executable file under current directory named C, or C if given after C<--output> (or C<-o> for short). The output is a shell-wrapper, a shim, of the named program inside current perlbrew environment. When the shim is executed, the original C is then executed with all relevant environment variable set to the perlbrew environment it is installed in, regardless which perlbrew environment is currently activated. The shim can also be moved to different directories and, such as the conventional C<~/.local/bin>, so it is always available. For example, you may find C from L a handy tool and decide to install it inside your daily working environment: perlbrew use perl-5.36.1 cpm install -g App::tldr But when you occasionally have to switch to a different environment, C would be tweaked and the command C would went missing, and that is the expected outcome: perlbrew use perl-5.18.4 tldr perl #=> error: command not found It would be nice if C can be made universally available. One way to mitigate such needs is to prepare install the C program outside of C, while still utilize perlbrew environment to run it. For example, prepare a conventional directory C<~/.local/bin> and put that in C, then: perlbrew use perl-5.36.1 cd /tmp perlbrew make-shim tldr mv /tmp/tldr ~/.local/bin/tldr This C<~/.local/bin/tldr> is a shell-wrapper of the actual C program, and it internally activates the perlbrew environment C. Running the tldr shim will then always run the actual C, no matter which perlbrew environment is activated, or even if perlbrew is turned off. The only requirements is that the perlbrew environment C and the installation of C has to remain. =head1 COMMAND: MAKE-PP Usage: perlbrew make-pp perlbrew make-pp -o perlbrew make-pp --output This commands produce an executable file under current directory named C, or C if given after C<--output> (or C<-o> for short). The output is a PAR-packed version of the named program inside current perlbrew environment. This requires the current perlbrew environment to have L and L installed first. Otherwise C bails out. In addition, if current perl is not a perlbrew-managed perl, also bails out. The produced file is a standalone binary executable containing these content: 1. The named program 2. perl runtime 3. all core perl libs of current perl 4. the entire site lib 5. the entire local lib (managed by `perlbrew lib` command), if active. It is expected that the executable can then be running on a different machine of the same OS and arch. Noted that this approach is the maximum overkill for packing one program as it'll be definitely packaing a lot more then the exact list of runtime dependencies of the named program. C is meant for a lazy solution for a non-trivial problem of perfectly determing the runtime dependencies of an arbitarary program. =head1 SEE ALSO L, L, L =cut command-list.t000644001750001750 504014465441602 16513 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; BEGIN { delete $ENV{PERLBREW_HOME}; delete $ENV{PERLBREW_ROOT}; delete $ENV{PERLBREW_LIB}; } use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use File::Spec::Functions qw( catdir ); use Test::Spec; use Test::Output qw( stdout_like ); mock_perlbrew_install("perl-5.12.3"); mock_perlbrew_install("perl-5.12.4"); mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.14.2"); { no warnings 'redefine'; sub App::perlbrew::current_perl { "perl-5.12.3" } } describe "list command," => sub { describe "when there no libs under PERLBREW_HOME,", sub { it "displays a list of perl installation names", sub { my $app = App::perlbrew->new("list"); stdout_like sub { $app->run(); }, qr/^(\s|\*)\sc?perl-?\d\.\d{1,3}[_.]\d{1,2}\s+/, 'Cannot find Perl in output' }; }; describe "when there are lib under PERLBREW_HOME,", sub { before each => sub { unless ( -d catdir($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.12.3@nobita') ) { App::perlbrew->new("lib", "create", "nobita")->run; } unless ( -d catdir($App::perlbrew::PERLBREW_HOME, "libs", 'perl-5.12.3@shizuka') ) { App::perlbrew->new("lib", "create", "shizuka")->run; } }; it "displays lib names" => sub { my $app = App::perlbrew->new("list"); stdout_like sub { $app->run(); }, qr/^(\s|\*)\sc?perl-?\d\.\d{1,3}[_.]\d{1,2}(@\w+)?/, 'Cannot find Perl with libraries in output' }; it "marks currently activated lib", sub { $ENV{PERLBREW_LIB} = "nobita"; my $app = App::perlbrew->new("list"); stdout_like sub { $app->run(); }, qr/^(\s|\*)\sc?perl-?\d\.\d{1,3}[_.]\d{1,2}(\@nobita)?/, 'Cannot find Perl with libraries in output' }; describe "when `--no-decoration` is given", sub { it "does not mark anything", sub { $ENV{PERLBREW_LIB} = "nobita"; my $app = App::perlbrew->new("list", "--no-decoration"); stdout_like sub { $app->run(); }, qr/^perl-?\d\.\d{1,3}[_.]\d{1,2}(@\w+)?/, 'No decoration mark in the output'; }; }; }; describe "when `--no-decoration` is given", sub { my $app = App::perlbrew->new("list", "--no-decoration"); stdout_like sub { $app->run(); }, qr/^perl-?\d\.\d{1,3}[_.]\d{1,2}(@\w+)?/, 'No decoration mark in the output'; }; }; runtests unless caller; command-info.t000644001750001750 1320314465441602 16513 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use Test::Output; use File::Spec; use Config; use App::perlbrew; describe "info command" => sub { it "should display info if under perlbrew perl" => sub { my $app = App::perlbrew->new("info"); my $mock_perl = { mock => 'current_perl' }; my $perl_path = $Config{perlpath}; $app->expects("current_perl")->returns($mock_perl)->at_least_once(); $app->expects("current_env")->returns('perl-5.8.9'); $app->expects("installed_perl_executable")->with($mock_perl)->returns($perl_path)->at_least_once(); $app->expects("configure_args")->with($mock_perl)->returns('config_args_value'); $app->expects("system_perl_shebang")->never; local $ENV{PERLBREW_ROOT} = 'perlbrew_root_value'; local $ENV{PERLBREW_HOME} = 'perlbrew_home_value'; local $ENV{PERLBREW_PATH} = 'perlbrew_path_value'; local $ENV{PERLBREW_MANPATH} = 'perlbrew_manpath_value'; my $expected = <<"OUT"; Current perl: Name: perl-5.8.9 Path: \Q$perl_path\E Config: config_args_value Compiled at: ...\\s+\\d{1,2}\\s+\\d{4}\\s+\\d{1,2}:\\d{2}:\\d{2} perlbrew: version: \Q$App::perlbrew::VERSION\E ENV: PERLBREW_ROOT: perlbrew_root_value PERLBREW_HOME: perlbrew_home_value PERLBREW_PATH: perlbrew_path_value PERLBREW_MANPATH: perlbrew_manpath_value OUT stdout_like sub { $app->run(); }, qr/$expected/; }; it "should display info if under system perl" => sub { my $app = App::perlbrew->new("info"); $app->expects("current_perl")->returns(''); $app->expects("current_env")->never; $app->expects("installed_perl_executable")->never; $app->expects("configure_args")->never; $app->expects("system_perl_shebang")->returns("system_perl_shebang_value")->once; local $ENV{PERLBREW_ROOT} = 'perlbrew_root_value'; local $ENV{PERLBREW_HOME} = 'perlbrew_home_value'; local $ENV{PERLBREW_PATH} = 'perlbrew_path_value'; local $ENV{PERLBREW_MANPATH} = 'perlbrew_manpath_value'; my $expected = <<"OUT"; Current perl: Using system perl. Shebang: system_perl_shebang_value perlbrew: version: \Q$App::perlbrew::VERSION\E ENV: PERLBREW_ROOT: perlbrew_root_value PERLBREW_HOME: perlbrew_home_value PERLBREW_PATH: perlbrew_path_value PERLBREW_MANPATH: perlbrew_manpath_value OUT stdout_like sub { $app->run(); }, qr/$expected/; }; it "should display info for a module if the module is installed" => sub { my $app = App::perlbrew->new; my $mock_perl = { mock => 'current_perl' }; my $perl_path = $Config{perlpath}; my $module_name = "Data::Dumper"; $app->expects("current_perl")->returns($mock_perl)->at_least_once(); $app->expects("current_env")->returns('perl-5.8.9'); $app->expects("installed_perl_executable")->with($mock_perl)->returns($perl_path)->at_least_once(); $app->expects("configure_args")->with($mock_perl)->returns('config_args_value'); $app->expects("system_perl_shebang")->never; local $ENV{PERLBREW_ROOT} = 'perlbrew_root_value'; local $ENV{PERLBREW_HOME} = 'perlbrew_home_value'; local $ENV{PERLBREW_PATH} = 'perlbrew_path_value'; local $ENV{PERLBREW_MANPATH} = 'perlbrew_manpath_value'; my $v = "KNOWN_VALUE"; (my $path_seperator = File::Spec->catdir( ( $v, $v ) ) ) =~ s/$v//g; my $module_location = join $path_seperator, split( /::/, $module_name); my $expected = <<"OUT"; Current perl: Name: perl-5.8.9 Path: \Q$perl_path\E Config: config_args_value Compiled at: ...\\s+\\d{1,2}\\s+\\d{4}\\s+\\d{1,2}:\\d{2}:\\d{2} perlbrew: version: \Q$App::perlbrew::VERSION\E ENV: PERLBREW_ROOT: perlbrew_root_value PERLBREW_HOME: perlbrew_home_value PERLBREW_PATH: perlbrew_path_value PERLBREW_MANPATH: perlbrew_manpath_value Module: \Q$module_name\E Location: .*\Q$module_location\E.pm Version: [\\d\\._]+ OUT stdout_like sub { $app->{args} = [ "info", $module_name]; $app->run(); }, qr/$expected/; }; it "should display a message that the module can't be found if the module isn't installed" => sub { my $app = App::perlbrew->new; my $mock_perl = { mock => 'current_perl' }; my $perl_path = $Config{perlpath}; my $module_name = "SOME_FAKE_MODULE"; $app->expects("current_perl")->returns($mock_perl)->at_least_once(); $app->expects("current_env")->returns('perl-5.8.9'); $app->expects("installed_perl_executable")->with($mock_perl)->returns($perl_path)->at_least_once(); $app->expects("configure_args")->with($mock_perl)->returns('config_args_value'); $app->expects("system_perl_shebang")->never; local $ENV{PERLBREW_ROOT} = 'perlbrew_root_value'; local $ENV{PERLBREW_HOME} = 'perlbrew_home_value'; local $ENV{PERLBREW_PATH} = 'perlbrew_path_value'; local $ENV{PERLBREW_MANPATH} = 'perlbrew_manpath_value'; my $expected = <<"OUT"; Current perl: Name: perl-5.8.9 Path: \Q$perl_path\E Config: config_args_value Compiled at: ...\\s+\\d{1,2}\\s+\\d{4}\\s+\\d{1,2}:\\d{2}:\\d{2} perlbrew: version: \Q$App::perlbrew::VERSION\E ENV: PERLBREW_ROOT: perlbrew_root_value PERLBREW_HOME: perlbrew_home_value PERLBREW_PATH: perlbrew_path_value PERLBREW_MANPATH: perlbrew_manpath_value Module: $module_name could not be found, is it installed?.* OUT stdout_like sub { $app->{args} = [ "info", $module_name]; $app->run(); }, qr/$expected/; }; }; runtests unless caller; list_modules.t000644001750001750 224214465441602 16630 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; mock_perlbrew_install("perl-5.14.1"); describe "list_modules method," => sub { before each => sub { delete $ENV{PERL_MB_OPT}; delete $ENV{PERL_MM_OPT}; delete $ENV{PERL_LOCAL_LIB_ROOT}; delete $ENV{PERLBREW_LIB}; delete $ENV{PERL5LIB}; }; describe "when run successfully", sub { before each => sub { no warnings; sub App::perlbrew::run_command_exec { my ($self, @args) = @_; if (grep { $_ eq '-MExtUtils::Installed' } @args) { print "Foo\n"; } else { die "Unexpected `exec`"; } return $self; } }; it "should return an arryref of module names ", sub { my $app = App::perlbrew->new(); $app->current_perl("perl-5.14.1"); my $modules = $app->list_modules(); is 0+@$modules, 1; is $modules->[0], "Foo"; }; }; }; runtests unless caller; perlbrew.pm000644001750001750 30742014465441602 17211 0ustar00gugodgugod000000000000App-perlbrew-0.98/lib/Apppackage App::perlbrew; use strict; use warnings; use 5.008; our $VERSION = "0.98"; use Config qw( %Config ); BEGIN { # Special treat for Cwd to prevent it to be loaded from somewhere binary-incompatible with system perl. my @oldinc = @INC; @INC = ( $Config{sitelibexp} . "/" . $Config{archname}, $Config{sitelibexp}, @Config{qw}, ); require Cwd; @INC = @oldinc; } use Getopt::Long (); use CPAN::Perl::Releases (); use JSON::PP qw( decode_json ); use File::Copy qw( copy ); use Capture::Tiny (); use App::Perlbrew::Util qw( files_are_the_same uniq find_similar_tokens ); use App::Perlbrew::Path (); use App::Perlbrew::Path::Root (); use App::Perlbrew::HTTP qw( http_download http_get ); ### global variables # set $ENV{SHELL} to executable path of parent process (= shell) if it's missing # (e.g. if this script was executed by a daemon started with "service xxx start") # ref: https://github.com/gugod/App-perlbrew/pull/404 $ENV{SHELL} ||= App::Perlbrew::Path->new( "/proc", getppid, "exe" )->readlink if -d "/proc"; local $SIG{__DIE__} = sub { my $message = shift; warn $message; exit(1); }; our $CONFIG; our $PERLBREW_ROOT; our $PERLBREW_HOME; my @flavors = ( { d_option => 'usethreads', implies => 'multi', common => 1, opt => 'thread|threads' }, # threads is for backward compatibility { d_option => 'usemultiplicity', opt => 'multi' }, { d_option => 'uselongdouble', common => 1, opt => 'ld' }, { d_option => 'use64bitint', common => 1, opt => '64int' }, { d_option => 'use64bitall', implies => '64int', opt => '64all' }, { d_option => 'DEBUGGING', opt => 'debug' }, { d_option => 'cc=clang', opt => 'clang' }, ); my %flavor; my $flavor_ix = 0; for (@flavors) { my ($name) = $_->{opt} =~ /([^|]+)/; $_->{name} = $name; $_->{ix} = ++$flavor_ix; $flavor{$name} = $_; } for (@flavors) { if ( my $implies = $_->{implies} ) { $flavor{$implies}{implied_by} = $_->{name}; } } ### methods sub new { my ( $class, @argv ) = @_; my %opt = ( original_argv => \@argv, args => [], yes => 0, force => 0, quiet => 0, D => [], U => [], A => [], sitecustomize => '', destdir => '', noman => '', variation => '', both => [], append => '', reverse => 0, verbose => 0, ); $opt{$_} = '' for keys %flavor; if (@argv) { # build a local @ARGV to allow us to use an older # Getopt::Long API in case we are building on an older system local (@ARGV) = @argv; Getopt::Long::Configure( 'pass_through', 'no_ignore_case', 'bundling', 'permute', # default behaviour except 'exec' ); $class->parse_cmdline( \%opt ); $opt{args} = \@ARGV; # fix up the effect of 'bundling' foreach my $flags ( @opt{qw(D U A)} ) { foreach my $value ( @{$flags} ) { $value =~ s/^=//; } } } my $self = bless \%opt, $class; # Treat --root option same way as env variable PERLBREW_ROOT (with higher priority) if ( $opt{root} ) { $ENV{PERLBREW_ROOT} = $self->root( $opt{root} ); } if ( $opt{builddir} ) { $self->{builddir} = App::Perlbrew::Path->new( $opt{builddir} ); } # Ensure propagation of $PERLBREW_HOME and $PERLBREW_ROOT $self->root; $self->home; if ( $self->{verbose} ) { $App::Perlbrew::HTTP::HTTP_VERBOSE = 1; } return $self; } sub parse_cmdline { my ( $self, $params, @ext ) = @_; my @f = map { $flavor{$_}{opt} || $_ } keys %flavor; return Getopt::Long::GetOptions( $params, 'yes', 'force|f', 'reverse', 'notest|n', 'quiet|q', 'verbose|v', 'output|o=s', 'as=s', 'append=s', 'help|h', 'version', 'root=s', 'switch', 'all', 'shell=s', 'no-patchperl', 'no-decoration', "builddir=s", # options passed directly to Configure 'D=s@', 'U=s@', 'A=s@', 'j=i', # options that affect Configure and customize post-build 'sitecustomize=s', 'destdir=s', 'noman', # flavors support 'both|b=s@', 'all-variations', 'common-variations', @f, @ext ); } sub root { my ( $self, $new_root ) = @_; $new_root ||= $PERLBREW_ROOT || $ENV{PERLBREW_ROOT} || App::Perlbrew::Path->new( $ENV{HOME}, "perl5", "perlbrew" )->stringify unless $self->{root}; $self->{root} = $PERLBREW_ROOT = $new_root if defined $new_root; $self->{root} = App::Perlbrew::Path::Root->new( $self->{root} ) unless ref $self->{root}; $self->{root} = App::Perlbrew::Path::Root->new( $self->{root}->stringify ) unless $self->{root}->isa('App::Perlbrew::Path::Root'); return $self->{root}; } sub home { my ( $self, $new_home ) = @_; $new_home ||= $PERLBREW_HOME || $ENV{PERLBREW_HOME} || App::Perlbrew::Path->new( $ENV{HOME}, ".perlbrew" )->stringify unless $self->{home}; $self->{home} = $PERLBREW_HOME = $new_home if defined $new_home; $self->{home} = App::Perlbrew::Path->new( $self->{home} ) unless ref $self->{home}; return $self->{home}; } sub builddir { my ($self) = @_; return $self->{builddir} || $self->root->build; } sub current_perl { my ( $self, $v ) = @_; $self->{current_perl} = $v if $v; return $self->{current_perl} || $self->env('PERLBREW_PERL') || ''; } sub current_lib { my ( $self, $v ) = @_; $self->{current_lib} = $v if $v; return $self->{current_lib} || $self->env('PERLBREW_LIB') || ''; } sub current_shell_is_bashish { my ($self) = @_; return ( $self->current_shell eq 'bash' ) || ( $self->current_shell eq 'zsh' ); } sub current_shell { my ( $self, $x ) = @_; $self->{current_shell} = $x if $x; return $self->{current_shell} ||= do { my $shell_name = App::Perlbrew::Path->new( $self->{shell} || $self->env('SHELL') )->basename; $shell_name =~ s/\d+$//; $shell_name; }; } sub current_env { my ($self) = @_; my $l = $self->current_lib; $l = "@" . $l if $l; return $self->current_perl . $l; } sub installed_perl_executable { my ( $self, $name ) = @_; die unless $name; my $executable = $self->root->perls($name)->perl; return $executable if -e $executable; return ""; } sub configure_args { my ( $self, $name ) = @_; my $perl_cmd = $self->installed_perl_executable($name); my $code = 'while(($_,$v)=each(%Config)){print"$_ $v" if /config_arg/}'; my @output = split "\n" => $self->do_capture( $perl_cmd, '-MConfig', '-wle', $code ); my %arg; for (@output) { my ( $k, $v ) = split " ", $_, 2; $arg{$k} = $v; } if (wantarray) { return map { $arg{"config_arg$_"} } ( 1 .. $arg{config_argc} ); } return $arg{config_args}; } sub cpan_mirror { my ( $self, $v ) = @_; $self->{cpan_mirror} = $v if $v; unless ( $self->{cpan_mirror} ) { $self->{cpan_mirror} = $self->env("PERLBREW_CPAN_MIRROR") || "https://cpan.metacpan.org"; $self->{cpan_mirror} =~ s{/+$}{}; } return $self->{cpan_mirror}; } sub env { my ( $self, $name ) = @_; return $ENV{$name} if $name; return \%ENV; } sub is_shell_csh { my ($self) = @_; return 1 if $self->env('SHELL') =~ /(t?csh)/; return 0; } # Entry point method: handles all the arguments # and dispatches to an appropriate internal # method to execute the corresponding command. sub run { my ($self) = @_; $self->run_command( $self->args ); } sub args { my ($self) = @_; # keep 'force' and 'yes' coherent across commands $self->{force} = $self->{yes} = 1 if ( $self->{force} || $self->{yes} ); return @{ $self->{args} }; } sub commands { my ($self) = @_; my $package = ref $self ? ref $self : $self; my @commands; my $symtable = do { no strict 'refs'; \%{ $package . '::' }; }; foreach my $sym ( keys %$symtable ) { if ( $sym =~ /^run_command_/ ) { my $glob = $symtable->{$sym}; if ( ref($glob) eq 'CODE' || defined *$glob{CODE} ) { # with perl >= 5.27 stash entry can points to a CV directly $sym =~ s/^run_command_//; $sym =~ s/_/-/g; push @commands, $sym; } } } return @commands; } sub find_similar_commands { my ( $self, $command ) = @_; $command =~ s/_/-/g; return @{ find_similar_tokens($command, [ sort $self->commands ]) }; } # This method is called in the 'run' loop # and executes every specific action depending # on the type of command. # # The first argument to this method is a self reference, # while the first "real" argument is the command to execute. # Other parameters after the command to execute are # considered as arguments for the command itself. # # In general the command is executed via a method named after the # command itself and with the 'run_command' prefix. For instance # the command 'exec' is handled by a method # `run_command_exec` # # If no candidates can be found, an execption is thrown # and a similar command is shown to the user. sub run_command { my ( $self, $x, @args ) = @_; my $command = $x; if ( $self->{version} ) { $x = 'version'; } elsif ( !$x ) { $x = 'help'; @args = ( 0, 0 ); } elsif ( $x eq 'help' ) { @args = ( 0, 2 ) unless @args; } my $s = $self->can("run_command_$x"); unless ($s) { $x =~ y/-/_/; $s = $self->can("run_command_$x"); } unless ($s) { my @commands = $self->find_similar_commands($x); if ( @commands > 1 ) { @commands = map { ' ' . $_ } @commands; die "Unknown command: `$command`. Did you mean one of the following?\n" . join( "\n", @commands ) . "\n"; } elsif ( @commands == 1 ) { die "Unknown command: `$command`. Did you mean `$commands[0]`?\n"; } else { die "Unknown command: `$command`. Typo?\n"; } } $self->$s(@args); } sub run_command_version { my ($self) = @_; my $package = ref $self; my $version = $self->VERSION; print "$0 - $package/$version\n"; } # Provides help information about a command. # The idea is similar to the 'run_command' and 'run_command_$x' chain: # this method dispatches to a 'run_command_help_$x' method # if found in the class, otherwise it tries to extract the help # documentation via the POD of the class itself using the # section 'COMMAND: $x' with uppercase $x. sub run_command_help { my ( $self, $status, $verbose, $return_text ) = @_; require Pod::Usage; if ( $status && !defined($verbose) ) { if ( $self->can("run_command_help_${status}") ) { $self->can("run_command_help_${status}")->($self); } else { my $out = ""; open my $fh, ">", \$out; Pod::Usage::pod2usage( -exitval => "NOEXIT", -verbose => 99, -sections => "COMMAND: " . uc($status), -output => $fh, -noperldoc => 1 ); $out =~ s/\A[^\n]+\n//s; $out =~ s/^ //gm; if ( $out =~ /\A\s*\Z/ ) { $out = "Cannot find documentation for '$status'\n\n"; } return "\n$out" if ($return_text); print "\n$out"; close $fh; } } else { Pod::Usage::pod2usage( -noperldoc => 1, -verbose => $verbose || 0, -exitval => ( defined $status ? $status : 1 ) ); } } # introspection for compgen my %comp_installed = ( use => 1, switch => 1, ); sub run_command_compgen { my ( $self, $cur, @args ) = @_; $cur = 0 unless defined($cur); # do `tail -f bashcomp.log` for debugging if ( $self->env('PERLBREW_DEBUG_COMPLETION') ) { open my $log, '>>', 'bashcomp.log'; print $log "[$$] $cur of [@args]\n"; } my $subcommand = $args[1]; my $subcommand_completed = ( $cur >= 2 ); if ( !$subcommand_completed ) { $self->_compgen( $subcommand, $self->commands ); } else { # complete args of a subcommand if ( $comp_installed{$subcommand} ) { if ( $cur <= 2 ) { my $part; if ( defined( $part = $args[2] ) ) { $part = qr/ \Q$part\E /xms; } $self->_compgen( $part, map { $_->{name} } $self->installed_perls() ); } } elsif ( $subcommand eq 'help' ) { if ( $cur <= 2 ) { $self->_compgen( $args[2], $self->commands() ); } } else { # TODO } } } sub _firstrcfile { my ( $self, @files ) = @_; foreach my $path (@files) { return $path if -f App::Perlbrew::Path->new( $self->env('HOME'), $path ); } return; } sub _compgen { my ( $self, $part, @reply ) = @_; if ( defined $part ) { $part = qr/\A \Q$part\E /xms if ref($part) ne ref(qr//); @reply = grep { /$part/ } @reply; } foreach my $word (@reply) { print $word, "\n"; } } # Internal utility function. # Given a specific perl version, e.g., perl-5.27.4 # returns a string with a formatted version number such # as 05027004. Such string can be used as a number # in order to make either a string comparison # or a numeric comparison. # # In the case of cperl the major number is added by 6 # so that it would match the project claim of being # Perl 5+6 = 11. The final result is then # multiplied by a negative factor (-1) in order # to make cperl being "less" in the ordered list # than a normal Perl installation. # # The returned string is made by four pieces of two digits each: # MMmmppbb # where: # MM is the major Perl version (e.g., 5 -> 05) # mm is the minor Perl version (e.g. 27 -> 27) # pp is the patch level (e.g., 4 -> 04) # bb is the blead flag: it is 00 for a "normal" release, or 01 for a blead one sub comparable_perl_version { my ( $self, $perl_version ) = @_; my ( $is_cperl, $is_blead ) = ( 0, 0 ); my ( $major, $minor, $patch ) = ( 0, 0, 0 ); if ( $perl_version =~ /^(?:(c?perl)-?)?(\d)\.(\d+).(\d+).*/ ) { $is_cperl = $1 && ( $1 eq 'cperl' ); $major = $2 + ( $is_cperl ? 6 : 0 ); # major version $minor = $3; # minor version $patch = $4; # patch level } elsif ( $perl_version =~ /^(?:(c?perl)-?)?-?(blead)$/ ) { # in the case of a blead release use a fake high number # to assume it is the "latest" release number available $is_cperl = $1 && ( $1 eq 'cperl' ); $is_blead = $2 && ( $2 eq 'blead' ); ( $major, $minor, $patch ) = ( 5, 99, 99 ); } return ( $is_cperl ? -1 : 1 ) * sprintf( '%02d%02d%02d%02d', $major + ( $is_cperl ? 6 : 0 ), # major version $minor, # minor version $patch, # patch level $is_blead ); # blead } # Internal method. # Performs a comparable sort of the perl versions specified as # list. sub sort_perl_versions { my ( $self, @perls ) = @_; return map { $_->[0] } sort { ( $self->{reverse} ? $a->[1] <=> $b->[1] : $b->[1] <=> $a->[1] ) } map { [$_, $self->comparable_perl_version($_)] } @perls; } sub run_command_available { my ($self) = @_; my @installed = $self->installed_perls(@_); my $is_verbose = $self->{verbose}; my @sections = ( ['perl', 'available_perl_distributions'] ); for (@sections) { my ( $header, $method ) = @$_; print "# $header\n"; my $perls = $self->$method; # sort the keys of Perl installation (Randal to the rescue!) my @sorted_perls = $self->sort_perl_versions( keys %$perls ); for my $available (@sorted_perls) { my $url = $perls->{$available}; my $ctime; for my $installed (@installed) { my $name = $installed->{name}; my $cur = $installed->{is_current}; if ( $available eq $installed->{name} ) { $ctime = $installed->{ctime}; last; } } printf "%1s %12s %s %s\n", $ctime ? 'i' : '', $available, ( $is_verbose ? $ctime ? "INSTALLED on $ctime via" : 'available from ' : '' ), ( $is_verbose ? "<$url>" : '' ); } print "\n\n"; } return; } sub available_perls { my ($self) = @_; my %dists = ( %{ $self->available_perl_distributions } ); return $self->sort_perl_versions( keys %dists ); } # -> Map[ NameVersion => URL ] sub available_perl_distributions { my ($self) = @_; my $perls = {}; my @perllist; # we got impatient waiting for cpan.org to get updated to show 5.28... # So, we also fetch from metacpan for anything that looks perlish, # and we do our own processing to filter out the development # releases and minor versions when needed (using # filter_perl_available) my $json = http_get('https://fastapi.metacpan.org/v1/release/versions/perl') or die "\nERROR: Unable to retrieve list of perls from Metacpan.\n\n"; my $decoded = decode_json($json); for my $release ( @{ $decoded->{releases} } ) { push @perllist, [$release->{name}, $release->{download_url}]; } foreach my $perl ( $self->filter_perl_available( \@perllist ) ) { $perls->{ $perl->[0] } = $perl->[1]; } return $perls; } # $perllist is an arrayref of arrayrefs. The inner arrayrefs are of the # format: [ , ] # perl_name = something like perl-5.28.0 # perl_url = URL the Perl is available from. # # If $self->{all} is true, this just returns a list of the contents of # the list referenced by $perllist # # Otherwise, this looks for even middle numbers in the version and no # suffix (like -RC1) following the URL, and returns the list of # arrayrefs that so match # # If any "newest" Perl has a sub filter_perl_available { my ( $self, $perllist ) = @_; if ( $self->{all} ) { return @$perllist; } my %max_release; foreach my $perl (@$perllist) { my $ver = $perl->[0]; if ( $ver !~ m/^perl-5\.[0-9]*[02468]\.[0-9]+$/ ) { next; } # most likely TRIAL or RC, or a DEV release my ( $release_line, $minor ) = $ver =~ m/^perl-5\.([0-9]+)\.([0-9]+)/; if ( exists $max_release{$release_line} ) { if ( $max_release{$release_line}->[0] > $minor ) { next; } # We have a newer release } $max_release{$release_line} = [$minor, $perl]; } return map { $_->[1] } values %max_release; } sub perl_release { my ( $self, $version ) = @_; my $mirror = $self->cpan_mirror(); # try CPAN::Perl::Releases my $tarballs = CPAN::Perl::Releases::perl_tarballs($version); my $x = ( values %$tarballs )[0]; if ($x) { my $dist_tarball = ( split( "/", $x ) )[-1]; my $dist_tarball_url = "$mirror/authors/id/$x"; return ( $dist_tarball, $dist_tarball_url ); } # try src/5.0 symlinks, either perl-5.X or perl5.X; favor .tar.bz2 over .tar.gz my $index = http_get("https://cpan.metacpan.org/src/5.0/"); if ($index) { for my $prefix ( "perl-", "perl" ) { for my $suffix ( ".tar.bz2", ".tar.gz" ) { my $dist_tarball = "$prefix$version$suffix"; my $dist_tarball_url = "$mirror/src/5.0/$dist_tarball"; return ( $dist_tarball, $dist_tarball_url ) if ( $index =~ /href\s*=\s*"\Q$dist_tarball\E"/ms ); } } } my $json = http_get("https://fastapi.metacpan.org/v1/release/_search?size=1&q=name:perl-${version}"); my $result; unless ( $json and $result = decode_json($json)->{hits}{hits}[0] ) { die "ERROR: Failed to locate perl-${version} tarball."; } my ( $dist_path, $dist_tarball ) = $result->{_source}{download_url} =~ m[(/authors/id/.+/(perl-${version}.tar.(gz|bz2|xz)))$]; die "ERROR: Cannot find the tarball for perl-$version\n" if !$dist_path and !$dist_tarball; my $dist_tarball_url = "https://cpan.metacpan.org${dist_path}"; return ( $dist_tarball, $dist_tarball_url ); } sub release_detail_perl_local { my ( $self, $dist, $rd ) = @_; $rd ||= {}; my $error = 1; my $mirror = $self->cpan_mirror(); my $tarballs = CPAN::Perl::Releases::perl_tarballs( $rd->{version} ); if ( keys %$tarballs ) { for ( "tar.bz2", "tar.gz" ) { if ( my $x = $tarballs->{$_} ) { $rd->{tarball_name} = ( split( "/", $x ) )[-1]; $rd->{tarball_url} = "$mirror/authors/id/$x"; $error = 0; last; } } } return ( $error, $rd ); } sub release_detail_perl_remote { my ( $self, $dist, $rd ) = @_; $rd ||= {}; my $error = 1; my $mirror = $self->cpan_mirror(); my $version = $rd->{version}; # try src/5.0 symlinks, either perl-5.X or perl5.X; favor .tar.bz2 over .tar.gz my $index = http_get("https://cpan.metacpan.org/src/5.0/"); if ($index) { for my $prefix ( "perl-", "perl" ) { for my $suffix ( ".tar.bz2", ".tar.gz" ) { my $dist_tarball = "$prefix$version$suffix"; my $dist_tarball_url = "$mirror/src/5.0/$dist_tarball"; if ( $index =~ /href\s*=\s*"\Q$dist_tarball\E"/ms ) { $rd->{tarball_url} = $dist_tarball_url; $rd->{tarball_name} = $dist_tarball; $error = 0; return ( $error, $rd ); } } } } my $json = http_get("https://fastapi.metacpan.org/v1/release/_search?size=1&q=name:perl-${version}"); my $result; unless ( $json and $result = decode_json($json)->{hits}{hits}[0] ) { die "ERROR: Failed to locate perl-${version} tarball."; } my ( $dist_path, $dist_tarball ) = $result->{_source}{download_url} =~ m[(/authors/id/.+/(perl-${version}.tar.(gz|bz2|xz)))$]; die "ERROR: Cannot find the tarball for perl-$version\n" if !$dist_path and !$dist_tarball; my $dist_tarball_url = "https://cpan.metacpan.org${dist_path}"; $rd->{tarball_name} = $dist_tarball; $rd->{tarball_url} = $dist_tarball_url; $error = 0; return ( $error, $rd ); } sub release_detail { my ( $self, $dist ) = @_; my ( $dist_type, $dist_version ); ( $dist_type, $dist_version ) = $dist =~ /^ (?: (perl) -? )? ( [\d._]+ (?:-RC\d+)? |git|stable|blead)$/x; $dist_type = "perl" if $dist_version && !$dist_type; my $rd = { type => $dist_type, version => $dist_version, tarball_url => undef, tarball_name => undef, }; # dynamic methods: release_detail_perl_local, release_detail_perl_remote my $m_local = "release_detail_${dist_type}_local"; my $m_remote = "release_detail_${dist_type}_remote"; unless ($self->can($m_local) && $self->can($m_remote)) { die "ERROR: Unknown dist type: $dist_type\n"; } my ($error) = $self->$m_local( $dist, $rd ); ($error) = $self->$m_remote( $dist, $rd ) if $error; if ($error) { die "ERROR: Fail to get the tarball URL for dist: $dist\n"; } return $rd; } sub run_command_init { my $self = shift; my @args = @_; if ( @args && $args[0] eq '-' ) { if ( $self->current_shell_is_bashish ) { $self->run_command_init_in_bash; } exit 0; } $_->mkpath for ( grep { !-d $_ } map { $self->root->$_ } qw(perls dists build etc bin) ); my ( $f, $fh ) = @_; my $etc_dir = $self->root->etc; for ( ["bashrc", "BASHRC_CONTENT"], ["cshrc", "CSHRC_CONTENT"], ["csh_reinit", "CSH_REINIT_CONTENT"], ["csh_wrapper", "CSH_WRAPPER_CONTENT"], ["csh_set_path", "CSH_SET_PATH_CONTENT"], ["perlbrew-completion.bash", "BASH_COMPLETION_CONTENT"], ["perlbrew.fish", "PERLBREW_FISH_CONTENT"], ) { my ( $file_name, $method ) = @$_; my $path = $etc_dir->child($file_name); if ( !-f $path ) { open( $fh, ">", $path ) or die "Fail to create $path. Please check the permission of $etc_dir and try `perlbrew init` again."; print $fh $self->$method; close $fh; } else { if ( -w $path && open( $fh, ">", $path ) ) { print $fh $self->$method; close $fh; } else { print "NOTICE: $path already exists and not updated.\n" unless $self->{quiet}; } } } my $root_dir = $self->root->stringify_with_tilde; # Skip this if we are running in a shell that already 'source's perlbrew. # This is true during a self-install/self-init. # Ref. https://github.com/gugod/App-perlbrew/issues/525 if ( $ENV{PERLBREW_SHELLRC_VERSION} ) { print("\nperlbrew root ($root_dir) is initialized.\n"); } else { my $shell = $self->current_shell; my ( $code, $yourshrc ); if ( $shell =~ m/(t?csh)/ ) { $code = "source $root_dir/etc/cshrc"; $yourshrc = $1 . "rc"; } elsif ( $shell =~ m/zsh\d?$/ ) { $code = "source $root_dir/etc/bashrc"; $yourshrc = $self->_firstrcfile( qw( .zshenv .bash_profile .bash_login .profile ) ) || ".zshenv"; } elsif ( $shell =~ m/fish/ ) { $code = ". $root_dir/etc/perlbrew.fish"; $yourshrc = '.config/fish/config.fish'; } else { $code = "source $root_dir/etc/bashrc"; $yourshrc = $self->_firstrcfile( qw( .bash_profile .bash_login .profile ) ) || ".bash_profile"; } if ( $self->home ne App::Perlbrew::Path->new( $self->env('HOME'), ".perlbrew" ) ) { my $pb_home_dir = $self->home->stringify_with_tilde; if ( $shell =~ m/fish/ ) { $code = "set -x PERLBREW_HOME $pb_home_dir\n $code"; } else { $code = "export PERLBREW_HOME=$pb_home_dir\n $code"; } } print <root->bin("perlbrew"); if ( files_are_the_same( $executable, $target ) ) { print "You are already running the installed perlbrew:\n\n $executable\n"; exit; } $self->root->bin->mkpath; open my $fh, "<", $executable; my $head; read( $fh, $head, 3, 0 ); if ( $head eq "#!/" ) { seek( $fh, 0, 0 ); my @lines = <$fh>; close $fh; $lines[0] = $self->system_perl_shebang . "\n"; open $fh, ">", $target; print $fh $_ for @lines; close $fh; } else { close($fh); copy( $executable, $target ); } chmod( 0755, $target ); my $path = $target->stringify_with_tilde; print "perlbrew is installed: $path\n" unless $self->{quiet}; $self->run_command_init(); return; } sub do_install_git { my ( $self, $dist ) = @_; my $dist_name; my $dist_git_describe; my $dist_version; opendir my $cwd_orig, "."; chdir $dist; if ( `git describe` =~ /v((5\.\d+\.\d+(?:-RC\d)?)(-\d+-\w+)?)$/ ) { $dist_name = 'perl'; $dist_git_describe = "v$1"; $dist_version = $2; } chdir $cwd_orig; require File::Spec; my $dist_extracted_dir = File::Spec->rel2abs($dist); $self->do_install_this( App::Perlbrew::Path->new($dist_extracted_dir), $dist_version, "$dist_name-$dist_version" ); return; } sub do_install_url { my ( $self, $dist ) = @_; my $dist_name = 'perl'; # need the period to account for the file extension my ($dist_version) = $dist =~ m/-([\d.]+(?:-RC\d+)?|git)\./; my ($dist_tarball) = $dist =~ m{/([^/]*)$}; if ( !$dist_version && $dist =~ /blead\.tar.gz$/ ) { $dist_version = "blead"; } my $dist_tarball_path = $self->root->dists($dist_tarball); my $dist_tarball_url = $dist; $dist = "$dist_name-$dist_version"; # we install it as this name later if ( $dist_tarball_url =~ m/^file/ ) { print "Installing $dist from local archive $dist_tarball_url\n"; $dist_tarball_url =~ s/^file:\/+/\//; $dist_tarball_path = $dist_tarball_url; } else { print "Fetching $dist as $dist_tarball_path\n"; my $error = http_download( $dist_tarball_url, $dist_tarball_path ); die "ERROR: Failed to download $dist_tarball_url\n$error\n" if $error; } my $dist_extracted_path = $self->do_extract_tarball($dist_tarball_path); $self->do_install_this( $dist_extracted_path, $dist_version, $dist ); return; } sub do_extract_tarball { my ( $self, $dist_tarball ) = @_; # Assuming the dir extracted from the tarball is named after the tarball. my $dist_tarball_basename = $dist_tarball->basename(qr/\.tar\.(?:gz|bz2|xz)$/); my $workdir; if ( $self->{as} ) { # TODO: Should we instead use the installation_name (see run_command_install()): # $destdir = $self->{as} . $self->{variation} . $self->{append}; $workdir = $self->builddir->child( $self->{as} ); } else { # Note that this is incorrect for blead. $workdir = $self->builddir->child($dist_tarball_basename); } $workdir->rmpath; $workdir->mkpath; my $extracted_dir; # Was broken on Solaris, where GNU tar is probably # installed as 'gtar' - RT #61042 my $tarx = ( $^O =~ /solaris|aix/ ? 'gtar ' : 'tar ' ) . ( $dist_tarball =~ m/xz$/ ? 'xJf' : $dist_tarball =~ m/bz2$/ ? 'xjf' : 'xzf' ); my $extract_command = "cd $workdir; $tarx $dist_tarball"; die "Failed to extract $dist_tarball" if system($extract_command); my @things = $workdir->children; if ( @things == 1 ) { $extracted_dir = App::Perlbrew::Path->new( $things[0] ); } unless ( defined($extracted_dir) && -d $extracted_dir ) { die "Failed to find the extracted directory under $workdir"; } return $extracted_dir; } sub do_install_blead { my ($self) = @_; # We always blindly overwrite anything that's already there, # because blead is a moving target. my $dist_tarball_path = $self->root->dists("blead.tar.gz"); unlink($dist_tarball_path) if -f $dist_tarball_path; $self->do_install_url("https://github.com/Perl/perl5/archive/blead.tar.gz"); } sub resolve_stable_version { my ($self) = @_; my ( $latest_ver, $latest_minor ); for my $cand ( $self->available_perls ) { my ( $ver, $minor ) = $cand =~ m/^perl-(5\.(6|8|[0-9]+[02468])\.[0-9]+)$/ or next; ( $latest_ver, $latest_minor ) = ( $ver, $minor ) if !defined $latest_minor || $latest_minor < $minor; } die "Can't determine latest stable Perl release\n" if !defined $latest_ver; return $latest_ver; } sub do_install_release { my ( $self, $dist, $dist_version ) = @_; my $rd = $self->release_detail($dist); my $dist_type = $rd->{type}; die "\"$dist\" does not look like a perl distribution name. " unless $dist_type && $dist_version =~ /^\d\./; my $dist_tarball = $rd->{tarball_name}; my $dist_tarball_url = $rd->{tarball_url}; my $dist_tarball_path = $self->root->dists($dist_tarball); if ( -f $dist_tarball_path ) { print "Using the previously fetched ${dist_tarball}\n" if $self->{verbose}; } else { print "Fetching perl $dist_version as $dist_tarball_path\n" unless $self->{quiet}; $self->run_command_download($dist); } my $dist_extracted_path = $self->do_extract_tarball($dist_tarball_path); $self->do_install_this( $dist_extracted_path, $dist_version, $dist ); return; } sub run_command_install { my ( $self, $dist, $opts ) = @_; unless ( $self->root->exists ) { die( "ERROR: perlbrew root " . $self->root . " does not exist. Run `perlbrew init` to prepare it first.\n" ); } unless ($dist) { $self->run_command_help("install"); exit(-1); } $self->{dist_name} = $dist; # for help msg generation, set to non # normalized name my ( $dist_type, $dist_version ); if ( ( $dist_type, $dist_version ) = $dist =~ /^(?:(c?perl)-?)?([\d._]+(?:-RC\d+)?|git|stable|blead)$/ ) { $dist_version = $self->resolve_stable_version if $dist_version eq 'stable'; $dist_type ||= "perl"; $dist = "${dist_type}-${dist_version}"; # normalize dist name my $installation_name = ( $self->{as} || $dist ) . $self->{variation} . $self->{append}; if ( not $self->{force} and $self->is_installed($installation_name) ) { die "\nABORT: $installation_name is already installed.\n\n"; } if ( $dist_type eq 'perl' && $dist_version eq 'blead' ) { $self->do_install_blead(); } else { $self->do_install_release( $dist, $dist_version ); } } # else it is some kind of special install: elsif ( -d "$dist/.git" ) { $self->do_install_git($dist); } elsif ( -f $dist ) { $self->do_install_archive( App::Perlbrew::Path->new($dist) ); } elsif ( $dist =~ m/^(?:https?|ftp|file)/ ) { # more protocols needed? $self->do_install_url($dist); } else { die "Unknown installation target \"$dist\", abort.\nPlease see `perlbrew help` " . "for the instruction on using the install command.\n\n"; } if ( $self->{switch} ) { if ( defined( my $installation_name = $self->{installation_name} ) ) { $self->switch_to($installation_name); } else { warn "can't switch, unable to infer final destination name.\n\n"; } } return; } sub check_and_calculate_variations { my $self = shift; my @both = @{ $self->{both} }; if ( $self->{'all-variations'} ) { @both = keys %flavor; } elsif ( $self->{'common-variations'} ) { push @both, grep $flavor{$_}{common}, keys %flavor; } # check the validity of the varitions given via 'both' for my $both (@both) { $flavor{$both} or die "$both is not a supported flavor.\n\n"; $self->{$both} and die "options --both $both and --$both can not be used together"; if ( my $implied_by = $flavor{$both}{implied_by} ) { $self->{$implied_by} and die "options --both $both and --$implied_by can not be used together"; } } # flavors selected always my $start = ''; $start .= "-$_" for grep $self->{$_}, keys %flavor; # make variations my @var = $start; for my $both (@both) { my $append = join( '-', $both, grep defined, $flavor{$both}{implies} ); push @var, map "$_-$append", @var; } # normalize the variation names @var = map { join '-', '', sort { $flavor{$a}{ix} <=> $flavor{$b}{ix} } grep length, split /-+/, $_ } @var; s/(\b\w+\b)(?:-\1)+/$1/g for @var; # remove duplicate flavors # After inspecting perl Configure script this seems to be the most # reliable heuristic to determine if perl would have 64bit IVs by # default or not: if ( $Config::Config{longsize} >= 8 ) { # We are in a 64bit platform. 64int and 64all are always set but # we don't want them to appear on the final perl name s/-64\w+//g for @var; } # remove duplicated variations my %var = map { $_ => 1 } @var; sort keys %var; } sub run_command_install_multiple { my ( $self, @dists ) = @_; unless (@dists) { $self->run_command_help("install-multiple"); exit(-1); } die "--switch can not be used with command install-multiple.\n\n" if $self->{switch}; die "--as can not be used when more than one distribution is given.\n\n" if $self->{as} and @dists > 1; my @variations = $self->check_and_calculate_variations; print join( "\n", "Compiling the following distributions:", map( " $_$self->{append}", @dists ), " with the following variations:", map( ( /-(.*)/ ? " $1" : " default" ), @variations ), "", "" ); my @ok; for my $dist (@dists) { for my $variation (@variations) { local $@; eval { $self->{$_} = '' for keys %flavor; $self->{$_} = 1 for split /-/, $variation; $self->{variation} = $variation; $self->{installation_name} = undef; $self->run_command_install($dist); push @ok, $self->{installation_name}; }; if ($@) { $@ =~ s/\n+$/\n/; print "Installation of $dist$variation failed: $@"; } } } print join( "\n", "", "The following perls have been installed:", map ( " $_", grep defined, @ok ), "", "" ); return; } sub run_command_download { my ( $self, $dist ) = @_; $dist = $self->resolve_stable_version if $dist && $dist eq 'stable'; my $rd = $self->release_detail($dist); my $dist_tarball = $rd->{tarball_name}; my $dist_tarball_url = $rd->{tarball_url}; my $dist_tarball_path = $self->root->dists($dist_tarball); if ( -f $dist_tarball_path && !$self->{force} ) { print "$dist_tarball already exists\n"; } else { print "Download $dist_tarball_url to $dist_tarball_path\n" unless $self->{quiet}; my $error = http_download( $dist_tarball_url, $dist_tarball_path ); if ($error) { die "ERROR: Failed to download $dist_tarball_url\n$error\n"; } } } sub purify { my ( $self, $envname ) = @_; my @paths = grep { index( $_, $self->home ) < 0 && index( $_, $self->root ) < 0 } split /:/, $self->env($envname); return wantarray ? @paths : join( ":", @paths ); } sub system_perl_executable { my ($self) = @_; my $system_perl_executable = do { local $ENV{PATH} = $self->pristine_path; `perl -MConfig -e 'print \$Config{perlpath}'`; }; return $system_perl_executable; } sub system_perl_shebang { my ($self) = @_; return $Config{sharpbang} . $self->system_perl_executable; } sub pristine_path { my ($self) = @_; return $self->purify("PATH"); } sub pristine_manpath { my ($self) = @_; return $self->purify("MANPATH"); } sub run_command_display_system_perl_executable { print $_[0]->system_perl_executable . "\n"; } sub run_command_display_system_perl_shebang { print $_[0]->system_perl_shebang . "\n"; } sub run_command_display_pristine_path { print $_[0]->pristine_path . "\n"; } sub run_command_display_pristine_manpath { print $_[0]->pristine_manpath . "\n"; } sub do_install_archive { require File::Basename; my $self = shift; my $dist_tarball_path = shift; my $dist_version; my $installation_name; if ( $dist_tarball_path->basename =~ m{(c?perl)-?(5.+)\.tar\.(gz|bz2|xz)\Z} ) { my $perl_variant = $1; $dist_version = $2; $installation_name = "${perl_variant}-${dist_version}"; } unless ( $dist_version && $installation_name ) { die "Unable to determine perl version from archive filename.\n\nThe archive name should look like perl-5.x.y.tar.gz or perl-5.x.y.tar.bz2 or perl-5.x.y.tar.xz\n"; } my $dist_extracted_path = $self->do_extract_tarball($dist_tarball_path); $self->do_install_this( $dist_extracted_path, $dist_version, $installation_name ); } sub do_install_this { my ( $self, $dist_extracted_dir, $dist_version, $installation_name ) = @_; my $variation = $self->{variation}; my $append = $self->{append}; my $looks_like_we_are_installing_cperl = $dist_extracted_dir =~ /\/ cperl- /x; $self->{dist_extracted_dir} = $dist_extracted_dir; $self->{log_file} = $self->root->child("build.${installation_name}${variation}${append}.log"); my @d_options = @{ $self->{D} }; my @u_options = @{ $self->{U} }; my @a_options = @{ $self->{A} }; my $sitecustomize = $self->{sitecustomize}; my $destdir = $self->{destdir}; $installation_name = $self->{as} if $self->{as}; $installation_name .= "$variation$append"; $self->{installation_name} = $installation_name; if ($sitecustomize) { die "Could not read sitecustomize file '$sitecustomize'\n" unless -r $sitecustomize; push @d_options, "usesitecustomize"; } if ( $self->{noman} ) { push @d_options, qw/man1dir=none man3dir=none/; } for my $flavor ( keys %flavor ) { $self->{$flavor} and push @d_options, $flavor{$flavor}{d_option}; } my $perlpath = $self->root->perls($installation_name); unshift @d_options, qq(prefix=$perlpath); push @d_options, "usedevel" if $dist_version =~ /5\.\d[13579]|git|blead/; push @d_options, "usecperl" if $looks_like_we_are_installing_cperl; my $version = $self->comparable_perl_version($dist_version); if ( defined $version and $version < $self->comparable_perl_version('5.6.0') ) { # ancient perls do not support -A for Configure @a_options = (); } else { unless ( grep { /eval:scriptdir=/ } @a_options ) { push @a_options, "'eval:scriptdir=${perlpath}/bin'"; } } print "Installing $dist_extracted_dir into " . $self->root->perls($installation_name)->stringify_with_tilde . "\n\n"; print <{verbose}; This could take a while. You can run the following command on another shell to track the status: tail -f ${\ $self->{log_file}->stringify_with_tilde } INSTALL my @preconfigure_commands = ( "cd $dist_extracted_dir", "rm -f config.sh Policy.sh", ); unless ( $self->{"no-patchperl"} || $looks_like_we_are_installing_cperl ) { my $patchperl = $self->root->bin("patchperl"); unless ( -x $patchperl && -f _ ) { $patchperl = "patchperl"; } push @preconfigure_commands, 'chmod -R +w .', $patchperl; } my $configure_flags = $self->env("PERLBREW_CONFIGURE_FLAGS") || '-de'; my @configure_commands = ( "sh Configure $configure_flags " . join( ' ', ( map { qq{'-D$_'} } @d_options ), ( map { qq{'-U$_'} } @u_options ), ( map { qq{'-A$_'} } @a_options ), ), ( defined $version and $version < $self->comparable_perl_version('5.8.9') ) ? ("$^X -i -nle 'print unless /command-line/' makefile x2p/makefile") : () ); my $make = $ENV{MAKE} || ( $^O eq "solaris" ? 'gmake' : 'make' ); my @build_commands = ( $make . ' ' . ( $self->{j} ? "-j$self->{j}" : "" ) ); # Test via "make test_harness" if available so we'll get # automatic parallel testing via $HARNESS_OPTIONS. The # "test_harness" target was added in 5.7.3, which was the last # development release before 5.8.0. my $use_harness = ( $dist_version =~ /^5\.(\d+)\.(\d+)/ && ( $1 >= 8 || $1 == 7 && $2 == 3 ) ) || $dist_version eq "blead"; my $test_target = $use_harness ? "test_harness" : "test"; local $ENV{TEST_JOBS} = $self->{j} if $test_target eq "test_harness" && ( $self->{j} || 1 ) > 1; my @install_commands = ( "${make} install" . ( $destdir ? " DESTDIR=$destdir" : q|| ) ); unshift @install_commands, "${make} $test_target" unless $self->{notest}; # Whats happening here? we optionally join with && based on $self->{force}, but then subsequently join with && anyway? @install_commands = join " && ", @install_commands unless ( $self->{force} ); my $cmd = join " && ", ( @preconfigure_commands, @configure_commands, @build_commands, @install_commands ); $self->{log_file}->unlink; if ( $self->{verbose} ) { $cmd = "($cmd) 2>&1 | tee $self->{log_file}"; print "$cmd\n" if $self->{verbose}; } else { $cmd = "($cmd) >> '$self->{log_file}' 2>&1 "; } delete $ENV{$_} for qw(PERL5LIB PERL5OPT AWKPATH NO_COLOR); if ( $self->do_system($cmd) ) { my $newperl = $self->root->perls($installation_name)->perl; unless ( -e $newperl ) { $self->run_command_symlink_executables($installation_name); } eval { $self->append_log('##### Brew Finished #####') }; if ($sitecustomize) { my $capture = $self->do_capture("$newperl -V:sitelib"); my ($sitelib) = $capture =~ m/sitelib='([^']*)';/; $sitelib = $destdir . $sitelib if $destdir; $sitelib = App::Perlbrew::Path->new($sitelib); $sitelib->mkpath; my $target = $sitelib->child("sitecustomize.pl"); open my $dst, ">", $target or die "Could not open '$target' for writing: $!\n"; open my $src, "<", $sitecustomize or die "Could not open '$sitecustomize' for reading: $!\n"; print {$dst} do { local $/; <$src> }; } my $version_file = $self->root->perls($installation_name)->version_file; if ( -e $version_file ) { $version_file->unlink() or die "Could not unlink $version_file file: $!\n"; } print "$installation_name is successfully installed.\n"; } else { eval { $self->append_log('##### Brew Failed #####') }; die $self->INSTALLATION_FAILURE_MESSAGE; } return; } sub do_install_program_from_url { my ( $self, $url, $program_name, $body_filter ) = @_; my $out = $self->root->bin($program_name); if ( -f $out && !$self->{force} && !$self->{yes} ) { require ExtUtils::MakeMaker; my $ans = ExtUtils::MakeMaker::prompt( "\n$out already exists, are you sure to override ? [y/N]", "N" ); if ( $ans !~ /^Y/i ) { print "\n$program_name installation skipped.\n\n" unless $self->{quiet}; return; } } my $body = http_get($url) or die "\nERROR: Failed to retrieve $program_name executable.\n\n"; unless ( $body =~ m{\A#!/}s ) { my $x = App::Perlbrew::Path->new( $self->env('TMPDIR') || "/tmp", "${program_name}.downloaded.$$" ); my $message = "\nERROR: The downloaded $program_name program seem to be invalid. Please check if the following URL can be reached correctly\n\n\t$url\n\n...and try again latter."; unless ( -f $x ) { open my $OUT, ">", $x; print $OUT $body; close($OUT); $message .= "\n\nThe previously downloaded file is saved at $x for manual inspection.\n\n"; } die $message; } if ( $body_filter && ref($body_filter) eq "CODE" ) { $body = $body_filter->($body); } $self->root->bin->mkpath; open my $OUT, '>', $out or die "cannot open file($out): $!"; print $OUT $body; close $OUT; chmod 0755, $out; print "\n$program_name is installed to\n\n $out\n\n" unless $self->{quiet}; } sub do_exit_with_error_code { my ( $self, $code ) = @_; exit($code); } sub do_system_with_exit_code { my ( $self, @cmd ) = @_; return system(@cmd); } sub do_system { my ( $self, @cmd ) = @_; return !$self->do_system_with_exit_code(@cmd); } sub do_capture { my ( $self, @cmd ) = @_; return Capture::Tiny::capture( sub { $self->do_system(@cmd); } ); } sub format_perl_version { my $self = shift; my $version = shift; return sprintf "%d.%d.%d", substr( $version, 0, 1 ), substr( $version, 2, 3 ), substr( $version, 5 ) || 0; } sub installed_perls { my $self = shift; my @result; my $root = $self->root; for my $installation ( $root->perls->list ) { my $name = $installation->name; my $executable = $installation->perl; next unless -f $executable; my $version_file = $installation->version_file; my $ctime = localtime( ( stat $executable )[10] ); # localtime in scalar context! my $orig_version; if ( -e $version_file ) { open my $fh, '<', $version_file; local $/; $orig_version = <$fh>; chomp $orig_version; } else { $orig_version = `$executable -e 'print \$]'`; if ( defined $orig_version and length $orig_version ) { if ( open my $fh, '>', $version_file ) { print {$fh} $orig_version; } } } push @result, { name => $name, orig_version => $orig_version, version => $self->format_perl_version($orig_version), is_current => ( $self->current_perl eq $name ) && !( $self->current_lib ), libs => [$self->local_libs($name)], executable => $executable, dir => $installation, comparable_version => $self->comparable_perl_version($orig_version), ctime => $ctime, }; } return sort { ( $self->{reverse} ? ( $a->{comparable_version} <=> $b->{comparable_version} or $b->{name} cmp $a->{name} ) : ( $b->{comparable_version} <=> $a->{comparable_version} or $a->{name} cmp $b->{name} ) ) } @result; } sub compose_locallib { my ( $self, $perl_name, $lib_name ) = @_; return join '@', $perl_name, $lib_name; } sub decompose_locallib { my ( $self, $name ) = @_; return split '@', $name; } sub enforce_localib { my ( $self, $name ) = @_; $name =~ s/^/@/ unless $name =~ m/@/; return $name; } sub local_libs { my ( $self, $perl_name ) = @_; my $current = $self->current_env; my @libs = map { my $name = $_->basename; my ( $p, $l ) = $self->decompose_locallib($name); +{ name => $name, is_current => $name eq $current, perl_name => $p, lib_name => $l, dir => $_, } } $self->home->child("libs")->children; if ($perl_name) { @libs = grep { $perl_name eq $_->{perl_name} } @libs; } return @libs; } sub is_installed { my ( $self, $name ) = @_; return grep { $name eq $_->{name} } $self->installed_perls; } sub assert_known_installation { my ( $self, $name ) = @_; return 1 if $self->is_installed($name); die "ERROR: The installation \"$name\" is unknown\n\n"; } # Return a hash of PERLBREW_* variables sub perlbrew_env { my ( $self, $name ) = @_; my ( $perl_name, $lib_name ); if ($name) { ( $perl_name, $lib_name ) = $self->resolve_installation_name($name); unless ($perl_name) { die "\nERROR: The installation \"$name\" is unknown.\n\n"; } unless ( !$lib_name || grep { $_->{lib_name} eq $lib_name } $self->local_libs($perl_name) ) { die "\nERROR: The lib name \"$lib_name\" is unknown.\n\n"; } } my %env = ( PERLBREW_VERSION => $VERSION, PERLBREW_PATH => $self->root->bin, PERLBREW_MANPATH => "", PERLBREW_ROOT => $self->root ); require local::lib; my $pb_home = $self->home; my $current_local_lib_root = $self->env("PERL_LOCAL_LIB_ROOT") || ""; my $current_local_lib_context = local::lib->new; my @perlbrew_local_lib_root = uniq( grep { /\Q${pb_home}\E/ } split( /:/, $current_local_lib_root ) ); if ( $current_local_lib_root =~ /^\Q${pb_home}\E/ ) { $current_local_lib_context = $current_local_lib_context->activate($_) for @perlbrew_local_lib_root; } if ($perl_name) { my $installation = $self->root->perls($perl_name); if ( -d $installation->child("bin") ) { $env{PERLBREW_PERL} = $perl_name; $env{PERLBREW_PATH} .= ":" . $installation->child("bin"); $env{PERLBREW_MANPATH} = $installation->child("man"); } if ($lib_name) { $current_local_lib_context = $current_local_lib_context->deactivate($_) for @perlbrew_local_lib_root; my $base = $self->home->child( "libs", "${perl_name}\@${lib_name}" ); if ( -d $base ) { $current_local_lib_context = $current_local_lib_context->activate($base); if ( $self->env('PERLBREW_LIB_PREFIX') ) { unshift @{ $current_local_lib_context->libs }, $self->env('PERLBREW_LIB_PREFIX'); } $env{PERLBREW_PATH} = $base->child("bin") . ":" . $env{PERLBREW_PATH}; $env{PERLBREW_MANPATH} = $base->child("man") . ":" . $env{PERLBREW_MANPATH}; $env{PERLBREW_LIB} = $lib_name; } } else { $current_local_lib_context = $current_local_lib_context->deactivate($_) for @perlbrew_local_lib_root; $env{PERLBREW_LIB} = undef; } my %ll_env = $current_local_lib_context->build_environment_vars; delete $ll_env{PATH}; for my $key ( keys %ll_env ) { $env{$key} = $ll_env{$key}; } } else { $current_local_lib_context = $current_local_lib_context->deactivate($_) for @perlbrew_local_lib_root; my %ll_env = $current_local_lib_context->build_environment_vars; delete $ll_env{PATH}; for my $key ( keys %ll_env ) { $env{$key} = $ll_env{$key}; } $env{PERLBREW_LIB} = undef; $env{PERLBREW_PERL} = undef; } return %env; } sub run_command_list { my $self = shift; my $is_verbose = $self->{verbose}; if ( $self->{'no-decoration'} ) { for my $i ( $self->installed_perls ) { print $i->{name} . "\n"; for my $lib ( @{ $i->{libs} } ) { print $lib->{name} . "\n"; } } } else { for my $i ( $self->installed_perls ) { printf "%-2s%-20s %-20s %s\n", $i->{is_current} ? '*' : '', $i->{name}, ( $is_verbose ? ( index( $i->{name}, $i->{version} ) < 0 ) ? "($i->{version})" : '' : '' ), ( $is_verbose ? "(installed on $i->{ctime})" : '' ); for my $lib ( @{ $i->{libs} } ) { print $lib->{is_current} ? "* " : " ", $lib->{name}, "\n"; } } } return 0; } sub launch_sub_shell { my ( $self, $name ) = @_; my $shell = $self->env('SHELL'); my $shell_opt = ""; if ( $shell =~ /\/zsh\d?$/ ) { $shell_opt = "-d -f"; if ( $^O eq 'darwin' ) { my $root_dir = $self->root; print <<"WARNINGONMAC"; -------------------------------------------------------------------------------- WARNING: zsh perlbrew sub-shell is not working on Mac OSX Lion. It is known that on MacOS Lion, zsh always resets the value of PATH on launching a sub-shell. Effectively nullify the changes required by perlbrew sub-shell. You may `echo \$PATH` to examine it and if you see perlbrew related paths are in the end, instead of in the beginning, you are unfortunate. You are advised to include the following line to your ~/.zshenv as a better way to work with perlbrew: source $root_dir/etc/bashrc -------------------------------------------------------------------------------- WARNINGONMAC } } my %env = ( $self->perlbrew_env($name), PERLBREW_SKIP_INIT => 1 ); unless ( $ENV{PERLBREW_VERSION} ) { my $root = $self->root; # The user does not source bashrc/csh in their shell initialization. $env{PATH} = $env{PERLBREW_PATH} . ":" . join ":", grep { !/$root\/bin/ } split ":", $ENV{PATH}; $env{MANPATH} = $env{PERLBREW_MANPATH} . ":" . join ":", grep { !/$root\/man/ } ( defined( $ENV{MANPATH} ) ? split( ":", $ENV{MANPATH} ) : () ); } my $command = "env "; while ( my ( $k, $v ) = each(%env) ) { no warnings "uninitialized"; $command .= "$k=\"$v\" "; } $command .= " $shell $shell_opt"; my $pretty_name = defined($name) ? $name : "the default perl"; print "\nA sub-shell is launched with $pretty_name as the activated perl. Run 'exit' to finish it.\n\n"; exec($command); } sub run_command_use { my $self = shift; my $perl = shift; if ( !$perl ) { my $current = $self->current_env; if ($current) { print "Currently using $current\n"; } else { print "No version in use; defaulting to system\n"; } return; } $self->launch_sub_shell($perl); } sub run_command_switch { my ( $self, $dist, $alias ) = @_; unless ($dist) { my $current = $self->current_env; printf "Currently switched %s\n", ( $current ? "to $current" : 'off' ); return; } $self->switch_to( $dist, $alias ); } sub switch_to { my ( $self, $dist, $alias ) = @_; die "Cannot use for alias something that starts with 'perl-'\n" if $alias && $alias =~ /^perl-/; die "${dist} is not installed\n" unless -d $self->root->perls($dist); if ( $self->env("PERLBREW_SHELLRC_VERSION") && $self->current_shell_is_bashish ) { local $ENV{PERLBREW_PERL} = $dist; my $HOME = $self->env('HOME'); my $pb_home = $self->home; $pb_home->mkpath; system( "$0 env $dist > " . $pb_home->child("init") ); print "Switched to $dist.\n\n"; } else { $self->launch_sub_shell($dist); } } sub run_command_off { my $self = shift; $self->launch_sub_shell; } sub run_command_switch_off { my $self = shift; my $pb_home = $self->home; $pb_home->mkpath; system( "env PERLBREW_PERL= $0 env > " . $pb_home->child("init") ); print "\nperlbrew is switched off. Please exit this shell and start a new one to make it effective.\n"; print "To immediately make it effective, run this line in this terminal:\n\n exec @{[ $self->env('SHELL') ]}\n\n"; } sub shell_env { my ( $self, $env ) = @_; my %env = %$env; my @statements; for my $k ( sort keys %env ) { my $v = $env{$k}; if ( defined($v) && $v ne '' ) { $v =~ s/(\\")/\\$1/g; push @statements, ["set", $k, $v]; } else { push @statements, ["unset", $k]; } } my $statements = ""; if ( $self->env('SHELL') =~ /(ba|k|z|\/)sh\d?$/ ) { for (@statements) { my ( $o, $k, $v ) = @$_; if ( $o eq 'unset' ) { $statements .= "unset $k\n"; } else { $v =~ s/(\\")/\\$1/g; $statements .= "export $k=\"$v\"\n"; } } } else { for (@statements) { my ( $o, $k, $v ) = @$_; if ( $o eq 'unset' ) { $statements .= "unsetenv $k\n"; } else { $statements .= "setenv $k \"$v\"\n"; } } } return $statements; } sub run_command_env { my ( $self, $name ) = @_; print $self->shell_env({ $self->perlbrew_env($name) }); } sub run_command_symlink_executables { my ( $self, @perls ) = @_; my $root = $self->root; unless (@perls) { @perls = map { $_->name } grep { -d $_ && !-l $_ } $root->perls->list; } for my $perl (@perls) { for my $executable ( $root->perls($perl)->bin->children ) { my ( $name, $version ) = $executable =~ m/bin\/(.+?)(5\.\d.*)?$/; next unless $version; $executable->symlink( $root->perls($perl)->bin($name) ); $executable->symlink( $root->perls($perl)->perl ) if $name eq "cperl"; } } } sub run_command_install_patchperl { my ($self) = @_; $self->do_install_program_from_url( 'https://raw.githubusercontent.com/gugod/patchperl-packing/master/patchperl', 'patchperl', sub { my ($body) = @_; $body =~ s/\A#!.+?\n/ $self->system_perl_shebang . "\n" /se; return $body; } ); } sub run_command_install_cpanm { my ($self) = @_; $self->do_install_program_from_url( 'https://raw.githubusercontent.com/miyagawa/cpanminus/master/cpanm' => 'cpanm' ); } sub run_command_install_cpm { my ($self) = @_; $self->do_install_program_from_url( 'https://raw.githubusercontent.com/skaji/cpm/main/cpm' => 'cpm' ); } sub run_command_self_upgrade { my ($self) = @_; require FindBin; unless ( -w $FindBin::Bin ) { die "Your perlbrew installation appears to be system-wide. Please upgrade through your package manager.\n"; } my $TMPDIR = $ENV{TMPDIR} || "/tmp"; my $TMP_PERLBREW = App::Perlbrew::Path->new( $TMPDIR, "perlbrew" ); http_download( 'https://raw.githubusercontent.com/gugod/App-perlbrew/master/perlbrew', $TMP_PERLBREW ); chmod 0755, $TMP_PERLBREW; my $new_version = qx($TMP_PERLBREW version); chomp $new_version; if ( $new_version =~ /App::perlbrew\/(\d+\.\d+)$/ ) { $new_version = $1; } else { $TMP_PERLBREW->unlink; die "Unable to detect version of new perlbrew!\n"; } if ( $new_version <= $VERSION ) { print "Your perlbrew is up-to-date (version $VERSION).\n" unless $self->{quiet}; $TMP_PERLBREW->unlink; return; } print "Upgrading from $VERSION to $new_version\n" unless $self->{quiet}; system $TMP_PERLBREW, "self-install"; $TMP_PERLBREW->unlink; } sub run_command_uninstall { my ( $self, $target ) = @_; unless ($target) { $self->run_command_help("uninstall"); exit(-1); } my @installed = $self->installed_perls(@_); my ($to_delete) = grep { $_->{name} eq $target } @installed; die "'$target' is not installed\n" unless $to_delete; my @dir_to_delete; for ( @{ $to_delete->{libs} } ) { push @dir_to_delete, $_->{dir}; } push @dir_to_delete, $to_delete->{dir}; my $ans = ( $self->{yes} ) ? "Y" : undef; if ( !defined($ans) ) { require ExtUtils::MakeMaker; $ans = ExtUtils::MakeMaker::prompt( "\nThe following perl+lib installation(s) will be deleted:\n\n\t" . join( "\n\t", @dir_to_delete ) . "\n\n... are you sure ? [y/N]", "N" ); } if ( $ans =~ /^Y/i ) { for (@dir_to_delete) { print "Deleting: $_\n" unless $self->{quiet}; App::Perlbrew::Path->new($_)->rmpath; print "Deleted: $_\n" unless $self->{quiet}; } } else { print "\nOK. Not deleting anything.\n\n"; return; } } sub run_command_exec { my $self = shift; my %opts; local (@ARGV) = @{ $self->{original_argv} }; Getopt::Long::Configure('require_order'); my @command_options = ( 'with=s', 'halt-on-error', 'min=s', 'max=s' ); $self->parse_cmdline( \%opts, @command_options ); shift @ARGV; # "exec" $self->parse_cmdline( \%opts, @command_options ); my @exec_with; if ( $opts{with} ) { my %installed = map { $_->{name} => $_ } map { ( $_, @{ $_->{libs} } ) } $self->installed_perls; my $d = ( $opts{with} =~ m/ / ) ? qr( +) : qr(,+); my @with = grep { $_ } map { my ( $p, $l ) = $self->resolve_installation_name($_); $p .= "\@$l" if $l; $p; } split $d, $opts{with}; @exec_with = map { $installed{$_} } @with; } else { @exec_with = grep { not -l $self->root->perls( $_->{name} ); # Skip Aliases } map { ( $_, @{ $_->{libs} } ) } $self->installed_perls; } if ( $opts{min} ) { # TODO use comparable version. # For now, it doesn't produce consistent results for 5.026001 and 5.26.1 @exec_with = grep { $_->{orig_version} >= $opts{min} } @exec_with; } if ( $opts{max} ) { @exec_with = grep { $_->{orig_version} <= $opts{max} } @exec_with; } if ( 0 == @exec_with ) { print "No perl installation found.\n" unless $self->{quiet}; } my $no_header = 0; if ( 1 == @exec_with ) { $no_header = 1; } my $overall_success = 1; for my $i (@exec_with) { my %env = $self->perlbrew_env( $i->{name} ); next if !$env{PERLBREW_PERL}; local %ENV = %ENV; $ENV{$_} = defined $env{$_} ? $env{$_} : '' for keys %env; $ENV{PATH} = join( ':', $env{PERLBREW_PATH}, $ENV{PATH} ); $ENV{MANPATH} = join( ':', $env{PERLBREW_MANPATH}, $ENV{MANPATH} || "" ); $ENV{PERL5LIB} = $env{PERL5LIB} || ""; print "$i->{name}\n==========\n" unless $no_header || $self->{quiet}; if ( my $err = $self->do_system_with_exit_code(@ARGV) ) { my $exit_code = $err >> 8; # return 255 for case when process was terminated with signal, in that case real exit code is useless and weird $exit_code = 255 if $exit_code > 255; $overall_success = 0; unless ( $self->{quiet} ) { print "Command terminated with non-zero status.\n"; print STDERR "Command [" . join( ' ', map { /\s/ ? "'$_'" : $_ } @ARGV ) . # trying reverse shell escapes - quote arguments containing spaces "] terminated with exit code $exit_code (\$? = $err) under the following perl environment:\n"; print STDERR $self->format_info_output; } $self->do_exit_with_error_code($exit_code) if ( $opts{'halt-on-error'} ); } print "\n" unless $self->{quiet} || $no_header; } $self->do_exit_with_error_code(1) unless $overall_success; } sub run_command_clean { my ($self) = @_; my $root = $self->root; my @build_dirs = $root->build->children; for my $dir (@build_dirs) { print "Removing $dir\n"; App::Perlbrew::Path->new($dir)->rmpath; } my @tarballs = $root->dists->children; for my $file (@tarballs) { print "Removing $file\n"; $file->unlink; } print "\nDone\n"; } sub run_command_alias { my ( $self, $cmd, $name, $alias ) = @_; unless ($cmd) { $self->run_command_help("alias"); exit(-1); } my $path_name = $self->root->perls($name) if $name; my $path_alias = $self->root->perls($alias) if $alias; if ( $alias && -e $path_alias && !-l $path_alias ) { die "\nABORT: The installation name `$alias` is not an alias, cannot override.\n\n"; } if ( $cmd eq 'create' ) { $self->assert_known_installation($name); if ( $self->is_installed($alias) && !$self->{force} ) { die "\nABORT: The installation `${alias}` already exists. Cannot override.\n\n"; } $path_alias->unlink; $path_name->symlink($path_alias); } elsif ( $cmd eq 'delete' ) { $self->assert_known_installation($name); unless ( -l $path_name ) { die "\nABORT: The installation name `$name` is not an alias, cannot remove.\n\n"; } $path_name->unlink; } elsif ( $cmd eq 'rename' ) { $self->assert_known_installation($name); unless ( -l $path_name ) { die "\nABORT: The installation name `$name` is not an alias, cannot rename.\n\n"; } if ( -l $path_alias && !$self->{force} ) { die "\nABORT: The alias `$alias` already exists, cannot rename to it.\n\n"; } rename( $path_name, $path_alias ); } elsif ( $cmd eq 'help' ) { $self->run_command_help("alias"); } else { die "\nERROR: Unrecognized action: `${cmd}`.\n\n"; } } sub run_command_display_bashrc { print BASHRC_CONTENT(); } sub run_command_display_cshrc { print CSHRC_CONTENT(); } sub run_command_display_installation_failure_message { my ($self) = @_; } sub run_command_lib { my ( $self, $subcommand, @args ) = @_; unless ($subcommand) { $self->run_command_help("lib"); exit(-1); } my $sub = "run_command_lib_$subcommand"; if ( $self->can($sub) ) { $self->$sub(@args); } else { print "Unknown command: $subcommand\n"; } } sub run_command_lib_create { my ( $self, $name ) = @_; die "ERROR: No lib name\n", $self->run_command_help( "lib", undef, 'return_text' ) unless $name; $name = $self->enforce_localib($name); my ( $perl_name, $lib_name ) = $self->resolve_installation_name($name); if ( !$perl_name ) { my ( $perl_name, $lib_name ) = $self->decompose_locallib($name); die "ERROR: '$perl_name' is not installed yet, '$name' cannot be created.\n"; } my $fullname = $self->compose_locallib( $perl_name, $lib_name ); my $dir = $self->home->child( "libs", $fullname ); if ( -d $dir ) { die "$fullname is already there.\n"; } $dir->mkpath; print "lib '$fullname' is created.\n" unless $self->{quiet}; return; } sub run_command_lib_delete { my ( $self, $name ) = @_; die "ERROR: No lib to delete\n", $self->run_command_help( "lib", undef, 'return_text' ) unless $name; $name = $self->enforce_localib($name); my ( $perl_name, $lib_name ) = $self->resolve_installation_name($name); my $fullname = $self->compose_locallib( $perl_name, $lib_name ); my $current = $self->current_env; my $dir = $self->home->child( "libs", $fullname ); if ( -d $dir ) { if ( $fullname eq $current ) { die "$fullname is currently being used in the current shell, it cannot be deleted.\n"; } $dir->rmpath; print "lib '$fullname' is deleted.\n" unless $self->{quiet}; } else { die "ERROR: '$fullname' does not exist.\n"; } return; } sub run_command_lib_list { my ($self) = @_; my $dir = $self->home->child("libs"); return unless -d $dir; opendir my $dh, $dir or die "open $dir failed: $!"; my @libs = grep { !/^\./ && /\@/ } readdir($dh); my $current = $self->current_env; for (@libs) { print $current eq $_ ? "* " : " "; print "$_\n"; } } sub run_command_upgrade_perl { my ($self) = @_; my $PERL_VERSION_RE = qr/(\d+)\.(\d+)\.(\d+)/; my ($current) = grep { $_->{is_current} } $self->installed_perls; unless ( defined $current ) { print "no perlbrew environment is currently in use\n"; exit(1); } my ( $major, $minor, $release ); if ( $current->{version} =~ /^$PERL_VERSION_RE$/ ) { ( $major, $minor, $release ) = ( $1, $2, $3 ); } else { print "unable to parse version '$current->{version}'\n"; exit(1); } my @available = grep { /^perl-$major\.$minor/ } $self->available_perls; my $latest_available_perl = $release; foreach my $perl (@available) { if ( $perl =~ /^perl-$PERL_VERSION_RE$/ ) { my $this_release = $3; if ( $this_release > $latest_available_perl ) { $latest_available_perl = $this_release; } } } if ( $latest_available_perl == $release ) { print "This perlbrew environment ($current->{name}) is already up-to-date.\n"; exit(0); } my $dist_version = "$major.$minor.$latest_available_perl"; my $dist = "perl-$dist_version"; print "Upgrading $current->{name} to $dist_version\n" unless $self->{quiet}; local $self->{as} = $current->{name}; local $self->{dist_name} = $dist; my @d_options = map { '-D' . $flavor{$_}->{d_option} } keys %flavor; my %sub_config = map { $_ => $Config{$_} } grep { /^config_arg\d/ } keys %Config; for my $value ( values %sub_config ) { my $value_wo_D = $value; $value_wo_D =~ s/^-D//; push @{ $self->{D} }, $value_wo_D if grep { /$value/ } @d_options; } $self->do_install_release( $dist, $dist_version ); } sub list_modules { my ( $self, $env ) = @_; $env ||= $self->current_env; my ( $stdout, $stderr, $success ) = Capture::Tiny::capture( sub { __PACKAGE__->new( "--quiet", "exec", "--with", $env, 'perl', '-MExtUtils::Installed', '-le', 'BEGIN{@INC=grep {$_ ne q!.!} @INC}; print for ExtUtils::Installed->new->modules;', )->run; } ); unless ($success) { unless ( $self->{quiet} ) { print STDERR "Failed to retrive the list of installed modules.\n"; if ( $self->{verbose} ) { print STDERR "STDOUT\n======\n$stdout\nSTDERR\n======\n$stderr\n"; } } return []; } my %rename = ( "ack" => "App::Ack", "libwww::perl" => "LWP", "libintl-perl" => "Locale::Messages", "Role::Identifiable" => "Role::Identifiable::HasTags", "TAP::Harness::Multiple" => "TAP::Harness::ReportByDescription", ); return [map { $rename{$_} || $_ } grep { $_ ne "Perl" } split( /\n/, $stdout )]; } sub run_command_list_modules { my ($self) = @_; my ( $modules, $error ) = $self->list_modules(); print "$_\n" for @$modules; } sub resolve_installation_name { my ( $self, $name ) = @_; die "App::perlbrew->resolve_installation_name requires one argument." unless $name; my ( $perl_name, $lib_name ) = $self->decompose_locallib($name); $perl_name = $name unless $lib_name; $perl_name ||= $self->current_perl; if ( !$self->is_installed($perl_name) ) { if ( $self->is_installed("perl-${perl_name}") ) { $perl_name = "perl-${perl_name}"; } else { return undef; } } return wantarray ? ( $perl_name, $lib_name ) : $perl_name; } # Implementation of the 'clone-modules' command. # # This method accepts a destination and source installation # of Perl to clone modules from and into. # For instance calling # $app->run_command_clone_modules($perl_a, $perl_b); # installs all modules that have been installed on Perl A # to the instance of Perl B. # The source instance is optional, that is if the method # is invoked with a single argument, the currently # running instance is used as source. Therefore the # two following calls are the same: # # $app->run_command_clone_modules( $self->current_perl, $perl_b ); # $app->run_command_clone_modules( $perl_b ); # # Of course, both Perl installation must exist on this # perlbrew enviroment. # # The method extracts the modules installed on the source Perl # instance and put them on a temporary file, such file is then # passed to another instance of the application to # execute cpanm on it. The final result is the installation # of source modules into the destination instance. sub run_command_clone_modules { my $self = shift; # default to use the currently installation my ( $dst_perl, $src_perl ); # the first argument is the destination, the second # optional argument is the source version, default # to use the current installation $dst_perl = pop || $self->current_env; $src_perl = pop || $self->current_env; # check source and destination do exist undef $src_perl if ( !$self->resolve_installation_name($src_perl) ); undef $dst_perl if ( !$self->resolve_installation_name($dst_perl) ); if ( !$src_perl || !$dst_perl || $src_perl eq $dst_perl ) { # cannot understand from where to where or # the user did specify the same versions $self->run_command_help('clone-modules'); exit(-1); } my @modules_to_install = @{ $self->list_modules($src_perl) }; unless (@modules_to_install) { print "\nNo modules installed on $src_perl !\n" unless $self->{quiet}; return; } print "\nInstalling $#modules_to_install modules from $src_perl to $dst_perl ...\n" unless $self->{quiet}; # create a new application to 'exec' the 'cpanm' # with the specified module list my @args = ( qw(--quiet exec --with), $dst_perl, 'cpanm' ); push @args, '--notest' if $self->{notest}; push @args, @modules_to_install; __PACKAGE__->new(@args)->run; } sub format_info_output { my ( $self, $module ) = @_; my $out = ''; $out .= "Current perl:\n"; if ( $self->current_perl ) { $out .= " Name: " . $self->current_env . "\n"; $out .= " Path: " . $self->installed_perl_executable( $self->current_perl ) . "\n"; $out .= " Config: " . $self->configure_args( $self->current_perl ) . "\n"; $out .= join( '', " Compiled at: ", ( map { / Compiled at (.+)\n/ ? $1 : () } `@{[ $self->installed_perl_executable($self->current_perl) ]} -V` ), "\n" ); } else { $out .= "Using system perl." . "\n"; $out .= "Shebang: " . $self->system_perl_shebang . "\n"; } $out .= "\nperlbrew:\n"; $out .= " version: " . $self->VERSION . "\n"; $out .= " ENV:\n"; for ( map { "PERLBREW_$_" } qw(ROOT HOME PATH MANPATH) ) { $out .= " $_: " . ( $self->env($_) || "" ) . "\n"; } if ($module) { my $code = qq{eval "require $module" and do { (my \$f = "$module") =~ s<::>g; \$f .= ".pm"; print "$module\n Location: \$INC{\$f}\n Version: " . ($module->VERSION ? $module->VERSION : "no VERSION specified" ) } or do { print "$module could not be found, is it installed?" } }; $out .= "\nModule: " . $self->do_capture( $self->installed_perl_executable( $self->current_perl ), "-le", $code ); } $out; } sub run_command_info { my ($self) = shift; print $self->format_info_output(@_); } sub run_command_make_shim { my ($self, $program) = @_; unless ($program) { $self->run_command_help("make-shim"); return; } my $output = $self->{output} || $program; if (-f $output) { die "ERROR: $program already exists under current directory.\n"; } my $current_env = $self->current_env or die "ERROR: perlbrew is not activated. make-shim requires an perlbrew environment to be activated.\nRead the usage by running: perlbrew help make-shim\n"; my %env = $self->perlbrew_env( $current_env ); my $shebang = '#!' . $self->env('SHELL'); my $preemble = $self->shell_env(\%env); my $path = $self->shell_env({ PATH => $env{"PERLBREW_PATH"} . ":" . $self->env("PATH") }); my $shim = join( "\n", $shebang, $preemble, $path, 'exec ' . $program . ' "$@"', "\n" ); open my $fh, ">", "$output" or die $!; print $fh $shim; close $fh; chmod 0755, $output; if ( $self->{verbose} ) { print "The shim $output is made.\n"; } } sub run_command_make_pp { my ($self, $program) = @_; unless ($program) { $self->run_command_help("make-pp"); return; } my $current_env = $self->current_env or die "ERROR: perlbrew is not activated. make-pp requires an perlbrew environment to be activated.\nRead the usage by running: perlbrew help make-pp\n"; my $output = $self->{output} || $program; if (-f $output) { die "ERROR: $program already exists under current directory.\n"; } my $path_program = $self->whereis_in_env($program, $current_env) or die "ERROR: $program cannot be found in $current_env"; my $path_pp = $self->whereis_in_env("pp", $current_env) or die "ERROR: pp cannot be found in $current_env"; my $sitelib = $self->do_capture( $self->installed_perl_executable( $self->current_perl ), "-MConfig", "-e", 'print $Config{sitelibexp}', ); my $locallib; if ($self->current_lib) { require local::lib; my ($current_lib) = grep { $_->{is_current} } $self->local_libs(); my @llpaths = sort { length($a) <=> length($b) } local::lib->lib_paths_for( $current_lib->{dir} ); $locallib = $llpaths[0]; } my $perlversion = $self->do_capture( $self->installed_perl_executable( $self->current_perl ), "-MConfig", "-e", 'print $Config{version}', ); my @cmd = ( $path_pp, "-B", # core modules "-a", "$sitelib;$perlversion", ($locallib ? ("-a", "$locallib;$perlversion") : ()), "-z", "9", "-o", $output, $path_program, ); $self->do_system(@cmd); } sub whereis_in_env { my ($self, $program, $env) = @_; my %env = $self->perlbrew_env( $env ); my @paths = split /:/, $env{PERLBREW_PATH}; my ($path) = grep { -x $_ } map { App::Perlbrew::Path->new($_, $program) } @paths; return $path; } sub BASHRC_CONTENT() { return "export PERLBREW_SHELLRC_VERSION=$VERSION\n" . ( exists $ENV{PERLBREW_ROOT} ? "export PERLBREW_ROOT=$PERLBREW_ROOT\n" : "" ) . "\n" . <<'RC'; __perlbrew_reinit() { if [[ ! -d "$PERLBREW_HOME" ]]; then mkdir -p "$PERLBREW_HOME" fi [ -f "$PERLBREW_HOME/init" ] && rm "$PERLBREW_HOME/init" echo '# DO NOT EDIT THIS FILE' > "$PERLBREW_HOME/init" command perlbrew env $1 | \grep PERLBREW_ >> "$PERLBREW_HOME/init" . "$PERLBREW_HOME/init" __perlbrew_set_path } __perlbrew_purify () { local path patharray outsep IFS=: read -r${BASH_VERSION+a}${ZSH_VERSION+A} patharray <<< "$1" for path in "${patharray[@]}" ; do case "$path" in (*"$PERLBREW_HOME"*) ;; (*"$PERLBREW_ROOT"*) ;; (*) printf '%s' "$outsep$path" ; outsep=: ;; esac done } __perlbrew_set_path () { export MANPATH=${PERLBREW_MANPATH:-}${PERLBREW_MANPATH:+:}$(__perlbrew_purify "$(manpath 2>/dev/null)") export PATH=${PERLBREW_PATH:-$PERLBREW_ROOT/bin}:$(__perlbrew_purify "$PATH") hash -r } __perlbrew_set_env() { local code code="$($perlbrew_command env $@)" || return $? eval "$code" } __perlbrew_activate() { [[ -n $(alias perl 2>/dev/null) ]] && unalias perl 2>/dev/null if [[ -n "${PERLBREW_PERL:-}" ]]; then __perlbrew_set_env "${PERLBREW_PERL:-}${PERLBREW_LIB:+@}$PERLBREW_LIB" fi __perlbrew_set_path } __perlbrew_deactivate() { __perlbrew_set_env unset PERLBREW_PERL unset PERLBREW_LIB __perlbrew_set_path } perlbrew () { local exit_status local short_option export SHELL if [[ $1 == -* ]]; then short_option=$1 shift else short_option="" fi case $1 in (use) if [[ -z "$2" ]] ; then echo -n "Currently using ${PERLBREW_PERL:-system perl}" [ -n "$PERLBREW_LIB" ] && echo -n "@$PERLBREW_LIB" echo else __perlbrew_set_env "$2" && { __perlbrew_set_path ; true ; } exit_status="$?" fi ;; (switch) if [[ -z "$2" ]] ; then command perlbrew switch else perlbrew use $2 && { __perlbrew_reinit $2 ; true ; } exit_status=$? fi ;; (off) __perlbrew_deactivate echo "perlbrew is turned off." ;; (switch-off) __perlbrew_deactivate __perlbrew_reinit echo "perlbrew is switched off." ;; (*) command perlbrew $short_option "$@" exit_status=$? ;; esac hash -r return ${exit_status:-0} } [[ -z "${PERLBREW_ROOT:-}" ]] && export PERLBREW_ROOT="$HOME/perl5/perlbrew" [[ -z "${PERLBREW_HOME:-}" ]] && export PERLBREW_HOME="$HOME/.perlbrew" if [[ ! -n "${PERLBREW_SKIP_INIT:-}" ]]; then if [[ -f "${PERLBREW_HOME:-}/init" ]]; then . "$PERLBREW_HOME/init" fi fi if [[ -f "${PERLBREW_ROOT:-}/bin/perlbrew" ]]; then perlbrew_command="${PERLBREW_ROOT:-}/bin/perlbrew" else perlbrew_command="perlbrew" fi __perlbrew_activate RC } sub BASH_COMPLETION_CONTENT() { return <<'COMPLETION'; if [[ -n ${ZSH_VERSION-} ]]; then autoload -U +X bashcompinit && bashcompinit fi export PERLBREW="command perlbrew" _perlbrew_compgen() { COMPREPLY=( $($PERLBREW compgen $COMP_CWORD ${COMP_WORDS[*]}) ) } complete -F _perlbrew_compgen perlbrew COMPLETION } sub PERLBREW_FISH_CONTENT { return "set -x PERLBREW_SHELLRC_VERSION $VERSION\n" . <<'END'; function __perlbrew_reinit if not test -d "$PERLBREW_HOME" mkdir -p "$PERLBREW_HOME" end echo '# DO NOT EDIT THIS FILE' > "$PERLBREW_HOME/init" command perlbrew env $argv[1] | \grep PERLBREW_ >> "$PERLBREW_HOME/init" __source_init __perlbrew_set_path end function __perlbrew_set_path set -l MANPATH_WITHOUT_PERLBREW (perl -e 'print join ":", grep { index($_, $ENV{PERLBREW_HOME}) < 0 } grep { index($_, $ENV{PERLBREW_ROOT}) < 0 } split/:/,qx(manpath 2> /dev/null);') if test -n "$PERLBREW_MANPATH" set -l PERLBREW_MANPATH $PERLBREW_MANPATH":" set -x MANPATH {$PERLBREW_MANPATH}{$MANPATH_WITHOUT_PERLBREW} else set -x MANPATH $MANPATH_WITHOUT_PERLBREW end set -l PATH_WITHOUT_PERLBREW (eval $perlbrew_command display-pristine-path | perl -pe'y/:/ /') # silencing stderr in case there's a non-existent path in $PATH (see GH#446) if test -n "$PERLBREW_PATH" set -x PERLBREW_PATH (echo $PERLBREW_PATH | perl -pe 'y/:/ /' ) eval set -x PATH $PERLBREW_PATH $PATH_WITHOUT_PERLBREW 2> /dev/null else eval set -x PATH $PERLBREW_ROOT/bin $PATH_WITHOUT_PERLBREW 2> /dev/null end end function __perlbrew_set_env set -l code (eval $perlbrew_command env $argv | perl -pe 's/^(export|setenv)/set -xg/; s/=/ /; s/^unset(env)* (.*)/if test -n "\$$2"; set -eg $2; end/; s/$/;/; y/:/ /') if test -z "$code" return 0; else eval $code end end function __perlbrew_activate functions -e perl if test -n "$PERLBREW_PERL" if test -z "$PERLBREW_LIB" __perlbrew_set_env $PERLBREW_PERL else __perlbrew_set_env $PERLBREW_PERL@$PERLBREW_LIB end end __perlbrew_set_path end function __perlbrew_deactivate __perlbrew_set_env set -x PERLBREW_PERL set -x PERLBREW_LIB set -x PERLBREW_PATH __perlbrew_set_path end function perlbrew test -z "$argv" and echo " Usage: perlbrew [options] [arguments]" and echo " or: perlbrew help" and return 1 switch $argv[1] case use if test ( count $argv ) -eq 1 if test -z "$PERLBREW_PERL" echo "Currently using system perl" else echo "Currently using $PERLBREW_PERL" end else __perlbrew_set_env $argv[2] if test "$status" -eq 0 __perlbrew_set_path end end case switch if test ( count $argv ) -eq 1 command perlbrew switch else perlbrew use $argv[2] if test "$status" -eq 0 __perlbrew_reinit $argv[2] end end case off __perlbrew_deactivate echo "perlbrew is turned off." case switch-off __perlbrew_deactivate __perlbrew_reinit echo "perlbrew is switched off." case '*' command perlbrew $argv end end function __source_init perl -pe 's/^(export|setenv)/set -xg/; s/^unset(env)* (.*)/if test -n "\$$2"; set -eg $2; end/; s/=/ /; s/$/;/;' "$PERLBREW_HOME/init" | source end if test -z "$PERLBREW_ROOT" set -x PERLBREW_ROOT "$HOME/perl5/perlbrew" end if test -z "$PERLBREW_HOME" set -x PERLBREW_HOME "$HOME/.perlbrew" end if test -z "$PERLBREW_SKIP_INIT" -a -f "$PERLBREW_HOME/init" __source_init end set perlbrew_bin_path "$PERLBREW_ROOT/bin" if test -f "$perlbrew_bin_path/perlbrew" set perlbrew_command "$perlbrew_bin_path/perlbrew" else set perlbrew_command perlbrew end set -e perlbrew_bin_path __perlbrew_activate ## autocomplete stuff ############################################# function __fish_perlbrew_needs_command set cmd (commandline -opc) if test (count $cmd) -eq 1 -a $cmd[1] = 'perlbrew' return 0 end return 1 end function __fish_perlbrew_using_command set cmd (commandline -opc) if test (count $cmd) -gt 1 if [ $argv[1] = $cmd[2] ] return 0 end end end for com in (perlbrew help | perl -ne'print lc if s/^COMMAND:\s+//') complete -f -c perlbrew -n '__fish_perlbrew_needs_command' -a $com end for com in switch use; complete -f -c perlbrew -n "__fish_perlbrew_using_command $com" \ -a '(perlbrew list | perl -pe\'s/\*?\s*(\S+).*/$1/\')' end END } sub CSH_WRAPPER_CONTENT { return <<'WRAPPER'; set perlbrew_exit_status=0 if ( "$1" =~ -* ) then set perlbrew_short_option="$1" shift else set perlbrew_short_option="" endif switch ( "$1" ) case use: if ( $%2 == 0 ) then if ( $?PERLBREW_PERL == 0 ) then echo "Currently using system perl" else if ( $%PERLBREW_PERL == 0 ) then echo "Currently using system perl" else echo "Currently using $PERLBREW_PERL" endif endif else set perlbrew_line_count=0 foreach perlbrew_line ( "`\perlbrew env $2:q`" ) eval "$perlbrew_line" @ perlbrew_line_count++ end if ( $perlbrew_line_count == 0 ) then set perlbrew_exit_status=1 else source "$PERLBREW_ROOT/etc/csh_set_path" endif endif breaksw case switch: if ( $%2 == 0 ) then \perlbrew switch else perlbrew use "$2" && source "$PERLBREW_ROOT/etc/csh_reinit" "$2" endif breaksw case off: unsetenv PERLBREW_PERL foreach perlbrew_line ( "`\perlbrew env`" ) eval "$perlbrew_line" end source "$PERLBREW_ROOT/etc/csh_set_path" echo "perlbrew is turned off." breaksw case switch-off: unsetenv PERLBREW_PERL source "$PERLBREW_ROOT/etc/csh_reinit" '' echo "perlbrew is switched off." breaksw default: \perlbrew $perlbrew_short_option:q $argv:q set perlbrew_exit_status=$? breaksw endsw rehash exit $perlbrew_exit_status WRAPPER } sub CSH_REINIT_CONTENT { return <<'REINIT'; if ( ! -d "$PERLBREW_HOME" ) then mkdir -p "$PERLBREW_HOME" endif echo '# DO NOT EDIT THIS FILE' >! "$PERLBREW_HOME/init" \perlbrew env $1 >> "$PERLBREW_HOME/init" source "$PERLBREW_HOME/init" source "$PERLBREW_ROOT/etc/csh_set_path" REINIT } sub CSH_SET_PATH_CONTENT { return <<'SETPATH'; unalias perl if ( $?PERLBREW_PATH == 0 ) then setenv PERLBREW_PATH "$PERLBREW_ROOT/bin" endif setenv PATH_WITHOUT_PERLBREW `perl -e 'print join ":", grep { index($_, $ENV{PERLBREW_ROOT}) } split/:/,$ENV{PATH};'` setenv PATH "${PERLBREW_PATH}:${PATH_WITHOUT_PERLBREW}" setenv MANPATH_WITHOUT_PERLBREW `perl -e 'print join ":", grep { index($_, $ENV{PERLBREW_ROOT}) } split/:/,qx(manpath 2> /dev/null);'` if ( $?PERLBREW_MANPATH == 1 ) then setenv MANPATH "${PERLBREW_MANPATH}:${MANPATH_WITHOUT_PERLBREW}" else setenv MANPATH "${MANPATH_WITHOUT_PERLBREW}" endif SETPATH } sub CSHRC_CONTENT { return "setenv PERLBREW_SHELLRC_VERSION $VERSION\n\n" . <<'CSHRC'; if ( $?PERLBREW_HOME == 0 ) then setenv PERLBREW_HOME "$HOME/.perlbrew" endif if ( $?PERLBREW_ROOT == 0 ) then setenv PERLBREW_ROOT "$HOME/perl5/perlbrew" endif if ( $?PERLBREW_SKIP_INIT == 0 ) then if ( -f "$PERLBREW_HOME/init" ) then source "$PERLBREW_HOME/init" endif endif if ( $?PERLBREW_PATH == 0 ) then setenv PERLBREW_PATH "$PERLBREW_ROOT/bin" endif source "$PERLBREW_ROOT/etc/csh_set_path" alias perlbrew 'source "$PERLBREW_ROOT/etc/csh_wrapper"' CSHRC } sub append_log { my ( $self, $message ) = @_; my $log_handler; open( $log_handler, '>>', $self->{log_file} ) or die "Cannot open log file for appending: $!"; print $log_handler "$message\n"; close($log_handler); } sub INSTALLATION_FAILURE_MESSAGE { my ($self) = @_; return <{log_file} If some perl tests failed and you still want to install this distribution anyway, do: (cd $self->{dist_extracted_dir}; make install) You might also want to try upgrading patchperl before trying again: perlbrew install-patchperl Generally, if you need to install a perl distribution known to have minor test failures, do one of these commands to avoid seeing this message: perlbrew --notest install $self->{dist_name} perlbrew --force install $self->{dist_name} FAIL } 1; __END__ =encoding utf8 =head1 NAME App::perlbrew - Manage perl installations in your C<$HOME> =head1 SYNOPSIS # Installation curl -L https://install.perlbrew.pl | bash # Initialize perlbrew init # See what is available perlbrew available # Install some Perls perlbrew install 5.32.1 perlbrew install perl-5.28.3 perlbrew install perl-5.33.6 # See what were installed perlbrew list # Swith to an installation and set it as default perlbrew switch perl-5.32.1 # Temporarily use another version only in current shell. perlbrew use perl-5.28.3 perl -v # Turn it off and go back to the system perl. perlbrew off # Turn it back on with 'switch', or 'use' perlbrew switch perl-5.32.1 perlbrew use perl-5.32.1 # Exec something with all perlbrew-ed perls perlbrew exec -- perl -E 'say $]' =head1 DESCRIPTION L is a program to automate the building and installation of perl in an easy way. It provides multiple isolated perl environments, and a mechanism for you to switch between them. Everything are installed unter C<~/perl5/perlbrew>. You then need to include a bashrc/cshrc provided by perlbrew to tweak the PATH for you. You then can benefit from not having to run C commands to install cpan modules because those are installed inside your C too. For the documentation of perlbrew usage see L command on L, or by running C, or by visiting L. The following documentation features the API of C module, and may not be remotely close to what your want to read. =head1 INSTALLATION It is the simplest to use the perlbrew installer, just paste this statement to your terminal: curl -L https://install.perlbrew.pl | bash Or this one, if you have C (default on FreeBSD): fetch -o- https://install.perlbrew.pl | sh After that, C installs itself to C<~/perl5/perlbrew/bin>, and you should follow the instruction on screen to modify your shell rc file to put it in your PATH. The installed perlbrew command is a standalone executable that can be run with system perl. The minimum required version of system perl is 5.8.0, which should be good enough for most of the OSes these days. A fat-packed version of L is also installed to C<~/perl5/perlbrew/bin>, which is required to build old perls. The directory C<~/perl5/perlbrew> will contain all install perl executables, libraries, documentations, lib, site_libs. In the documentation, that directory is referred as C. If you need to set it to somewhere else because, say, your C has limited quota, you can do that by setting C environment variable before running the installer: export PERLBREW_ROOT=/opt/perl5 curl -L https://install.perlbrew.pl | bash As a result, different users on the same machine can all share the same perlbrew root directory (although only original user that made the installation would have the permission to perform perl installations.) You may also install perlbrew from CPAN: cpan App::perlbrew In this case, the perlbrew command is installed as C or C or others, depending on the location of your system perl installation. Please make sure not to run this with one of the perls brewed with perlbrew. It's the best to turn perlbrew off before you run that, if you're upgrading. perlbrew off cpan App::perlbrew You should always use system cpan (like /usr/bin/cpan) to install C because it will be installed under a system PATH like C, which is not affected by perlbrew C or C command. The C command will not upgrade the perlbrew installed by cpan command, but it is also easy to upgrade perlbrew by running C again. =head1 PROJECT DEVELOPMENT L uses github L for issue tracking. Issues sent to these two systems will eventually be reviewed and handled. To participate, you need a github account. Please briefly read the short instructions about how to get your work released to CPAN: L =head1 AUTHOR Kang-min Liu C<< >> =head1 COPYRIGHT Copyright (c) 2023 Kang-min Liu C<< >>. =head1 LICENCE The MIT License =head1 DISCLAIMER OF WARRANTY BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. =cut command-install.t000644001750001750 520114465441602 17205 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec 0.49; # with_deep use Test::Deep; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; sub arrange_available_perls; sub arrange_command_line; sub expect_dispatch_via; describe "command install" => sub { it "should install exact perl version" => sub { arrange_command_line install => 'perl-5.12.1'; expect_dispatch_via do_install_release => [ 'perl-5.12.1', '5.12.1' ]; }; it "should install exact cperl version" => sub { arrange_command_line install => 'cperl-5.26.4'; expect_dispatch_via do_install_release => [ 'cperl-5.26.4', '5.26.4' ]; }; it "should install stable version of perl" => sub { arrange_command_line install => 'perl-stable'; arrange_available_perls qw[ perl-5.12.2 perl-5.12.3 perl-5.14.1 perl-5.14.2 perl-5.29.0 ]; expect_dispatch_via do_install_release => [ 'perl-5.14.2', '5.14.2' ]; }; it "should install blead perl" => sub { arrange_command_line install => 'perl-blead'; expect_dispatch_via do_install_blead => []; }; it "should install git checkout" => sub { my $checkout = tempdir (CLEANUP => 1); dir ($checkout, '.git')->mkpath; arrange_command_line install => $checkout; expect_dispatch_via do_install_git => [ $checkout ]; }; it "should install from archive" => sub { my $checkout = tempdir (CLEANUP => 1); my $file = file ($checkout, 'archive.tar.gz')->stringify; open my $fh, '>', $file; close $fh; arrange_command_line install => $file; expect_dispatch_via do_install_archive => [ all ( obj_isa ('App::Perlbrew::Path'), methods (stringify => $file), ) ]; }; it "should install from uri" => sub { arrange_command_line install => 'http://example.com/foo/bar'; expect_dispatch_via do_install_url => [ 'http://example.com/foo/bar' ]; }; }; runtests unless caller; sub arrange_available_perls { my (@list) = @_; App::perlbrew->stubs (available_perls => sub { $_[0]->sort_perl_versions (@list) }); } sub arrange_command_line { my (@command_line) = @_; share my %shared; $shared{app} = App::perlbrew->new (@command_line); } sub expect_dispatch_via { my ($method, $arguments) = @_; share my %shared; my $expectation = App::perlbrew->expects ($method); $expectation = $expectation->with_deep (@$arguments) if $arguments; $shared{app}->run; ok $expectation->verify; } home.t000644001750001750 350714465441602 15062 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Deep qw[]; use Test::Spec; sub looks_like_perlbrew_home; local $App::perlbrew::PERLBREW_HOME = '/perlbrew/home'; local $ENV{PERLBREW_HOME} = '/env/home'; local $ENV{HOME} = '/home'; describe "App::perlbrew#home method" => sub { it "should return \$App::perlbrew::PERLBREW_HOME if provided" => sub { my $app = App::perlbrew->new; looks_like_perlbrew_home $app->home, '/perlbrew/home'; }; it "should default to \$ENV{PERLBREW_HOME} if provided" => sub { local $App::perlbrew::PERLBREW_HOME; my $app = App::perlbrew->new; looks_like_perlbrew_home $app->home, '/env/home'; }; it "should default to \$ENV{HOME} subpath" => sub { local $App::perlbrew::PERLBREW_HOME; local $ENV{PERLBREW_HOME}; my $app = App::perlbrew->new; looks_like_perlbrew_home $app->home, '/home/.perlbrew'; }; it "should return the instance property of 'home' if set" => sub { my $app = App::perlbrew->new; $app->home("/fnord"); looks_like_perlbrew_home $app->home, "/fnord"; }; }; runtests unless caller; sub looks_like_perlbrew_home { my ($got, $expected) = @_; my ($ok, $stack); ($ok, $stack) = Test::Deep::cmp_details "$got", "$expected"; unless ($ok) { fail; diag "Return value comparison failed"; diag Test::Deep::deep_diag $stack; return; } ($ok, $stack) = Test::Deep::cmp_details "$got", "$App::perlbrew::PERLBREW_HOME"; unless ($ok) { fail; diag "Global \$PERLBREW_HOME comparison failed"; diag Test::Deep::deep_diag $stack; return; } return Test::Deep::cmp_deeply $got, Isa('App::Perlbrew::Path'); } 09.exit_status.t000644001750001750 110214465441602 16722 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use FindBin; use lib $FindBin::Bin; use App::perlbrew; require 'test_helpers.pl'; use Test::More; use Test::Exception; use Path::Class; my $bin_perlbrew = file(__FILE__)->dirname->dirname->child("script")->child("perlbrew"); throws_ok( sub { my $app = App::perlbrew->new("unknown-command"); $app->run; }, qr[unknown-command] ); my $perl = $^X; system("$perl -Ilib ${bin_perlbrew} unknown-command 2>&1"); ok($? != 0); system("$perl -Ilib ${bin_perlbrew} version 2>&1"); ok($? == 0); done_testing; .perltidyrc000644001750001750 24414465441602 15637 0ustar00gugodgugod000000000000App-perlbrew-0.98--maximum-line-length=120 --indent-columns=4 --continuation-indentation=4 --square-bracket-tightness=2 --tight-secret-operators --maximum-consecutive-blank-lines=1 http.t000644001750001750 342214465441602 15105 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use Test::Spec; use App::perlbrew; use File::Temp 'tempdir'; use IO::All; use App::Perlbrew::HTTP qw(http_user_agent_program http_get http_download); unless ($ENV{PERLBREW_DEV_TEST}) { plan skip_all => < sub { my ($output); before all => sub { http_get( "https://get.perlbrew.pl", undef, sub { $output = $_[0]; } ); }; it "calls the callback to assign content to \$output", sub { ok defined($output) && length($output) > 0; }; it "seems to download the correct content", sub { ok $output =~ m<\A #!/usr/bin/perl\n >x; ok $output =~ m< \$fatpacked\{"App/perlbrew.pm"\} >x; }; }; describe "http_download function, downloading the perlbrew-installer." => sub { my ($dir, $output, $download_error); before all => sub { $dir = tempdir( CLEANUP => 1 ); $output = "$dir/perlbrew-installer"; if (-f $output) { plan skip_all => < sub { ok(-f $output); }; it "seems to be downloading the right content" => sub { is(scalar(io($output)->getline), "#!/bin/sh\n"); }; }; runtests unless caller; command-clone-modules.t000644001750001750 531614465441602 20314 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; BEGIN { $ENV{SHELL} = "/bin/bash" } use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_install("perl-5.16.0"); no warnings; my ($__from, $__to, $__notest); sub App::perlbrew::list_modules { my ($self, $env) = @_; $__from = $env || $self->current_env; return ["Foo", "Bar"]; } sub App::perlbrew::run_command_exec { my ($self, @args) = @_; if (grep { $_ eq 'cpanm' } @args) { $__to = $args[1]; ($__notest) = grep { $_ eq '--notest' } @{$self->{original_argv}}; } return $self; } use warnings; describe "clone-modules command," => sub { before each => sub { delete $ENV{PERL_MB_OPT}; delete $ENV{PERL_MM_OPT}; delete $ENV{PERL_LOCAL_LIB_ROOT}; delete $ENV{PERLBREW_LIB}; delete $ENV{PERL5LIB}; $__from = undef; $__to = undef; $__notest = undef; }; describe "when invoked with two arguments, A and B", sub { it "should display clone modules from A to B", sub { my $app = App::perlbrew->new( "clone-modules", "perl-5.14.1", "perl-5.16.0" ); $app->run; is $__from, "perl-5.14.1"; is $__to, "perl-5.16.0"; ok(!defined($__notest)); }; }; describe "when invoked with two arguments, A and B, with `--notest`", sub { it "should display clone modules from A to B", sub { my $app = App::perlbrew->new( "clone-modules", "--notest", "perl-5.14.1", "perl-5.16.0" ); $app->run; is $__from, "perl-5.14.1"; is $__to, "perl-5.16.0"; ok(defined($__notest)); }; }; describe "when invoked with one argument X", sub { it "should display clone modules from current-perl to X", sub { my $app = App::perlbrew->new("clone-modules", "perl-5.14.1"); $app->expects("current_env")->returns("perl-5.16.0")->at_least(1); $app->run; is $__from, "perl-5.16.0"; is $__to, "perl-5.14.1"; ok(!defined($__notest)); }; }; describe "when invoked with one argument X, with `--notest`", sub { it "should display clone modules from current-perl to X", sub { my $app = App::perlbrew->new("clone-modules", "--notest", "perl-5.14.1"); $app->expects("current_env")->returns("perl-5.16.0")->at_least(1); $app->run; is $__from, "perl-5.16.0"; is $__to, "perl-5.14.1"; ok(defined($__notest)); }; }; }; runtests unless caller; failure-command-install-cpm.t000644001750001750 204514465441602 21412 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use Test::Spec; use File::Temp qw( tempdir ); use App::perlbrew; $App::perlbrew::PERLBREW_ROOT = my $perlbrew_root = tempdir( CLEANUP => 1 ); $App::perlbrew::PERLBREW_HOME = my $perlbrew_home = tempdir( CLEANUP => 1 ); { no warnings 'redefine'; sub App::perlbrew::http_get { my ($url) = @_; like $url, qr/cpm$/, "GET cpm url: $url"; return "404 not found."; } } describe "App::perlbrew->install_cpm" => sub { it "should no produced 'cpm' in the bin dir, if the downloaded content seems to be invalid." => sub { my $error; my $error_produced = 0; eval { my $app = App::perlbrew->new("install-cpm", "-q"); $app->run(); } or do { $error = $@; $error_produced = 1; }; my $cpm = App::Perlbrew::Path->new($perlbrew_root, "bin", "cpm"); ok $error_produced, "generated an error: $error"; ok !(-f $cpm), "cpm is not produced. $cpm"; }; }; runtests unless caller; command-alias.t000644001750001750 207214465441602 16633 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl #!/usr/bin/env perl use strict; use warnings; BEGIN { $ENV{SHELL} = "/bin/bash" } use FindBin; use lib $FindBin::Bin; use App::perlbrew; require "test_helpers.pl"; use Test::Spec; use Test::Output; use Config; mock_perlbrew_install("perl-5.14.1"); mock_perlbrew_lib_create('perl-5.14.1@nobita'); describe "alias command," => sub { before each => sub { delete $ENV{PERL_MB_OPT}; delete $ENV{PERL_MM_OPT}; delete $ENV{PERL_LOCAL_LIB_ROOT}; delete $ENV{PERLBREW_LIB}; delete $ENV{PERL5LIB}; }; describe "when invoked with unknown action name,", sub { it "should display usage message" => sub { my $x = "correcthorsebatterystaple"; my $app = App::perlbrew->new("alias", $x); stderr_like { eval { $app->run; 1; } or do { print STDERR $@; }; } qr/ERROR: Unrecognized action: `$x`/; } }; }; runtests unless caller; META.json000644001750001750 521414465441602 15120 0ustar00gugodgugod000000000000App-perlbrew-0.98{ "abstract" : "Manage perl installations in your C<$HOME>", "author" : [ "Kang-min Liu C<< >>" ], "dynamic_config" : 0, "generated_by" : "App::ModuleBuildTiny version 0.041", "license" : [ "mit" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "App-perlbrew", "prereqs" : { "configure" : { "requires" : { "Module::Build::Tiny" : "0.039" } }, "develop" : { "requires" : { "App::ModuleBuildTiny" : "0.041", "Pod::Markdown" : "2.002" } }, "runtime" : { "requires" : { "CPAN::Perl::Releases" : "5.20230720", "Capture::Tiny" : "0.48", "Devel::PatchPerl" : "2.08", "ExtUtils::MakeMaker" : "7.22", "File::Copy" : "0", "File::Temp" : "0.2304", "JSON::PP" : "0", "Pod::Usage" : "1.69", "local::lib" : "2.000014" } }, "test" : { "requires" : { "File::Which" : "1.21", "IO::All" : "0.51", "Path::Class" : "0.33", "Test::Exception" : "0.32", "Test::More" : "1.001002", "Test::NoWarnings" : "1.04", "Test::Output" : "1.03", "Test::Simple" : "1.001002", "Test::Spec" : "0.49", "Test::TempDir::Tiny" : "0.016" } } }, "provides" : { "App::Perlbrew::HTTP" : { "file" : "lib/App/Perlbrew/HTTP.pm" }, "App::Perlbrew::Path" : { "file" : "lib/App/Perlbrew/Path.pm" }, "App::Perlbrew::Path::Installation" : { "file" : "lib/App/Perlbrew/Path/Installation.pm" }, "App::Perlbrew::Path::Installations" : { "file" : "lib/App/Perlbrew/Path/Installations.pm" }, "App::Perlbrew::Path::Root" : { "file" : "lib/App/Perlbrew/Path/Root.pm" }, "App::Perlbrew::Util" : { "file" : "lib/App/Perlbrew/Util.pm" }, "App::perlbrew" : { "file" : "lib/App/perlbrew.pm", "version" : "0.98" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/gugod/App-perlbrew/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/gugod/App-perlbrew.git", "web" : "https://github.com/gugod/App-perlbrew" } }, "version" : "0.98", "x_serialization_backend" : "JSON::PP version 4.16", "x_spdx_expression" : "MIT", "x_static_install" : "1" } 08.error_available.t000644001750001750 70114465441602 17462 0ustar00gugodgugod000000000000App-perlbrew-0.98/t#!/usr/bin/env perl use strict; use warnings; use App::perlbrew; use Test::More; use Test::Exception; no warnings 'redefine'; sub App::perlbrew::http_get { "" } throws_ok( sub { my $app = App::perlbrew->new("available"); $app->run; }, qr[ERROR:] ); throws_ok( sub { my $app = App::perlbrew->new("available"); my $ret = $app->available_perl_distributions(); }, qr[ERROR:] ); done_testing;