Choose Your Own Tutorial
Converting a Dist to Dist::Zilla
This tutorial page is adapted from the Perl Pub article More Code, Less Cruft: Managing Distributions with Dist::Zilla
Switching your old code to use Dist::Zilla is easy, and you can be conservative or go whole hog. We'll walk through the process of converting one of my dists, Number::Nary. To follow along, clone its git repository and start with the commit tagged
pre-dzil. If you don't want to use
git, that's fine. You'll still be able to see what's going on.
The first thing we'll replace is Makefile.PL, the traditional program for building and installing distributions (or "dists"). If you started with a Module::Build-based distribution, we'd replace Build.PL, instead. Dist::Zilla will build those files for you in the dist you ship so that installing users have them, but you'll never need to think about them again.
Number::Nary was packaged with Module::Install, the library that inspired me to build Dist::Zilla. Its Makefile.PL looked like this:
If it had been using ExtUtils::MakeMaker, it might've looked something like this:
We can just delete that file and replace it with the file dist.ini, looking like this:
Right now, we've gained lines, but don't worry -- that won't last long.
Most of this should be self-explanatory, but the cluster of square-bracketed names isn't. Each one sets up another plugin, and every plugin helps with part of the well-defined process of building your dist. The ones above set up the absolute minimum needed to replace Makefile.PL: they pull in all the files in your checkout and when you build the dist they add the extra files you need to ship.
At this point, if you just wanted to build a tarball to release, you could run
dzil build (instead of
perl Makefile.PL && make dist) and upload the resulting file. We want to start seeing the savings, though, so here we go...
Eliminating Pointless Packaging Files
The MANIFEST.SKIP file tells other packaging tools which files to exclude. You could keep using it (with the ManifestSkip plugin), but you can almost always just drop the file and use the PruneCruft plugin. It prunes all the files people usually put in their skip file.
The CPAN community has a tradition of shipping lots of good documentation, written in Pod. Despite this, a number of tools expect a plain README file. The Readme plugin will generate one for you.
Downstream distributors (like Linux distributions) like to see really clear license statements, especially in the form of a LICENSE file. Because your dist.ini knows the details of your license, it can generate this file for you.
So, we've deleted three whole files -- MANIFEST.SKIP, LICENSE, and README -- and added exactly the following to our configuration:
Not bad, especially when you remember that now when you edit your dist version, license, or abstract, these files will be guaranteed to contain the new data.
There are a bunch of tests that people expect CPAN authors to run before releasing these days. Number::Nary had three of them:
xt/release/perl-critic.t xt/release/pod-coverage.t xt/release/pod-syntax.t
They were in the ./xt/release directory to indicate that they should only be run when testing a new release candidate, not by every installing user.
These files are pretty simple, but the last thing you want is to find out that you've been copying and pasting a slightly buggy version of the file around. Instead, you can just generate these files as needed, and if there's a bug, you fix the plugin and everything gets the fix on the next rebuild. Once again, we can delete those three files in favor of these plugins:
Test::Perl::Critic and the Pod test plugins add test files to your ./xt directory and ExtraTests rewrites them to live in ./t, but only under the correct circumstances, like during release testing.
If you'd customized your Pod coverage tests to consider certain methods trusted despite having no docs, you can move that configuration into your Pod itself, adding a line like this:
(If you're using Pod::Weaver, make sure that this line isn't being lost in translation! One way to do that is to make sure you've got a Leftovers section.)
The Test::Perl::Critic plugin, by the way, does not come with Dist::Zilla. It's a third party plugin. There are a bunch of those on the CPAN, and they're easy to install.
[Test::Perl::Critic] tells Dist::Zilla to load Dist::Zilla::Plugin::Test::Perl::Critic. Just install that with cpan or your package manager and you're ready to use the plugin.
The @Basic Bundle and Cutting Releases
Since most of the time you want to use the same config everywhere, Dist::Zilla makes it easy to reuse configuration. We're using something very close to the "Basic" plugin bundle shipped with Dist::Zilla. We could replace all the plugin configuration (except for Prereqs) with this:
...so we're finally getting back to a nice, small config file.
Classic gets us a few other plugins, too, but most of them aren't worth mentioning right now. One that is, though, is UploadToCPAN. It enables the command
dzil release, which lets you release your dist to the CPAN easily.
Letting Dist::Zilla Alter Our Modules
So far, we've just let Dist::Zilla build extra files like tests and packaging files. You can get a lot more out of Dist::Zilla if you let it mess around with your library files, too.
For example, we could add the PkgVersion and PodVersion plugins to let Dist::Zilla take care of setting the version in all our libraries. They find .pm files and add a
our $VERSION = ... declaration and a
=head1 VERSION section to the Pod -- which means we could go delete all those from our code and not worry about keeping them up to date anymore.
Another thing that Dist::Zilla can help with is managing our prerequisites. Right now, our dist.ini has a long list of prerequisites, just like our old Makefile.PL did:
[Prereqs] Carp = 0 List::MoreUtils = 0.09 Sub::Exporter = 0.90 UDCode = 0
We can get rid of all that with AutoPrereqs, which will analyze our code to find all the libraries we need and the versions needed. We just pull out Prereqs and add AutoPrereqs. (In this example, it's fine, but AutoPrereqs may not pick up some unusual forms of dependency. When converting your own dist, consider double-checking.)
Dist::Zilla can also automatically provide sections of boilerplate Pod like
If you'd like to learn about declaring or detecting prerequisites, turn to page 5
If you'd like to learn how to test your distribution, turn to page 8
If you'd like to learn how to release your distribution to the CPAN, turn to page 9