Pull to refresh

Авторинг Perl модулей

Reading time 19 min
Views 6.2K
При разработке перл-модулей приходится делать много работы, которая практически не связана с задачами и кодом модуля — начиная от создания десятка типовых файлов/каталогов и заканчивая выполнением десятка одинаковых операций необходимых для выпуска новой версии.

Помимо того, что это скучно, лениво, и часто приводит к ошибкам (из-за необходимости обновлять мета-информацию — вроде номера версии — в нескольких файлах или нечаянного пропуска части команд при релизе) всё дополнительно осложняется перловским TIMTOWTDI — существует несколько разных систем сборки, у всех есть свои достоинства и недостатки (но нет простой таблички с их перечислением), и ни одна из них не является рекомендуемой ни официально ни сообществом.

Кроме того, многие из нас пишут на перле очень много лет, и последний раз читали perlnewmod когда изучали перл. В результате, когда создаются новые модули это нередко делается в стиле 15-ти летней давности, причём система сборки выбирается практически случайным образом — либо древний, но знакомый и точно умеющий что угодно EUMM, либо одна из других (не потому, что нужна именно она, а просто в надежде что она окажется проще и удобнее EUMM, не создав при этом новых проблем… которые она всё-таки со временем создаёт).

Далее кратко описаны имеющиеся на начало 2015 года средства, которые могут облегчить процесс разработки перл-модулей, сделать ваши модули более современными, и упростить другим разработчикам доработку ваших модулей. Я постарался перечислить их основные плюсы и минусы, но т.к. сам пользовался не всеми то буду дополнять/исправлять этот список в соответствии с вашими комментариями.


Задачи


Итак, давайте составим список задач, которые обычно входят в процесс авторинга Perl модулей.

Задачи при создании нового модуля:
  1. задать имя/email автора
  2. определить лицензию
  3. выбрать систему сборки
  4. выбрать дополнительные особенности:
    • поддержка XS
    • базовый набор тестов (проверка документации, правописания, качества  кода, зависимостей, файлов системы сборки, etc.)
    • автоматическая генерация README из документации модуля
    • использование VCS
    • интеграция с GitHub, Travis CI
  5. создать скелет модуля — каталог с кучкой файлов необходимых для его  разработки и релиза:
    • скелет самого модуля и документации
    • базовый набор тестов
    • Changes
    • README
    • LICENSE
    • файлы системы сборки
    • список зависимостей (иногда входит в файлы системы сборки)
    • при использовании VCS: репозиторий и его настройки

Задачи при релизе новой версии:
  1. обновить список зависимостей
  2. собрать модуль
  3. запустить тесты
  4. выбрать новый номер версии и изменить её в нескольких файлах (в  некоторых файлах — в нескольких местах)
  5. описать изменения в Changes
  6. добавить в Changes текущую дату и версию релиза
  7. обновить README
  8. при использовании VCS:
    1. commit изменений версии, Changes, и всех остальных изменённых файлов
    2. добавить tag для новой версии
    3. при использовании центрального репо (GitHub) — отправить в него  изменения
  9. создать архив с модулем
  10. залить его на CPAN

В идеале, все решения необходимые при создании нового модуля (кроме необходимости в XS) нужно принять один раз, и в дальнейшем создавать новые модули одной командой. А при релизе, в идеале, одна команда должна выполнить все шаги кроме выбора нового номера версии и описания изменений в Changes.

Update: если вы дочитали сюда, и не поняли что за «авторинг» такой и чем он отличается от обычного использования Makefile.PL/Build.PL — прочитайте эти два комментария.

$VERSION


In a perfect world, I would never blog about version numbers in Perl.
 «Version numbers should be boring» — David Golden
Перед тем как перейти к сути вопроса, необходимо описать одну проблему: выбор формата для версии модуля. Хотя это и не связано напрямую с темой статьи, этот выбор необходимо делать в процессе авторинга, и он не так прост, как может показаться.

Есть очень много способов неправильно объявить версию своего модуля, поэтому я перечислю только правильные — их намного меньше.

Старая десятичная / Old-style decimal


Стабильные релизы (две/три цифры, кому как нравится):

