8

Within my Dockerfile, I am setting up the Perl modules that will be installed when run, like so:

RUN ["cpanm", "Carp", "Carp::Heavy", "Class::Data::Inheritable"]

However, for one module, I need a specific version of a module, not the latest one. How can I specify that version in the above line?

I've been searching online for hours, and haven't turned up anything useful yet.

Mik
  • 443
  • 4
  • 9

4 Answers4

7

Instead of specifying a module name, specify a URL. Eg, instead of Class::Data::Inheritable, use https://cpan.metacpan.org/authors/id/T/TM/TMTM/Class-Data-Inheritable-0.06.tar.gz

You can find the applicable URL by going to the module page on metacpan, selecting the version you want, and copying the download link.

PS: You might want to also set PERL_CPANM_OPT=--from https://cpan.metacpan.org/ in the environment so cpanm only downloads using HTTPS.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
7

For anyone who's searching for this same answer in the future, another option can be found here in the documentation for cpanm:

cpanm Plack@0.9990

If you have a long list of modules, consider feeding a cpanfile into cpanm rather than listing them all in the Dockerfile.

The easiest way to specify a particular version number for a module in a cpanfile is like this:

requires 'Text::ParseWords', '==3.1';

The syntax for requesting the latest version of a module is this:

requires 'Text::ParseWords';

Requesting a minimum version: (note the lack of '==')

requires 'Text::ParseWords', '3.1';

The syntax for requesting specific versions in other ways is fairly well-documented here.

Another great write-up of the use of cpanm and a cpanfile can be found in Installation of cpan modules by cpanm and cpanfile.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Mik
  • 443
  • 4
  • 9
  • 1
    Excellent summary (I am going to tidy up the formatting a little later). However, note that, in production, I like to know exactly where everything is coming from. For that purpose, you may want to keep your own repository of specific instances of CPAN dist files. See also [CPAN::Mini](https://metacpan.org/pod/CPAN::Mini) and [Pinto](https://metacpan.org/pod/Pinto). – Sinan Ünür Jul 27 '16 at 22:39
  • 1
    Thanks. I looked into Pinto and decided that it would be overkill, since I'm just using this to spin up Docker containers. [Carton](https://metacpan.org/release/carton) is another tool to consider, though it also uses the cpanfile, and I'm having trouble digging up working syntax to include a url instead of a version number in the cpanfile. – Mik Jul 27 '16 at 22:55
  • 1
    I don't think there is syntax for including modules by URL in a cpanfile. However, you can probably achieve the same effect by setting the mirror in the environment, and specifying an exact version. – Sinan Ünür Jul 28 '16 at 00:39
  • I did find this **one** blog post with syntax for including a git url. Sadly, the line is cut off. I've made a couple of guesses, but so far cpanm keeps trying to translate the url into a version number: http://blogs.perl.org/users/lestrrat/2013/03/the-main-problem-with-cpan-modules-on-github.html – Mik Jul 28 '16 at 15:43
  • Looking at the source of the web page, it seems to be `requires 'My::Experimental::Module" => "git://github.com/lestrrat/p5-MyExperimental-Module.git";` – Sinan Ünür Jul 28 '16 at 18:07
  • 1
    LOL, can't believe I didn't think to look at the source. I guess that's what happens when you stare at the same problem for too long. However, that is one of the syntax variations that I tried, and cpanm interpreted it as a version number, regardless of the "=>" between. I left a comment on the blog post requesting clarification regarding the syntax, so hopefully the blogger can provide some missing context or clarification. Thanks for all the effort you've put into this; it's been extremely helpful. – Mik Jul 29 '16 at 14:40
  • 1
    The reason I had not originally suggested something like that was because I looked at the source of the cpanfile module to see if requirements options checked for URLs and I could not find a check, I assumed it did not exist. The blog post made me think I had missed something. I should have tried. Thank you for the update. – Sinan Ünür Jul 29 '16 at 16:06
4

To have CPAN install a specific version of a module, you need to provide the full module distribution filename including the author. For example to install the module Set::Object version 1.28, at the command line type:

cpan SAMV/Set-Object-1.28.tar.gz

Same thing apply with Docker, just add

RUN cpan SAMV/Set-Object-1.28.tar.gz
Camilo Silva
  • 8,283
  • 4
  • 41
  • 61
0

To specify target module version you can use

cpanm MIYAGAWA/Plack-0.99_05.tar.gz              # full distribution path
cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz  # install from URL
cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz   # install from a local file

See official documentation: https://metacpan.org/dist/App-cpanminus/view/bin/cpanm

But better, to my mind, would be to use cpanfile. See --cpanfile option https://metacpan.org/dist/App-cpanminus/view/bin/cpanm#-cpanfile and format of this file https://metacpan.org/pod/cpanfile

But if you have many modules (like me), I recommend to use cpm. It installs modules in parallel very fast. Also with help of docker we could cache builds, thus rebuilds will takes seconds. Here is my Dockerfile:

## Modules
WORKDIR ${APP_ROOT}

# install modules outside of WORKDIR, so it will not interfere when we do COPY . .
RUN  mkdir -p ../modules
RUN  ln -s ../modules local

RUN  cpanm -n -L ./local App::cpm Carton::Snapshot  && rm -rf /root/.cpanm
COPY cpanfile ./
COPY cpanfile.snapshot ./
RUN  \
  --mount=type=cache,target=/root/.perl-cpm   \
  cpm install  -w 16  --no-test  -L ./local   \
  --with-develop


# regenerate cpanfile.snapshot
# https://github.com/miyagawa/Carmel#cpm
# cpm doesn't have the ability to manage cpanfile.snapshot file on its own.
RUN  carton install
# You can copy snapshot from container by running:
# docker cp <container_name>:${APP_ROOT}/cpanfile.snapshot.latest ./cpanfile.snapshot
Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158