Miyagawa's Carton dependency tracking system for CPAN modules is about to reach its 1.0 release, so I've been exploring it for a client project.
The example project has five or six developers, all working remotely. We collaborate from a single Git repository. We have one testing server, one live server, and one mail server, though we're going to add at least one separate database server in the very near future. Our deployment strategy is minimal; we've automated part of it so that we can roll back commits that have problems, but we haven't automated database changes or system administration changes (adding an SSL certificate, changing the IP address of the database, installing a necessary Debian package, et cetera).
We do have a semi-structured list of deltas for CPAN module installations, but the process of keeping things up to date still requires manual intervention. Because tracking new dependencies and updated dependencies requires manual intervention (for example, a change to JSON rendering in Mojolicious 4 necessitated upgrading Mojolicious everywhere), Carton seemed like a good fit.
Carton does a couple of things. It keeps track of the dependencies of a project and their version numbers, given a list of dependencies, and lets you install those specific dependencies on any machine which has Carton.
In other words, if I somehow tell Carton that my project depends on Test::Most and Math::BaseConvert,
Carton will write out a file it knows how to understand such that anyone who
checks out the repository can use carton install
to install the
exact version of those modules I have installed.
(Carton can also bundle dependencies into a cache directory and install them from that cache, but that's not what we're doing.)
To start using Carton, install it. Then create a cpanfile with your dependencies:
require 'Test::Most';
require 'Math::BaseConvert';
With this file in place, run carton install
. This will install
those modules, if necessary, and write a file called cpanfile.snapshot
with dependency information. (See Module::CPANfile for
more information about cpanfile.)
Because Carton intends to manage dependencies for an application, it wants
to install its modules to local/lib/perl5/ beneath the current
directory. This may not work with your application; you may prefer to set the
PERL_CARTON_PATH
environment variable to point elsewhere. Keep in
mind that wherever you have Carton install these dependencies, your application
needs to have that directory in its include path somehow. (See Carton::Environment
for more information.)
You can safely exclude that directory from your source control, but you should include both cpanfile and cpanfile.snapshot so that other people can work with Carton from your VCS checkout.
Adding a dependency is as easy as editing cpanfile and running
carton install
. Similarly, satisfying dependencies on a new
checkout is as easy as running carton install
.
For various reasons, our client project has a Makefile, so it's likely we'll add a simple target to add dependencies (and stage them for the next git commit) and to update dependencies. This, in fact, is one of the benefits of the design of Carton. Even though I only found an environment variable for customizing the library installation path, it's almost trivial to use the modules which make up Carton to build an application-specific installer—whereby we can keep our cpanfile and cpanfile.snapshot files in a directory of our choosing.
There's not much else to Carton I need beyond what I've described here. It doesn't intend to produce a full CPAN repository as tools like DarkPAN or Pinto do, which is fine. All we need is a little more discipline on how we manage dependencies, and Carton gives us an effective way to do that.