our $VERSION = '0.08';
our $VERSION = '0.008';
package MyModule 0.08;                  # need perl-5.12
package MyModule 0.008;                 # need perl-5.12

Альфа-версии для тестирования CPAN Testers перед выпуском 0.09 / 0.009:

our $VERSION = '0.08_01';
our $VERSION = '0.008_001';

Либо, учитывая что альфа-версии пользователи всё-равно не увидят, вы можете использовать две независимые последовательности для стабильных и нестабильных релизов: пример.

Точечно-числовая / Dotted-decimal


Стабильные релизы (можно использовать 3 и более чисел в версии):

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

Альфа-версии для тестирования CPAN Testers перед выпуском v0.8.1:

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

Хотя "v0.8_1" тоже можно использовать как альфа-версию между стабильными "v0.8.0" и "v0.8.1" но такая версия может быть только одна — если понадобится выпустить несколько альфа-версий то выпустить стабильную с номером "v0.8.1" уже не получится.

Семантическая / Semantic


На данный момент нет возможности полностью соответствовать спецификации семантического версионирования - pre-release версии определённые как "1.2.3-alpha1" применить к перл-модулям нельзя. Самым близким вариантом будет вышеописанная 3-х элементная точечно-числовая версия — вы можете следовать правилам определения следующей стабильной версии по спецификации, а вместо текстовых pre-release версий выпускать числовые альфа-версии.

TRIAL


Вы уже заметили, что альфа версии это, как говорят наши зарубежные коллеги, «боль в заднице». Фактически ведь речь идёт не о настоящих «альфа» — настоящие альфа, бета и прочие pre-release версии описаны в спецификации семантического версионирования и не поддерживаются перлом. Речь идёт о том, чтобы дать CPAN команду «не индексировать» данную версию. Таким образом мы смешиваем в одной переменной два типа данных (номер версии и флаг для CPAN), что является плохим стилем, уродливо выглядит, запутывает (что выбрать перед выпуском "v0.8.1""v0.8_1" или "v0.8.0_1"?) и создаёт другие проблемы: альфа версии нельзя задать в package, в некоторых старых (до 5.8.1) версиях perl они работают не корректно.

Не так давно на CPAN добавили новый способ дать команду «не индексировать» данную версию — если в имени архива с модулем есть слово "TRIAL". Таким образом, вы можете больше не использовать «альфа» версии. Некоторые утилиты (Dist::Zillashipit, …) поддерживают параметр для добавления в имя архива с модулем "-TRIAL" перед заливанием на CPAN. Учтите, что "v1.2.3-TRIAL" (в отличие от "v1.2_3") это обычная версия "v1.2.3", так что следующая после неё должна быть "v1.2.4" или "v1.2.4-TRIAL".

Скелет модуля / Boilerplate


Эти утилиты создают каталог с новым модулем, наполняя его базовым набором необходимых файлов по какому-то шаблону. Это самый старый, и, до сих пор, основной способ создать новый модуль. Проблема этого подхода в том, что значительную часть этих файлов мало просто однократно создать, их нужно постоянно обновлять при выпуске новых версий модуля. Поэтому многие постепенно начинают использовать вместо этих утилит более комплексные решения (обычно на базе Dist::Zilla).

h2xs, Module::Starter


Использование этих модулей описано в perlnewmod, но суть в том, что они очень устарели, практически не поддерживаются, слишком сложные и при этом недостаточно гибкие.

На CPAN можно найти ещё некоторое количество аналогичных модулей, но все, которые видел я, были заточены под потребности их авторов и не очень гибко настраивались — по сути, задача генерации каталога с новым модулем по шаблону настолько проста, что почти каждый пишет свой велосипед (мой — это скрипт на 20 строк в ~/bin/, тоже абсолютно не настраиваемый).

Сборка / Build


С 95% модулей содержащих несколько pm-файлов, тесты и стандартно собирающийся небольшой кусок XS — справится любая система сборки.

Начиная с 5.10.1 появилась поддержка configure_requires — т.е. теперь можно в META.{json,yml} указать какие модули должны быть установлены до запуска perl Makefile.PL или perl Build.PL. Иными словами теперь не важно, установлен ли у пользователя, например, Module::Build::Tiny — вы можете использовать его для сборки своего модуля. А можете написать свою систему сборки для своих модулей.

