Dist::Zilla, Pod::Weaver and bin
I use Dist::Zilla for managing my distributions. It's awesome and useful, although it lacks some bits of documentation every now and then; this lack is compensated in other ways, e.g. IRC.
I also use the PodWeaver plugin to automatically generate boilerplate POD stuff in the modules. Some time ago I needed to add some programs to a distribution of mine (which I also managed to forget at the moment, but this is another story), and this is where I got hit by all the voodoo.
The first program was actually a Perl program, consisting of a minimal script to call the appropriate run()
method in one of the modules of the distro:
$ cat bin/perl-program
#!/usr/bin/env perl
use prova;
prova->run();
This led Dist::Zilla to complain like this:
$ dzil build
[DZ] beginning to build prova
[DZ] guessing dist's main_module is lib/prova.pm
couldn't determine document name for bin/perl-program at ...
which isn't the best advice in the world (it actually complains about Pod::Weaver), but let's ignore it for the moment. After a bit of googling - or whatever, I actually don't remember - I found that there were basically two options:
put an explicit
package
declaration in the driver program, like this:$ cat bin/perl-program #!/usr/bin/env perl package prova; use prova; prova->run();
put a comment with a PODNAME:
$ cat bin/perl-program #!/usr/bin/env perl # PODNAME: prova use prova; prova->run();
The latter seems slightly less dumb so I opted for it. I say slightly because IMHO the bottom line should be that the name is equal to the filename, but this is (again) another story. Yes, I know, it's open source and I can propose patches - did I say I'm not complaining?
Anyway, I then needed to add a shell script to the lot:
$ cat bin/script.sh
#!/bin/bash
echo 'Hello, World!'
and again the error popped up:
$ dzil build
[DZ] beginning to build prova
[DZ] guessing dist's main_module is lib/prova.pm
[PodWeaver] [@Default/Name] couldn't find abstract in bin/perl-program
couldn't determine document name for bin/script.sh at ...
Now, I could use the PODNAME
trick above:
$ cat bin/script.sh
#!/bin/bash
# PODNAME: script.sh
echo 'Hello, World!'
but it turns out - with little surprise - that the file is considered a Perl one, with the consequence that in the distribution it gets POD added to it:
#!/bin/bash
# PODNAME: script.sh
echo 'Hello, World!'
__END__
=pod
=head1 NAME
script.sh
=head1 VERSION
version 0.1.0
=head1 AUTHOR
Flavio Poletti <polettix@cpan.org>
=head1 COPYRIGHT AND LICENSE
blah blah blah...
=cut
The only thing is that - ehr... - bash does not like POD very much.
Google was not my friend in this case, but I found one in Dist::Zilla's IRC channel (which is #distzilla
on irc.perl.org
, by the way), which I think (hope) is Christopher J. Madsen, the original contributor of Dist::Zilla::Plugin::FileFinder::ByName.
He instructed me to use that module - which entered the core as of version 4.300003 - to obtain what I was after: keep the PodWeaver plugin working on Perl stuff, while ignoring shell stuff. But, more importantly, he adviced me about why.
Many plugins - including the PodWeaver one - rely upon the Finder
role to do their work. This role is something that finds files to be used by the plugin; in the case of PodWeaver, the default is to take whatever module will be installed and whatever stuff is in the bin directory. OK, it can be a bit more complicated than this, but most of the times it's OK. This default is the same as if we configured the following in the dist.ini
file:
[PodWeaver]
finder = :InstallModules
finder = :ExecFiles
It turns out that if we explicitly configure a finder
all the defaults are wiped away, so - for example - if our bin
directory contained shell scripts only we could be happy with this:
[PodWeaver]
finder = :InstallModules
In our case, anyway, this would disable PodWeaver for Perl programs as well, which is not acceptable. This is where FileFinder::ByName kicks in:
[FileFinder::ByName / BinNotShell]
dir = bin
skip = .*\.sh$
This plugin lets us create new finders. In the example above, we are creating a finder that finds stuff in the bin
directory, skipping all files that end with .sh
(note that skip
sets a regular expression). At this point, we're ready for the configuration of the PodWeaver plugin:
[PodWeaver]
finder = :InstallModules
finder = BinNotShell
It's correct, the new finder does not want the initial colon. Now, when it's time for the Pod::Weaver plugin to find files, it will get all the modules that will be installed AND the files in the bin
directory whose name does not end with .sh
. Yay!