8

I am using perlbrew. I have installed lots of cpan modules under perlbrew perl-5.20.2.

Is there a way (or what is the best way) to do a tarball installation of my perl-5.20.2 plus all the CPAN modules that I have installed under perlbrew so that I can just clone it unto another machine?

I am aware of perlbrew download perl-5.20.2 but that only seems to tarball perl-5.20.2 and not all the CPAN modules that I have installed.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Hamster
  • 680
  • 7
  • 23
  • 2
    You could take the approach described in [How To Reinstall All Modules On New Perl](http://perlbrew.pl/Reinstall-All-Modules-On-New-Perl.html), but write the output of `perlbrew list-modules` to a file, copy the file to the other machine, and use it as the input for `perlbrew exec`. However, this would require downloading the entire set of modules twice, and you would get the latest version of everything, so you might have version mismatches between your two installations. – ThisSuitIsBlackNot Mar 12 '15 at 16:07
  • 1
    @ThisSuitIsBlackNot ++ With `cpanm` you can use versions - as in `cpanm Plack@0.9990`, but there's no option to get a current version list with `'perlbrew list-modules`. One way to get a pretty good list of current versions of modules installed under - say - `~/perl5/` is to look for any `install.json` files and process those. *e.g.* `find ~/perl5/ -name install.json -exec jq -M '.name + "@" + .version' {} +`. This assumes `install.json` exists. Tweaking the output format that so `perlbrew exec cpanm` likes it would probably be needed – G. Cito Mar 12 '15 at 17:25

4 Answers4

5

With perlbrew you can use the lib command to create a local::lib to go with your perlbrew perl.

perlbrew lib create perl-5.20.2@app_reqs

Then, if all goes well, when you install modules you will find them in:

$HOME/.perlbrew/libs/perl-5.20.2@app_reqs

If you don't use the perbrew lib create approach to managing your modules, then they are installed to $HOME/perl5/perlbrew/perls/perl-5.20.1/lib/site_perl/5.20.2. Cloning either of those directories might work, but you are likely better off reinstalling all the modules using the techniques from the perlbrew.pl website since XS modules should be rebuilt etc.

If you want to reuse and track local sources the most reliable approach is to create a local CPAN mirror to work from using App::lcpan or minicpan. If you have already downloaded the source using cpanm a quick hackish approach is to find the source files (under $HOME/.cpanm/) and do something like this in your shell:

% mkdir  ~/cpansourcefiles  
% for source in ~/.cpanm/work/*/* ; do cp $source ~/cpansourcefiles ;done

Then you can get cpanm to install using those sources by passing the filename as the argument instead of the module name:

% cpanm ~/cpansourcefiles/List-MoreUtils-0.406.tar.gz

or even:

% cpanm ~/cpansourcefiles/*  

NB: YMMV since this is prone to breakage and might skip some of the version and dependency checking you normally get with cpanm but it is simpler than setting up a mirror when it works.


A few other high powered tools that make deploying Perl applications robust and reliable:


EDIT:

Tools like perlbrew, pinto, carton, and cpanm are a vast improvement over a motley personal collection of scripts for doing similar things. Thanks to all the developers and contributors to these tools!

I'm not aware of any features in cpanm or perlbrew that allow you to reliably produce a list of installed files and their versions. Something like:

 cpanm --list_installed
 perlbrew list_installed_versions

or:

 cpanm --export-cpanfile
 perlbrew list_installed_as_cpanfile

might be a welcome feature.

As I noted in a comment to the OP above, you can garner useful information about your module installation from the install.json files that are installed by cpanm. Modules like CPAN::Meta, Module::Metadata and Distribution::Metadata can be helpful too.

The suggestion to use find and jq (which was from @Ilmari Karonen see Upgrade all modules installed by local::lib in this answer) led to the quick unfinished hack below. One challenge/issue is there's sometimes install.json files left lying around in multiple locations:

  • lib/perl5/$Config{archname}/.meta/Whatever-Mod-1.0050000/install.json
  • lib/perl5/$Config{archname}/.meta/Whatever-Mod-1.0090000/install.json
  • ... etc.

This is likely because these files are not always cleanly removed when upgrading, reinstalling or other mucking about PEBKAC errors. To work properly, the code below should be changed so that it notices when there are multiple name-version combinations of a module's install.json and then does a more thorough check that the module is installed and gets its version. The script should have options: $dir could come from @ARGV. TIMTOWTDI, "well volunteered", etc.

#!perl  
# list_installed_mods.pl 
# DOES NOT THOROUGHLY VERIFY CURRENT VERSION

use File::Find;                                       
use JSON;                                       
use v5.16;     
my $dir = "$ENV{HOME}/perl5/lib/perl5";      

for my $installed ( find_installed($dir) ) {     
  say parse_install_json( $installed );     
} 

sub find_installed {  
  my $libdir = shift;    
  my @files;   
  File::Find::find ({ wanted => 
    sub { push @files, $File::Find::name if /install\.json/i} },
    $libdir );
  return @files; 
} 

sub parse_install_json {
  my $filename = shift;
  my $json_text = do {   
   open(my $json_fh, "<:encoding(UTF-8)", $filename)                
      or die("Can't open \$filename\": $!\n");                          
   local $/;
   <$json_fh>                                                           
  }; 
  my $install = decode_json($json_text) ;   
  return ( $install->{name} ,"\@", $install->{version} ) ;
} 
Community
  • 1
  • 1
G. Cito
  • 6,210
  • 3
  • 29
  • 42
1

Possibly not the best way, but here's what I did recently.

I committed my Perlbrewed Perl version to a git repo, so I could use git archive to create a tar for me. Likewise with my Local::Lib modules. Then I wrote a little bit of scripting so that I could tag master, build archives from a tag, copy the archive to the remote server, unpack and chmod/chown the files.

I did this because at the time it was a quick and dirty solution to not having the time to set up Pinto or Carton.

Len Jaffe
  • 3,442
  • 1
  • 21
  • 28
  • ++ I can't see how this wouldn't work when you have perl only modules (no XS) and a simple installation. My approach (see my answer) - which was to copy source files from `~/cpanm` and install them directly to avoid downloading - felt similarly hackish but worked for a `local::lib` perlbrew installation that had only a few dozen modules installed. I used `perlbrew` to build perl itself (the same version of course) from source. – G. Cito Mar 12 '15 at 17:36
  • 1
    I used perlbrew to insall everything I needed, locallized under a perlbrew directory, including XS and pure perl modules. perlbrew keeps each version of perl compartmentalized, so I could just tar up a git tag starting at a version's root directory. A few lines of script to set the correct perlbrew env vars on the target server, and it all worked. Woudl I have liked a solution using the evolving standards? Yes. But is wasn't in the cards for that project. – Len Jaffe Mar 12 '15 at 21:46
1

It's only part of the solution but want mentioned so far: Perl's configure script has a -D relocateableinc parameter since some versions. When building/brewing a Perl with that option the lib paths won't be hardcoded absolute path but relative to the perl binary which allows you to move the entire directory around or just rename it. I'm building all my Perl's with that option since years and it hasn't created any problems so far.

Alexander Hartmaier
  • 2,178
  • 12
  • 21
0

The clone-modules command might be what you're seeking.

Example output for the below command follows:

perlbrew clone-modules perl-5.36.0 perl-5.37.6

Installing 398 modules from perl-5.36.0 to perl-5.37.6 ...

! Couldn't find module or a distribution AWS-Signature4
Successfully installed Algorithm-Diff-1.201
Successfully installed Algorithm-Loops-1.032
Successfully installed Module-Build-0.4231
Successfully installed ExtUtils-PkgConfig-1.16
Successfully installed Alien-VideoLAN-LibVLC-0.04
Successfully installed File-Slurp-9999.32

You can run this command after building a new perl with perlbrew to migrate (the latest versions of) CPAN modules from one version to another by reinstalling them for the new version that was just built.

Elvin
  • 166
  • 7