ExtUtils::MakeMaker (a.k.a. EUMM)


Особенности:
  • требует наличия make
  • есть поддержка графа зависимостей (благодаря использованию make)

Недостатки:
  • для изменения процесса сборки обычно приходится менять Makefile (либо  дописывая к нему кусок, либо как-то его преобразуя; более того, это  необходимо делать портабельно как в плане формата Makefile так и в  плане используемых в нём шелл-команд) — что очень сильно всё усложняет
    • при внесении изменений нужно писать портабельный код
  • слишком большой и сложный,  никто не хочет его поддерживать  и развивать
  • к нему сложно писать плагины и сложно подключать одновременно несколько  плагинов

Достоинства:
  • самый гибкий из всех альтернатив, поэтому в сложных случаях приходится  использовать исключительно EUMM

Module::Build (a.k.a. MB)


Особенности:
  • для работы достаточно perl, не нужен ни make ни знание как писать  портабельный Makefile
  • нет поддержки графа зависимостей (что от чего зависит при сборке)
  • убирают из core (модулей распространяемых вместе с perl) — что ни на что  не повлияет (спасибо configure_requires), но вызвало волну  FUD; на самом деле никаких новых  причин его избегать не появилось, и если старые причины вас не  останавливали — то продолжайте спокойно им пользоваться и дальше

Недостатки:
  • слишком большой и сложный, никто не хочет его поддерживать и развивать
  • из-за архитектуры схожей с EUMM (для расширения нужно писать код,  который будет использоваться для генерации другого кода, который уже  будет выполняться) у него та же проблема — сложно писать плагины и  сложно подключать одновременно несколько плагинов (недавно появился  Module::Build::Pluggable,  который пытается решить вторую половину этой проблемы)

Достоинства:
  • использовать и, в небольших объёмах, расширять значительно проще, чем  EUMM

Module::Install (a.k.a. MI)


Особенности:
  • обёртка над EUMM

Недостатки:
  • пытался решить проблему отсутствия в то время configure_requires копируя  себя и все необходимые ему для сборки текущего модуля плагины в inc/ -  что, в свою очередь, создало новые проблемы (а сейчас и вовсе потеряло  смысл) — от необходимости перевыпускать свой модуль для исправления бага  в идущей в комплекте с ним версии MI до неудобств при использовании VCS  из-за того, что в репозитории постоянно обновляется код относящийся к MI

Достоинства:
  • простой и наглядный интерфейс

Несмотря на единодушную нелюбовь сообщества к EUMM и Module::Build, у меня сложилось впечатление что Module::Install в последнее время вообще перестали воспринимать всерьёз — создаваемые им время от времени проблемы перевесили его достоинства.

Module::Build::Tiny (a.k.a. MBT)


Особенности:
  • эксперимент, показавший что можно сделать систему сборки на перле  достаточную для большинства модулей всего в 120 строчках кода

Ваш Build.PL выглядит так:

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

Как ни странно, но этим даже можно пользоваться — используя файл cpanfile для управления зависимостями и вспомогательную утилиту mbtiny для авторинга (генерации Build.PL, MANIFEST и META.{json,yml}, подготовки архива с модулем — того, что делал Module::Build и что не относится к процессу сборки модуля). Либо использовать Dist::Zilla вместо mbtiny (кстати, Dist::Milla и Minilla используют MBT — для таких навороченных систем как раз очень удобно, когда система сборки делает только своё дело и не берёт на себя «лишние» задачи).

Управление зависимостями / Dependencies


cpanfile


Это подход, при котором зависимости указываются отдельно от системы сборки, в файле cpanfile. Есть несколько причин это делать:

  • Если вы используете разные системы сборки в разных модулях, то  использование cpanfile позволит забыть об отличиях синтаксиса (и  ограничениях — EUMM и Module::Install пока не полностью поддерживают  CPAN::Meta::Spec 2.0) разных  систем сборки и использовать один формат для всех (кстати,  совместимый с форматом Module::Install).
  • Этим же способом можно задавать зависимости не только для перл-модулей,  но и для обычных приложений (у которых обычно нет Makefile.PL или  Build.PL и зависимости указывать просто негде) — собственно, именно  ради этой возможности cpanfile и был разработан. Причём можно задать для  отдельной зависимости альтернативный источник, откуда её брать — из  приватного CPAN mirror, из git, etc.
  • Можно устанавливать все зависимости через cpanm --installdeps . или  carton без META.{json,yml} файлов.
  • При использовании Module::Install можно не держать в репозитории inc/  и META.{json,yml} и корректно указывать зависимость от Module::Install  как «develop» (author_requires) а не «configure» (configure_requires).  При этом другие разработчики, у которых не установлен Module::Install,  смогут его установить через cpanm --with-develop --installdeps . или  carton.

