When developing pearl modules, you have to do a lot of work, which is practically not related to the tasks and module code - from creating a dozen generic files / directories to doing a dozen identical operations necessary for the release of a new version.
In addition to being
boring, lazy, and often leads to errors (due to the need to update meta-information — such as the version number — in several files or the inadvertent omission of some commands during release), everything is further complicated by Perl TIMTOWTDI — there are several different build systems , all have their advantages and disadvantages (but there is no simple label with their enumeration), and none of them
is recommended by any official or community.
In addition, many of us have been writing on pearl for many years, and the last time they read
perlnewmod was studying pearl. As a result, when new modules are created, this is often done
in the style of 15 years ago , and
the assembly system is chosen almost randomly - either the ancient, but familiar and precisely able
EUMM , or one of the others (not because she needs , but simply in the hope that it will be easier and more convenient for EUMM, without creating new problems ... which it does create with time).
')
The following briefly describes the tools available at the beginning of 2015 that can facilitate the process of developing pearl modules, make your modules more modern, and make it easier for other developers to refine your modules. I tried to list their main pros and cons, but because I myself did not use everything, I will supplement / correct this list in accordance with your comments.
Tasks
So let's create a list of tasks that are usually included in the process of authoring Perl modules.
Tasks when creating a new module:- set name / email author
- determine license
- select build system
- select additional features:
- XS support
- basic test suite (checking documentation, spelling, code quality, dependencies, build system files, etc.)
- automatic generation of README from module documentation
- use VCS
- integration with GitHub, Travis CI
- create a skeleton module - a directory with a bunch of files needed for its development and release:
- the skeleton of the module itself and documentation
- basic test suite
- Changes
- README
- LICENSE
- build system files
- dependency list (sometimes included in build system files)
- when using VCS: repository and its settings
Tasks in the release of the new version:- update the list of dependencies
- assemble module
- run tests
- select a new version number and change it in several files (in some files - in several places)
- describe changes to Changes
- add current date and release version to Changes
- update README
- when using VCS:
- commit changes to version, Changes, and all other modified files
- add tag for new version
- when using central repo (GitHub) - send changes to it
- create archive with module
- pour it on CPAN
Ideally, all decisions necessary when creating a new module (except for the need for XS) need to be taken once, and in the future to create new modules with one command. And with the release, ideally, one team should perform all the steps except for choosing a new version number and a description of changes in Changes.
Update: if you read it here, and did not understand what kind of “authoring” is and how it differs from the usual use of Makefile.PL/Build.PL - read these
two comments .
$ VERSION
In a perfect world, I would never write a blog about version numbers in Perl.
"Version numbers should be boring" - David Golden
Before proceeding to the essence of the question, it is necessary to describe one problem: the choice of format for the module version. Although it is not directly related to the topic of the article, this choice must be made during the authoring process, and it is not as simple as it may seem.
There are
so many ways to incorrectly declare the version of your module, so I will list only the correct ones - there are a lot of them.
Old decimal / Old-style decimal
Stable releases (two / three digits, as you like):
our $VERSION = '0.08'; our $VERSION = '0.008'; package MyModule 0.08;
Alpha versions for testing CPAN Testers before the release of
0.09
/
0.009
:
our $VERSION = '0.08_01'; our $VERSION = '0.008_001';
Or, considering that users won't see alpha versions anyway, you can use two independent sequences for stable and unstable releases:
an example .
Dotted-number / dotted-decimal
Stable releases (3 or more numbers can be used in the version):
use version; our $VERSION = 'v0.8.0';
Alpha versions for testing CPAN Testers before
v0.8.1
release:
use version; our $VERSION = 'v0.8.0_1';
Although
"v0.8_1"
can also be used as an alpha version between the stable
"v0.8.0"
and
"v0.8.1"
but this version can only be one - if you need to release several alpha versions, then release the stable one with the number
"v0.8.1"
will not work.
Semantic / Semantic
At the moment there is no possibility to
fully comply with the
specification of semantic versioning - the pre-release versions defined as
"1.2.3-alpha1"
cannot be applied to pearl modules. The closest option would be the above-described 3-element dot-number version - you can follow the rules for determining the next stable version according to the specification, and instead of textual pre-release versions release numerical alpha versions.
TRIAL
You have already noticed that the alpha version is, as our foreign colleagues say, “pain in the ass”. In fact, this is not about real “alpha” - real alpha, beta and other pre-release versions are described in the semantic versioning specification and are not supported by pearl. The point is to give the
CPAN the command “do not index” this version. Thus, we mix two data types in one variable (version number and flag for CPAN), which is bad style, looks ugly, confuses (what to choose before releasing
"v0.8.1"
-
"v0.8_1"
or
"v0.8.0_1"
?) and creates other problems: the alpha version cannot be set in the package, in some old (up to 5.8.1) versions of perl, they do not work correctly.
Not so long ago, a new way was added to CPAN to give the command “do not index” this version - if the word
"TRIAL"
is in the archive name with the module. Thus, you can no longer use the "alpha" version. Some utilities (
Dist :: Zilla ,
shipit , ...) support the parameter to be added to the archive name with the
"-TRIAL"
module before being
"-TRIAL"
to the CPAN. Note that
"v1.2.3-TRIAL"
(unlike
"v1.2_3"
) is the usual version of
"v1.2.3"
, so the next one after it should be
"v1.2.4"
or
"v1.2.4-TRIAL"
.
Skeleton Module / Boilerplate
These utilities create a directory with a new module, filling it with a basic set of necessary files for some pattern. This is the oldest, and, until now, the main way to create a new module. The problem with this approach is that a significant portion of these files are not enough to create once, they need to be constantly updated when new versions of the module are released. Therefore, many gradually begin to use more complex solutions instead of these utilities (usually based on Dist :: Zilla).
h2xs, Module :: Starter
The use of these modules is described in
perlnewmod , but the point is that they are very outdated, practically
not supported , too complex and not flexible enough.
On CPAN, you can find some more
similar modules , but all that I saw were tailored to the needs of their authors and were not very flexibly configured - in fact, the task of generating a catalog with a new module using a template is so simple that almost everyone writes their own bike ( mine is a script for 20 lines in
~/bin/
, which is also absolutely not customizable).
Build
With 95% of modules containing several pm-files, tests and a small piece of XS as standard, any assembly system will cope with it.
Starting from 5.10.1 there is support for configure_requires - i.e. you can now in
META.{json,yml}
specify which modules should be installed
before running
perl Makefile.PL
or
perl Build.PL
. In other words, now it does not matter whether the user has installed, for example,
Module :: Build :: Tiny - you can use it to build your own module. Or you can write your build system for your modules.
ExtUtils :: MakeMaker (aka EUMM)
Features:- requires
make
- there is dependency graph support (using
make
)
Disadvantages:- to change the build process, you usually have to change the
Makefile
(either by appending a piece to it, or somehow transforming it; moreover, it must be done portably in both the Makefile
format and the shell commands used in it) - which is very strong complicates- when making changes you need to write portable code
- too big and complicated, nobody wants to support and develop it
- it is difficult to write plugins to it and it is difficult to connect several plug-ins at the same time
Advantages:- the most flexible of all alternatives, therefore in difficult cases you have to use only EUMM
Module :: Build (aka MB)
Features:- there is enough perl to work, no
make
needed, no knowledge how to write a portable Makefile
- there is no dependency graph support (what does it depend on when building)
- removed from core (modules distributed with perl) —that won't affect anything (thanks to configure_requires), but caused a FUD wave; in fact, no new reasons for avoiding it have appeared, and if the old reasons did not stop you, continue to use it calmly and continue
Disadvantages:- too big and complicated, nobody wants to support and develop it
- because of the architecture similar to EUMM (for the extension you need to write code that will be used to generate other code that will already be executed), it has the same problem - it is difficult to write plugins and it is difficult to connect several plugins at the same time ( Module :: Build recently appeared : : Pluggable , which is trying to solve the other half of this problem)
Advantages:- use and, in small volumes, expand much easier than EUMM
Module :: Install (aka MI)
Features:Disadvantages:- trying to solve the problem of the lack of at that time configure_requires by copying itself and all the plugins in
inc/
necessary for building the current module — which, in turn, created new problems (and now has no meaning at all) —from the need to re-issue its module to fix the bug in the bundled version of the MI to the inconvenience when using VCS due to the fact that the code relating to the MI is constantly updated in the repository
Advantages:- simple and intuitive interface
Despite the unanimous dislike of the community for EUMM and
Module :: Build , I got the impression that
Module :: Install has lately stopped being taken seriously at all - the problems it creates from time to time outweighed its merits.
Module :: Build :: Tiny (aka MBT)
Features:- An experiment that showed that it is possible to make an assembly system on a pearl sufficient for most modules, just 120 lines of code
Your
Build.PL
looks like this:
use 5.008001;
Strangely enough, you can even use it - using the
cpanfile file for managing dependencies and the auxiliary utility
mbtiny for authoring (generating
Build.PL
,
MANIFEST
and
META.{json,yml}
, preparing the archive with the module - what the Module :: Build and that does not apply to the module
building process). Either use Dist :: Zilla instead of
mbtiny
(by the way,
Dist :: Milla and
Minilla use MBT - for such clever systems it is very convenient when the build system does only its work and does not take on "extra" tasks).
Dependency Management / Dependencies
cpanfile
This is an approach in which dependencies are specified separately from the build system, in the
cpanfile
file. There are several reasons to do this:
- If you use different build systems in different modules, using the cpanfile allows you to forget about the differences in syntax (and restrictions — EUMM and Module :: Install do not fully support CPAN :: Meta :: Spec 2.0 ) of different build systems and use the same format for all (by the way, compatible with the Module :: Install format).
- In the same way, you can set dependencies not only for pearl modules, but also for ordinary applications (which usually do not have a
Makefile.PL
or Build.PL
and there is simply no way to specify dependencies) - actually, it was for this feature that cpanfile was developed. Moreover, you can set an alternative source for a separate dependency, from where to get it - from the private CPAN mirror, from git, etc. - You can install all the dependencies via
cpanm --installdeps .
or carton without META.{json,yml}
files. - When using Module :: Install, you can not keep in the
inc/
and META.{json,yml}
repository META.{json,yml}
and correctly specify the dependence on Module :: Install as “develop” (author_requires) and not “configure” (configure_requires). At the same time, other developers who have not installed Module :: Install will be able to install it via cpanm --with-develop --installdeps .
or carton
.
Version Control / VCS
In the case of pearl modules, you need to keep in mind that, on the one hand,
you need to store all the files
necessary for building the module (so that it can be
installed directly from the repository via
cpanm
and that other developers get the
working version of the project after the fork), and on the other hand, avoid littering it with unnecessary auto-generated files (for example, Module :: Install files in
inc/
) - because you commit them all the time, plus they will litter the diff, etc. This is especially true for Dist :: Zilla users - if you want to receive pull requests, then you shouldn’t require that those who want to fix you some trifles have to install 150-200 additional modules to start the project build.
Github
When using
GitHub, you most likely have to either write an additional description of the module in
README.md
, or configure the automatic generation of this file from the module's POD documentation. And in the second case, you may need to add additional elements - for example, the project build status in Travis CI.
Continuous Integration / CI
CPAN Testers
Until April 2013,
CPAN Testers did not support a separate indication of
test_requires (dependencies required only for running tests). In this case, the assembly system has long given the opportunity to indicate them ... but it did not work. As a result, some module developers were very upset, they released a new version without any clever test_requires and forgot about this feature. So, it is
already possible !
Details of test_requires support by different versions of build systems.In principle, the CPAN Testers service covers basic needs, but it has one drawback: testing occurs
after release . To drive a module through CPAN Testers before release, you need to release special
alpha versions - and it’s still a release, and CPAN Testers doesn’t work that fast.
GitHub + Travis CI
By connecting to the repository with a module on GitHub
Travis CI, you can automate testing of the current version of the module
before release on
several versions of perl (although this is not so cool in terms of different platforms like CPAN Testers, but it's still better than running tests on your own machine ).
Release / Release
App :: scan_prereqs_cpanfile
Provides the
scan-prereqs-cpanfile command to analyze module dependencies and generate a
cpanfile
or display differences from the current
cpanfile
(if it was modified manually and simply re-generating it is not the best idea).
Perl :: Version
Provides the
perl-reversion command to change the version number in (almost) all module files.
Supports
README
, but not
README.md
.
CPAN :: Uploader
Provides the
cpan-upload command for
uploading modules to CPAN from the command line. The config file
~/.pause
with login / password for PAUSE can be encrypted by GnuPG.
Github
Unfortunately, GitHub is not yet able to automatically upload pearl modules to CPAN (although, probably, technically, it would be more correct to say that this CPAN does not know how to download modules from GitHub) when adding a tag for a new version (as is the case with plug-ins for jQuery). But anyway, I'll leave this point here, all of a sudden, the right people will see it and add a feature.
Support / Support
CPAN RT
The bug tracker CPAN has been the only available option for many years. Given its awkward interface, it was very sad. On the other hand, it can be used even if you
do not use VCS when developing a module.
Fortunately, now it is possible to specify in
META.{json,yml}
(not with handles, of course, but through the build system used)
an alternative bug tracker (for example, on GitHub). Unfortunately, although this will change the links to the bug tracker on the CPAN and
MetaCPAN sites , this will not disable the ability to add tickets for your module to the CPAN RT (but it shows a notification that the preferred bug tracker is in a different place). Of course, after changing the bug tracker, the
current bugs remain in RT .
Github
I will not describe the advantages and convenience of supporting projects on GitHub (especially conspicuous compared with CPAN RT). Moreover, even if you don’t like Git, you can work with Mercurial locally without any problems and still keep the project on GitHub (via the
hg-git plugin).
If you want to move current tickets from CPAN RT to GitHub Issues, you can try using
rt-to-github.pl or this
modification of its old version.
Authoring / Authoring
In this section, utilities will be described completely taking on the process of authoring modules, often using the above-described utilities to solve individual authoring subtasks.
I have two servers, one has just been installed, there are only 27 CPAN modules, on the second one many pearl projects have been developed for many years, 248 CPAN modules are installed there. I calculated how many additional CPAN modules have to be installed on each of the servers for the utilities described in this section:
- Dist :: Zilla (without additional plug-ins) requires 162 modules on the first and 83 modules on the second server.
- Dist :: Milla (in fact, a selection of plugins for Dist :: Zilla) requires 257 and 166 modules.
- Minilla (which declares minimum dependencies as one of the main advantages) - 126 and 41 modules.
- ShipIt - 1 and 1.
- App :: ModuleBuildTiny - 8 and 6.
Dist :: Zilla
This is a real monster.
He does everything! On CPAN, there are now about 900 modules included in 480 distributions that extend Dist :: Zilla. Of these 480 distributions, 315 are plug-ins (Dist :: Zilla :: Plugin :: *), and another 100 are different collections of these plug-ins (Dist :: Zilla :: PluginBundle :: *).
There are only two problems: how many days you need to spend, so that he starts doing what you personally need, and the number of modules you need to install to use it.
On the first problem - I can not say anything. I did not dare to get involved and try to customize it for myself. Who did it - share your impressions in the comments.
The second problem is also quite important - if you want to receive patches and pull requests to your module, it is necessary that those who wish to make changes to it can be done simply enough. If they need to install half of the CPAN to correct a couple of lines (the author claims that
not half, but only 0.6% ) and deal with a non-standard build process, you will not wait for the patch.
Dist :: Milla
Features:- just a selection of plugins for Dist :: Zilla and a utility wrapper
- Perl license is used, to change it, replace it with another one in POD
- there is no automatic detection and update of dependencies, they need to be described manually in
cpanfile
- you can use
scan-prereqs-cpanfile --diff=cpanfile
to quickly find all new connected modules that have not yet been added to cpanfile
- you can choose which build system will be used: Module :: Build :: Tiny (by default), Module :: Build or EUMM, but I'm not sure that you can use all the features of the selected build system -
Build.PL
doesn't make sense to edit, it’s each build is re-generated
Disadvantages (compared to Dist :: Zilla):- An even greater number of dependencies that need to be installed ... but this, to a large extent, is compensated by the fact that you can save a few days on drawing up your own collection of plug-ins, which is not the fact that it would be less
- however, as soon as you want to add a new feature, for example the output of a badge with the Travis CI report in README.md, you will still need to search for and connect the additional Dist :: Zilla plugin
- like XS-modules are not supported (probably will need to connect an additional plugin)
Advantages:- Many popular Dist :: Zilla plugins modify the module code and / or documentation (or depend on the plugins that do it), forcing you to change your workflow - there are basically no such plugins in Dist :: Milla: your code and documentation are changed only by you (excluding update
$VERSION
upon release)- instead of changing the code / documentation based on the given meta-data, Dist :: Milla works in the opposite direction, calculating the meta-data based on the code, documentation, and repository — as build systems like Module :: Install or Module have always done: : Build
- Unlike most modules using Dist :: Zilla, third-party developers can easily participate in the development of modules using Dist :: Milla - they do not need to install Dist :: Zilla themselves or deal with a non-standard build process, your module looks, builds, tests and installs like all normal modules
- in particular, your module can be installed directly from GitHub
- there is no need to spend a few days on selecting and setting up your own set of plug-ins for Dist :: Zilla, you can immediately start using a fairly good starter set, and then modify it as needed
- support of migration of an existing module using another build or authoring system on Dist :: Milla
Minilla
Features:- almost identical to Dist :: Milla with default settings
Disadvantages:Advantages:- compatible with standard build / install process
- does not use Dist :: Zilla
- significantly less dependencies than Dist :: Milla
- supports XS
- support for migrating an existing module using another Minilla build or authoring system
If you do authoring in almost the same way as Tokuhiro Matsuno (by Minilla), or if you are exactly how authoring is done, the main thing is that everything works out of the box itself in a fairly modern way (i.e. using git and GitHub) and not required the installation of a wild number of modules - Minilla is ideal for you. If you need to do something differently, you will have to look for a replacement for him (most likely she will be Dist :: Milla).
ShipIt
shipit
, .
.shipit
, :
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
shipit
.shipit
:
Changes
- (
Makefile.PL
Build.PL
) - commit ( Git/Mercurial/SVN)
- tag
- CPAN
, CPAN
(
README
POD, POD, , ., …).
, ShipIt — , Dist::Milla ShipIt Dist::Milla. ShipIt , , , . , , Dist::Zilla ShipIt.
Dist::Zilla ( ShipIt Dist::Zilla) ShipIt — . ,
Dist::Zilla .
App::ModuleBuildTiny
, . , 0.005, … , Module::Build::Tiny , Dist::Zilla Minilla.
, . «A standalone authoring tool», . ( ) Dist::Zilla.
— CPAN:
mkdir -p Example-MBtiny/lib/Example/ cd Example-MBtiny vi lib/Example/MBtiny.pm mbtiny dist
Example-MBtiny-$VERSION.tar.gz
CPAN. -
lib/Example/MBtiny.pm
.
( - ) , GitHub:
README.md
,
LICENSE
,
Changes
,
t/*
,
.gitignore
,
.travis.yml
, GitHub.
—
mbtiny
:
mbtiny test
mbtiny dist
, , Build.PL
, MANIFEST
META.{json,yml}
. , CPAN, — cpanm
- pull-request.- —
mbtiny regenerate
Build.PL
, MANIFEST
META.{json,yml}
. , , — .
GitHub
metamerge.json
,
META.{json,yml}
:
{ "resources" : { "bugtracker" : { "web" : "https://github.com/powerman/Example-MBtiny/issues" }, "homepage" : "https://github.com/powerman/Example-MBtiny", "repository" : { "type" : "git", "url" : "git://github.com/powerman/Example-MBtiny.git", "web" : "https://github.com/powerman/Example-MBtiny" } } }
:
# update dependencies scan-prereqs-cpanfile >cpanfile # ... update META.* from cpanfile if you added META.* into the repo mbtiny regenerate # build & test mbtiny test # update version everywhere ver=1.2.3 perl-reversion -set $ver # don't forget to update version & date vi Changes # regenerate README.md with badges cp BADGES.md README.md pod2markdown lib/Example/MBtiny.pm >> README.md # release git commit -a -m "release $ver" git tag $ver git push mbtiny dist cpan-upload Example-MBtiny-$ver.tar.gz
, — , - , - . . (, ) Dist::Zilla.
Summary
- , ,
use 5.010001;
our $VERSION="v1.2.3";
- Module::Build::Tiny Module::Build ( MBT)
cpanfile
- GitHub, GitHub
META.json
— . :
- Minilla, -
- Dist::Milla, Minilla - , Dist::Zilla
- App::ModuleBuildTiny, ,
______________________