Why I use cpanfile (and you should too)

CPANfile is a simple way to declare your project's dependencies in a build system independent manner.

  1. In recent versions of cpanminus, it makes your entire project installable from a git repository, and,
  2. it also allows you to "pin" your dependencies on a specific CPAN release in a very sophisticated way, rather than "this version or newer" which is the typical Perl dependency resolution.

Why would you want to install a project from git instead of the normal CPAN download/build/test/install process? There are a lot of use cases, but the one I care about most is experimentation, followed fairly closely by patching. Finally, there are pieces of projects which are too trivial to go through the whole "PAUSE packaging/upload" process.

The git representation of a Perl module may be weeks or months ahead of its most recent CPAN release. Also some developers maintain branches of the project which add (or remove) features not available in the CPAN release.

Using CPANfile makes using such code much easier to download and install correctly. If you haven't started using it already, please consider adding CPANfile to your normal development activities, especially if you host your code on a service like Git Hub.

Read more here. I'd also be happy to answer any questions in the comments here, sent from twitter or by email.

10 Comments

Why should anyone use a 4th format to define dependencies?

The official way is to mark them in your Makefile.PL or Build.PL, or even dist.ini,
which creates the 2 static files META.json and META.yml automatically.

So the 3 formats are the
1. the dynamic ones you maintain,
and the 2 static ones, which are kept uptodate automatically.

cpanfile is only supported by cpanm and carton, and miyagawa should really talk to the CPAN toolchain maintainers to add the features he misses.

I only see requires and recommends for the steps configure, build, test and install, which are all supported already.
New are lt version and conflicts, which can be easily added to the existing meta format.

So I see no need for yet another meta format to maintain, which looks like a ruby gemfile or rpm spec.

Balcanization.

CPAN::Meta::Spec already supports fairly specific version ranges such as "Foo::Bar" => ">= 1.2, != 1.5, < 2.0" which means "any version of Foo::Bar greater than or equal to 1.2, but below 2.0, and not 1.5 (presumably because there was a bug in that release)".

The tool support isn't there yet, but it will be one day (hopefully). I think the main difficulty at the moment is the PAUSE indexer, which only keeps the latest version number in its index. The MetaCPAN API might provide a way forward.

Another option within a corporate environment is to create a minicpan and only stock it with the versions you have internaly vetted (possibly with a QA process).

Of course, upgrading this becomes an exercise in frustration because I cannot say "Give me the next version from X.YZ". I also cannot say "Starting from Foo::Bar, upgrade everything necessary to the minimal possible version, then run the test suite, and keep upgrading each one until the suite breaks or we're at the latest version."

Something like CPANTS, but with my test suite as the driving force.

Reini:

> The official way is to mark them in your Makefile.PL or Build.PL, or even dist.ini,
> which creates the 2 static files META.json and META.yml automatically.

Official way for CPAN modules, yes.That's why I created Module::Install::CPANfile and Dist::Zilla::Prereqs::FromCPANfile, which automatically converts cpanfile into aprpropriate Makefile.PL as well as MYMETA files.

> cpanfile is only supported by cpanm and carton

With the conversion above, it's supported by all CPAN toolchain, once you pack them into a CPAN distribution.

> miyagawa should really talk to the CPAN toolchain maintainers to add the features he misses.

I've been doing it all the time, by attending QA hackathon three times.


rob:

> Another option within a corporate environment is to create a minicpan and only stock it with the versions you have internaly vetted (possibly with a QA process).

Yes, that's why Pinto and Carton exist. They handle it differently, but the basic idea/goal is the same.

Reini:
> The official way is to mark them in your Makefile.PL or Build.PL, or even dist.ini

It's interesting you mention dist.ini as "the official way" - I would say it isn't, because dist.ini is just a config file for an authoring tool to emit these build files (to generate META/MYMETA files in the end), and not directly supported by ANY cpan clients.

However if you say dist.ini is really official, then cpanfile is official too, since you just add [Prereq::FromCPANfile] to your dist.ini and it works with all the toolchain.

Back to the original question, why new format - cpanfile originally was invented to be a DSL (a la Module::Install) to describe dependencies. It's directly supported by Carton, and I created Module::CPANfile to programatically parse the file, as well as converting it to CPAN::Meta::Prereqs (by working with xdg/rjbs).

Again, if you think dzil is fine, Module::Install is fine, and then cpanfile is yet another invention, you're missing the point.

The use with Carton has always been the point, since that way you can describe your application's CPAN deps needs without making it a CPAN distribution. and that became one of the reason "cpanm --installdeps ." is a so popular command to bootstrap dependencies in a non-CPAN perl applications.

Hope this clarifies. I hear a lot of great feedback people using cpanfile to describe their app dependencies, without making it like a fake CPAN distribution, and love it.

Mark:

Thanks for the post. However I'm curious what you meant by the git installation via the cpanfile, because it's not directly supported yet :)

requires 'git://github.com/...' might (accidentally) work because cpanm runs it as an argument, but it's not the way it should be, and I plan to add the explicit git URL/rev support in cpanfile in the coming weeks, with a warning to migrate to the new syntax.

Mark:
I see, then you can do:

cpanm git://github.com/mrallen1/perl-Tombala

:)

I stopped editing Makefile.PL or Build.PL for both, CPAN modules and applications. With Dist::Zilla one can either track dependencies in dist.ini (also automatically with [AutoPrereqs]) or in cpanfile and use [FromCPANfile].

A benefit of this approach is a better separation between data ("what") and code ("how"): Makefile.PL and Build.PL is code how to do the build process. cpanfile is data to specify what dependencies exist.

Leave a comment

About Mark Allen

user-pic Singer, dad, nerd, not necessarily in that order. @bytemeorg