Управление версиями / VCS


В случае перл-модулей нужно иметь в виду, что в репозитории нужно, с одной стороны, хранить все необходимые для сборки модуля файлы (чтобы его можно было устанавливать прямо из репозитория через cpanm и чтобы после форка другие разработчики получили рабочую версию проекта), а с другой избежать замусоривания его лишними авто-генерируемыми файлами (например, файлами Module::Install в inc/) — вам ведь их commit-ить постоянно, плюс они будут замусоривать diff, etc. Особенно это касается пользователей Dist::Zilla — если вы хотите получать pull-request-ы то не стоит требовать чтобы желающие пофиксить вам какую-то мелочь были вынуждены устанавливать 150-200 дополнительных модулей для запуска сборки проекта.

GitHub


При использовании GitHub вам скорее всего придётся либо писать дополнительное описание модуля в README.md, либо настроить автоматическую генерацию этого файла из POD-документации модуля. И во втором случае может потребоваться добавлять дополнительные элементы - например, статус сборки проекта в Travis CI.

Непрерывная интеграция / CI


CPAN Testers


До апреля 2013 CPAN Testers не поддерживал отдельное указание test_requires (зависимостей необходимых только для запуска тестов). При этом системы сборки уже давно давали возможность их указывать… но это не работало. В результате некоторые разработчики модулей сильно огорчались, выпускали новую версию без всяких умных test_requires и забывали про эту фичу. Так вот, уже можноПодробности поддержки test_requires разными версиями систем сборки.

В принципе, сервис CPAN Testers покрывает основные потребности, но у него есть один недостаток: тестирование происходит уже после релиза. Чтобы прогнать модуль через CPAN Testers до релиза нужно выпускать специальные alpha-версии — и всё-равно это релиз, да и работает CPAN Testers не так уж быстро.

GitHub + Travis CI


Подключив к репозиторию с модулем на GitHub Travis CI можно автоматизировать тестирование текущей версии модуля до релиза на нескольких версиях perl (хоть это и не так круто в плане разных платформ как CPAN Testers, но всё-таки лучше, чем запускать тесты только у себя на машине).

Выпуск / Release


App::scan_prereqs_cpanfile


Предоставляет команду scan-prereqs-cpanfile для анализа зависимостей модуля и генерирования cpanfile или вывода отличий от текущего cpanfile (если он модифицировался вручную и просто сгенерировать его заново это не лучшая идея).

Perl::Version


Предоставляет команду perl-reversion для изменения номера версии в (почти) всех файлах модуля.

Поддерживает README, но не README.md.

CPAN::Uploader


Предоставляет команду cpan-upload для заливания модулей на CPAN из командной строки. Конфиг-файл ~/.pause с логином/паролем для PAUSE может быть зашифрован GnuPG.

GitHub


К сожалению, GitHub пока не умеет автоматически заливать перл-модули на CPAN (хотя, наверное, технически правильнее будет сказать, что это CPAN не умеет выкачивать модули с GitHub) при добавлении тега для новой версии (как это происходит, например, с плагинами для jQuery). Но я всё-равно оставлю этот пункт здесь, вдруг его увидят нужные люди и добавят фичу.

Поддержка / Support


CPAN RT


Баг-трекер CPAN много лет был единственным доступным вариантом. Учитывая его неудобный интерфейс это было очень печально. С другой стороны, им можно пользоваться даже если вы не используете VCS при разработке модуля.

