📜 ⬆️ ⬇️

Authoring Perl Modules

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:
  1. set name / email author
  2. determine license
  3. select build system
  4. 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
  5. 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:
  1. update the list of dependencies
  2. assemble module
  3. run tests
  4. select a new version number and change it in several files (in some files - in several places)
  5. describe changes to Changes
  6. add current date and release version to Changes
  7. update README
  8. when using VCS:
    1. commit changes to version, Changes, and all other modified files
    2. add tag for new version
    3. when using central repo (GitHub) - send changes to it
  9. create archive with module
  10. 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; # need perl-5.12 package MyModule 0.008; # need perl-5.12 

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'; # need perl-5.8.1 our $VERSION = 'v0.8.0'; # need perl-5.10 package MyModule v0.8.0; # need perl-5.12 

Alpha versions for testing CPAN Testers before v0.8.1 release:

 use version; our $VERSION = 'v0.8.0_1'; # need perl-5.8.1 our $VERSION = 'v0.8.0_1'; # need perl-5.10 

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:
Disadvantages:
Advantages:

Module :: Build (aka MB)


Features:
Disadvantages:
Advantages:

Module :: Install (aka MI)


Features:
Disadvantages:
Advantages:
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:
Your Build.PL looks like this:

 use 5.008001; # only if you need it use Module::Build::Tiny; Build_PL(); 

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:


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


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:
Disadvantages (compared to Dist :: Zilla):
Advantages:

Minilla


Features:
Disadvantages:
Advantages:
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 :

  1. Changes
  2. ( Makefile.PL Build.PL )
  3. commit ( Git/Mercurial/SVN)
  4. tag
  5. 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 :


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



— . :




______________________
habrahabr backend AsciiDoc .

Source: https://habr.com/ru/post/249767/


All Articles