К счастью, сейчас есть возможность указать в META.{json,yml} (не ручками, конечно, а через используемую систему сборки) альтернативный баг-трекер (например на GitHub). К сожалению, хотя при этом изменятся ссылки на баг-трекер на сайтах CPAN и MetaCPAN, это не отключит возможность добавлять тикеты для вашего модуля на CPAN RT (но там показывается уведомление, что предпочитаемый баг-трекер в другом месте). Разумеется, после изменения баг-трекера текущие баги остаются в RT.

GitHub


Не буду описывать преимущества и удобство поддержки проектов на GitHub (особенно бросающиеся в глаза по сравнению с CPAN RT). Тем более, что даже если не нравится Git, то можно без проблем локально работать с Mercurial и всё-равно держать проект на GitHub (через плагин hg-git).

Если вы захотите переместить текущие тикеты из CPAN RT в GitHub Issues - можете попробовать воспользоваться rt-to-github.pl или этой модификацией его старой версии.

Авторинг / Authoring


В этом разделе будут описаны утилиты полностью берущие на себя процесс авторинга модулей, зачастую используя при этом вышеописанные утилиты решающие отдельные подзадачи авторинга.

У меня есть два сервера, один только что установлен, там всего 27 CPAN-модулей, на втором много лет разрабатывается много перл-проектов, там установлено 248 CPAN-модулей. Я подсчитал, сколько приходится установить дополнительных CPAN-модулей на каждом из серверов для описанных в этом разделе утилит:

  • Dist::Zilla (без дополнительных плагинов) требует 162 модуля на первом и  83 на втором сервере.
  • Dist::Milla (фактически, подборка плагинов для Dist::Zilla) требует 257  и 166 модулей.
  • Minilla (которая декларирует минимум зависимостей как одно из основных  преимуществ) — 126 и 41 модуль.
  • ShipIt — 1 и 1.
  • App::ModuleBuildTiny — 8 и 6.

Dist::Zilla


Это настоящий монстр. Он делает всё! На CPAN сейчас порядка 900 модулей входящих в 480 дистрибутивов расширяющих возможности Dist::Zilla. Из этих 480 дистрибутивов 315 это плагины (Dist::Zilla::Plugin::*), и ещё 100 - разные подборки этих плагинов (Dist::Zilla::PluginBundle::*).

Есть только две проблемы: сколько дней нужно потратить, чтобы он начал делать то, что нужно лично вам, и количество модулей, которые требуется установить чтобы им воспользоваться.

По первой проблеме — ничего не могу сказать. Я не рискнул связываться и пытаться его настроить под себя. Кто это сделал — поделитесь впечатлениями в комментариях.

Вторая проблема тоже достаточно важна — если вы хотите получать патчи и pull-request-ы к своему модулю, необходимо, чтобы желающие внести в него изменения могли сделать это достаточно просто. Если им для исправления пары строк нужно будет установить половину CPAN (автор утверждает что не половину, а всего 0.6%) и разбираться с нестандартным процессом сборки - патч вы не дождётесь.

Dist::Milla


Особенности:
  • просто подборка плагинов для Dist::Zilla и утилита-обёртка
  • используется лицензия Perl, для изменения замените её другой в POD
  • нет автоматического определения и обновления зависимостей, их нужно  описывать вручную в cpanfile
    • можно воспользоваться scan-prereqs-cpanfile --diff=cpanfile чтобы  быстро найти все новые подключенные модули, которые ещё не добавлены в  cpanfile
  • можно выбрать какая система сборки будет использоваться:  Module::Build::Tiny (по умолчанию), Module::Build или EUMM, но я не  уверен, что можно воспользоваться всеми возможностями выбранной системы  сборки — Build.PL редактировать смысла нет, он при каждой сборке  генерируется заново

Недостатки (по сравнению с Dist::Zilla):
  • ещё большее количество зависимостей, которые нужно установить… но это, в  значительной мере, компенсируется тем, что можно сэкономить несколько  дней на составление своей подборки плагинов, которая ещё не факт что  оказалась бы меньше
    • впрочем, как только захочется добавить новую фичу, например вывод  badge с отчётом Travis CI в README.md — всё-равно нужно будет искать и  подключать  дополнительный  плагин Dist::Zilla
  • вроде бы XS-модули не поддерживаются (вероятно, нужно будет подключать  дополнительный плагин)

Достоинства:
  • многие популярные плагины Dist::Zilla модифицируют код и/или  документацию модуля (или зависят от плагинов, которые это делают),  заставляя вас изменять свой рабочий процесс — таких плагинов в  Dist::Milla принципиально нет: ваш код и документацию изменяете только  вы сами (исключая обновление $VERSION при релизе)
    • вместо того, чтобы изменять код/документацию на основании заданных  мета-данных, Dist::Milla работает в обратном направлении, вычисляя  мета-данные на основании кода, документации и репозитория — как это  всегда делали системы сборки вроде Module::Install или Module::Build
  • в отличие от большинства модулей использующих Dist::Zilla, в разработке  модулей использующих Dist::Milla могут легко участвовать сторонние  разработчики — им не нужно устанавливать себе Dist::Zilla или  разбираться с нестандартным процессом сборки, ваш модуль выглядит,  собирается, тестируется и устанавливается как все обычные модули
    • в частности, ваш модуль можно устанавливать прямо из GitHub
  • нет необходимости тратить несколько дней на подбор и настройку своего  набора плагинов для Dist::Zilla, можно начать сразу использовать  достаточно неплохой стартовый набор, и в дальнейшем его модифицировать  по мере необходимости
  • поддержка миграции существующего модуля использующего другую систему  сборки или авторинга на Dist::Milla

Minilla


Особенности:
  • работает практически идентично Dist::Milla с настройками по умолчанию

Недостатки:
  • практически не настраивается

Достоинства:
  • совместим со стандартным процессом сборки/установки модуля
  • не использует Dist::Zilla
  • значительно меньше зависимостей, чем у Dist::Milla
  • поддерживает XS
  • поддержка миграции существующего модуля использующего другую систему  сборки или авторинга на Minilla

Если вы делаете авторинг практически так же, как Tokuhiro Matsuno (автор Minilla), либо если вам всё-равно как именно делается авторинг, главное чтобы всё работало само из коробки достаточно современным образом (т.е. с использованием git и GitHub) и не требовало установки дикого количества модулей — Minilla вам идеально подойдёт. Если же потребуется что-то делать иначе — придётся искать ему замену (вероятнее всего ей окажется Dist::Milla).

ShipIt


Позволяет одной командой shipit выполнить большинство операций, требуемых при выпуске новой версии.

В каталоге модуля создаётся файл .shipit, примерно такой:

steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN

и теперь при запуске shipit будут выполнены указанные в .shipit операции:

  1. у вас спросят номер новой версии
  2. новая версия пропишется в коде модуля
  3. проверит наличие записи в Changes и предложит её добавить
  4. запустит тесты (поддерживает Makefile.PL и Build.PL)
  5. сделает commit (поддерживает Git/Mercurial/SVN)
  6. добавит tag для новой версии
  7. подготовит архив с модулем
  8. зальёт архив на 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.

Резюме


  • если нет острой необходимости поддерживать старые версии перла, на мой  взгляд, в модулях стоит по умолчанию использовать use 5.010001;
  • версию задавать используя формат our $VERSION="v1.2.3";
    • соответствовать спецификации семантического версионирования настолько,  насколько возможно в перле
    • для альфа-версий добавлять после версии в имени архива с модулем  "-TRIAL" вместо использования подчёркиваний в номере версии
  • в качестве системы сборки использовать Module::Build::Tiny или  Module::Build (только если не хватает возможностей MBT)
  • для управления зависимостями использовать cpanfile
  • держать модуль на GitHub, указать ссылки на GitHub в META.json
    • использовать Travis CI

Что же касается выбора утилиты для авторинга — здесь сложно дать однозначную рекомендацию. Если выбирать среди не заброшенных:

  • Minilla, если работа по умолчанию устраивает и нет потребности как-то  его настраивать
  • Dist::Milla, если нравится Minilla но хочется что-то настроить, либо  хочется начать использовать Dist::Zilla с достаточно адекватной и  документированной подборки плагинов
  • App::ModuleBuildTiny, если хочется быстро сделать свой велосипед,  простой и достаточно гибко настраиваемый

Разные полезности для авторов модулей



______________________
Текст конвертирован используя habrahabr backend для AsciiDoc.
Tags:
Hubs:
+16
Comments 34
Comments Comments 34

Articles