Alexei ZnamenskyPublicado em 01/03/2011
A manutenção de um módulo Perl é cheia de tarefas repetitivas: configurar
o Makefile.PL
, atualizar documentação, atualizar versão de dependências,
copiar as mais diversas suítes de testes para a árvore, formatar o código,
"commitar" o código do controle de versão - eventualmente aplicar tags
nesse controle de versão e, por fim, fazer o upload do módulo para o
PAUSE[1], e de lá para o
CPAN[2].
Especificamente do ponto de vista de documentação, há a chata tarefa de
atualizar a versão do módulo em todos os arquivos que fazem parte dele -
se forem muitos, a chateação também será muita.
Adicionar seções com informações "repetidas", como AUTHOR, LICENSE,
SUPPORT, entre outras, é também algo repetitivo e sujeito a erros bobos
se feito manualmente. Alguns módulos fornecem um arquivo README
que é a
renderização em texto do POD do arquivo principal do módulo - também é uma
tarefa que poderia ser facilmente automatizada.
Por fim, quando estamos trabalhando em equipe, precisamos ter um maior cuidado com o sistema de controle de versões, criando branches específicos para times e/ou tarefas específicas, e realizando o merge dos mesmos depois. O sistema de controle de versão que, se ainda não é, está se tornando o mais popular na comunidade Perl (e de outras linguagens também) é o git[3], software originalmente escrito pelo próprio Linus Torvalds[4].
As principais vantagens do git são:
Em Maio de 2008(?)[7], Ricardo Signes, (RJBS), desenvolvedor norte-americano, membro atuante da comunidade Perl, contribuidor do CPAN, com dezenas de módulos[8] publicados, começou um projeto ambicioso, o Dist::Zilla[9]. O Dist::Zilla, como descrito em seu site[10], é um "programa para facilitar a escrita, o empacotamento, o gerenciamento e a publicação de software livre". Para nós programadores e batalhadores cotidianos, isso significa: menos tempo gasto com códigos, arquivos e configurações boilerplate, e mais tempo disponível para dedicar-se à codificação propriamente dita. Naturalmente, aqui, estamos falando de Perl - iremos usar o Dist::Zilla para escrever módulos e/ou aplicativos em Perl.
Este artigo não pretende ser um guia completo sobre o Dist::Zilla. Para uma documentação mais abrangente, sugerimos ler os tutoriais do Dist::Zilla[11]. Vamos mostrar aqui o básico, e um pouco além.
O Dist::Zilla permite várias ações. Para executar essas ações, usamos a
aplicação de linha de comando que vem com o Dist::Zilla, que é o comando
dzil
. Alguns dos usos mais freqüentes:
Para executar toda a suíte de testes do módulo:
$ dzil test
[DZ] building test distribution under .build/nQGOr0w7RL
...
Para gerar um build (tar-ball) do módulo:
$ dzil build
...
Para fazer um release: build, (opcionalmente) rodar todos os testes e, (idem) fazer o upload do módulo para o CPAN:
$ dzil release
...
O Dist::Zilla é controlado pelas configurações em arquivos ".ini", tanto para configurações do usuário quanto para configurações do projeto.
Para poder ter o Dist::Zilla funcionando, você deve, antes de mais nada, instalá-lo:
$ cpan Dist::Zilla
Uma vez que o cpan
termine a instalação, você terá disponível o comando
dzil
no seu shell. É preciso então fazer um setup do Dist::Zilla:
dzil setup
Esse comando irá gerar um arquivo ~/.dzil/config.ini
, contendo as
informações solicitadas. Por exemplo:
[%User]
name = Alexei Znamensky
email = russoz@cpan.org
[%Rights]
license_class = Perl_5
copyright_holder = Alexei Znamensky
Note que o dzil setup
perguntará sobre usuário e senha do CPAN. Caso você
escolha por colocar essa informação no Dist::Zilla, ela estará presente no
config.ini
. Opcionalmente você pode colocar essa informação separadamente
no arquivo ~/.pause
:
user russoz
password p0t@toe5
Você não é obrigado a ter essa informação em nenhum desses arquivos, isso é estritamente opcional, mas, naturalmente, não será possível fazer o upload automático do módulo para o CPAN sem esses dados.
Com isso você já está pronto para usar o Dist::Zilla no seu módulo.
Vamos exemplificar o uso do Dist::Zilla com a conversão de um módulo, pois fica mais fácil de visualizar o que substitui o quê. Esta seção é adaptada do tutorial escrito pelo próprio RJBS sobre conversão de um módulo[12].
No começo deste ano este autor que aqui escreve se tornou co-mantenedor do módulo Queue::Base[13]. Além de alguns ajustes no código do módulo, o Queue::Base foi utilizado como cobaia para a conversão para Dist::Zilla.
Para começarmos a utilizar o Dist::Zilla, precisamos criar, no diretório raiz
da distribuição/módulo/aplicação, um arquivo dist.ini
.
Basicamente os passos para conversão foram:
O Makefile.PL
continha o seguinte código:
use inc::Module::Install;
name 'Queue-Base';
all_from 'lib/Queue/Base.pm';
author q{Alexei Znamensky };
license 'perl';
requires 'version' => 0.77;
build_requires 'Test::More';
auto_install;
WriteAll;
Esse arquivo pode ser removido. Não será mais necessário.
Ao invés dele, teremos um dist.init
:
name = Queue-Base
version = 2.0_2
author = Farkas Arpad
author = Alexei Znamensky
license = Perl_5
copyright_holder = Alexei Znamensky
[GatherDir]
[MetaYAML]
[ModuleInstall] <<<<<<<<< AQUI
[Manifest]
...
Um dist.ini
irá conter tags de seções e definições, como
informações sobre o módulo e o autor.
Notem nesse trecho anotado do
primeiro dist.ini
do Queue::Base[14],
que colocamos uma tag de seção na qual especificamos o uso do
Module::Install[15].
Todas essas tags de seções (com exceção aos que começarem com "@" e outros
que contém uma barra "/"), correspondem a classes no namespace
Dist::Zilla::Plugin::
, isto é, no trecho acima estamos referenciando as
classes:
Dessas quatro classes[16][17][18][19], Dist::Zilla::Plugin::ModuleInstall não faz parte do próprio Dist::Zilla, ela foi desenvolvida por Kent Fredric[20].
Existem vários plugins prontos, para realizar uma infinidade de diferentes tarefas[21]. Destacamos aqui alguns dos mais importantes (na opinião desde autor):
[GatherDir] - lista os arquivos
[Manifest] - gera arquivo MANIFEST
[Readme] - gera arquivo README
[License] - gera arquivo LICENSE
[MakeMaker] - gera um Makefile.PL (ExtUtils::MakeMaker)
[ModuleInstall] - idem (Module::Install)
[ModuleBuild] - gera um Build.PL (Module::Build)
[PreReqs] - permite especificar dependências
[AutoPrereqs] - detecta dependências automaticamente
[PodVersion] - acrescenta VERSION a cada arquivo .pm
[OurPodVersion] - idem, usando our $VERSION
A lista completa seria finita, mas enorme. Para facilitar um pouco a nossa
vida, existem os bundles, que agrupam vários plugins em uma única
seção. O mais imediato é o Basic
, que é fornecido pelo próprio Dist::Zilla.
Para usá-lo, basta colocar no dist.ini
:
[@Basic]
Esse bundle é definido na classe Dist::Zilla::PluginBundle::Basic[22], e
corresponde aos plugins: [GatherDir]
, [PruneCruft]
, [ManifestSkip]
,
[MetaYAML]
, [License]
, [Readme]
, [ExtraTests]
, [ExecDir]
,
[ShareDir]
, [MakeMaker]
, [Manifest]
, [TestRelease]
,
[ConfirmRelease]
, [UploadToCPAN]
.
Utilizando o [@Basic]
podemos (devemos!) remover os arquivos:
README
, LICENSE
, MANIFEST
e, se estivermos usando o
[ModuleInstall]
, podemos também remover o diretório inc/
- ele será
gerado automaticamente durante o build com os arquivos necessários.
Alguns dos plugins utilizados podem não estar instalados. Para saber quais plugins você precisa instalar, basta rodar:
dzil authordeps
É possível criar novos bundles, e é uma prática comum que os autores criem bundles com seus grupos de plugins prediletos.
Existem plugins que realizam a mesma tarefa que algum plugin que já faz
parte de um bundle que esteja em uso. Nesse caso, o plugin declarado no
bundle será ignorado e o plugin declarado no dist.ini
será utilizado.
A escolha do conjunto de plugins a utilizar depende de muitas coisas, mas o fator decisivo é a preferência do desenvolvedor.
Vamos colar aqui o dist.ini
atual do projeto Queue::Base e comentar
cada trecho.
name = Queue-Base
version = 2.200
author = Alexei Znamensky
license = Perl_5
copyright_holder = Farkas Arpad
Várias informações específicas do projeto: nome, autor, tipo de licença, etc.. Particularmente, o número da versão poderia ser automatizado, e será algum dia para o Queue::Base - mas enquanto isso não ocorre, ele continua sendo declarado aqui. Essas informações podem depois ser utilizadas para gerar documentação POD automaticamente.
[MetaResources]
bugtracker.web = http://github.com/russoz/Queue-Base/issues
repository.web = http://github.com/russoz/Queue-Base
repository.url = git://github.com/russoz/Queue-Base.git
repository.type = git
Meta-informações sobre o probjeto, como por exemplo o endereço da index.tpage, onde reportar erros, o repositório de controle de versões.
[@Basic]
[MetaJSON]
[ReadmeFromPod]
[InstallGuide]
[GitFmtChanges]
max_age = 365
tag_regexp = ^.*$
file_name = Changes
log_format = short
Usando a tag [@Basic]
incluímos todos aqueles plugins
listados acima, mas também:
[MetaJSON]
Escolhemos gerar também um arquivo META.json
com as meta-informações do
pacote para indexação no CPAN;
[ReadmeFromPod]
Geramos o arquivo README
automaticamente a partir do POD do arquivo
principal do módulo (no caso do Queue::Base, seria o arquivo
lib/Queue/Base.pm
);
[InstallGuide]
Geramos um arquivo INSTALL
com instruções de instalação (de acordo com o
builder utilizado: MakeMaker, Module::Install ou Module::Build);
[GitFmtChanges]
Geramos o arquivo Changes
com a listagem das modificações realizadas no
projeto, a partir dos logs do git.
[OurPkgVersion]
Optamos por utilizar a tag [OurPkgVersion]
para inserir o número
de versão nos arquivos, tanto em código (our $VERSION = x.yz
) quanto em
POD (=head1 VERSION
).
[PodWeaver]
Ao utilizar o [PodWeaver]
no Dist::Zilla, estamos na verdade
utilizando o Pod::Weaver[23] para gerar trechos da documentação em formato POD.
Este artigo pretendia, em sua incepção explanar mais sobre o Pod::Weaver, mas
decidimos nos manter somente com o Dist::Zilla para não virar um livro. Entre
outras coisas, podem ser atualizadas automaticamente no POD dos arquivos as
seções: NAME
(com descrição, em formato padrão), VERSION
, AUTHOR
,
COPYRIGHT & LICENSE
, SUPPORT
(com informação sobre Perldoc, websites),
AVAILABILITY
, DISCLAIMER OF WARRANTY
. O Pod::Weaver possui um arquivo
de configuração específico, o weaver.ini
. Veja o
weaver.ini
[24]
utilizado no Queue::Base, para exemplo.
[AutoPrereqs]
O jeito mais simple é utilizar o [AutoPrereqs]
, que irá
percorrer os seus arquivos levantando as dependências. Naturalmente pode haver
pequenas divergências, ou podemos querer forçar uma versão mínima específica
de algum módulo. Para esses e outros casos, podemos usar a tag [Prereqs]
,
declarando explicitamente as versões necessárias.
[PerlTidy]
Incluindo a tag [PerlTidy]
no seu dist.ini
, você terá a
garantia de que o código do seu módulo será formatado de uma maneira
consistente ANTES do empacotamento. Você pode usar as definições padrão do
Perl::Tidy[25] ou pode fornecer o seu próprio perltidyrc
.
[@Git]
O bundle [@Git]
, criado por
Jerome Quelin[26], engloba os plugins:
[Git::Check]
, [Git::Commit]
, [Git::CommitBuild]
, [Git::Init]
,
[Git::NextVersion]
, [Git::Push]
, [Git::Tag]
. Obviamente, com ele
podemos automatizar várias atividade relacionadas ao git, das quais
destacam-se a "checagem" (se houver arquivos não "commitados" no git,
ele irá interromper o release), a aplicação de tag com o número da
versão, e o push automático para o repositório remoto. Similarmente,
existem plugins para o Subversion[27] e
o Mercurial[28].
[ReportVersions]
[CompileTests]
[EOLTests]
[PodCoverageTests]
[UnusedVarsTests]
[CriticTests]
[HasVersionTests]
[KwaliteeTests]
[MetaTests]
[PodSyntaxTests]
Podemos incluir testes padronizados de código, compilação, documentação e
estilo, adicionando tags no dist.ini
, como pode ser visto acima. Duas
das principais vantagens são: não termos de copiar arquivos de teste
manualmente e não termos de mantê-los atualizados (sempre que fazemos o
release são utilizadas as versões atuais (presumindo que mantemos nossa
instalação atualizada) dos módulos.
Ainda existe espaço para várias melhorias, e para vários plugins, o Dist::Zilla é um projeto em andamento. Mas é uma ferramenta indispensável para um desenvolvedor em Perl Moderno, que não pode ou não tem mais tempo para ficar repetindo as mesmas tarefas "burocráticas" a cada novo módulo.
O Dist::Zilla é uma fantástica ferramenta de apoio. Ela facilita o processo de desenvolvimento, testes, release, e até mesmo o de documentar seu código. E o melhor é que você não precisa jogar fora tudo o que tem pronto para começar a usá-lo: a conversão pode ser feita de forma gradual.
[1] PAUSE - The [Perl programming] Authors Upload Server - http://pause.perl.org/
[2] CPAN - Comprehensive Perl Archive Network - http://www.cpan.org
[3] GIT - The fast version control system - http://git-scm.com
[4] Linus Torvalds - Artigo na Wikipedia - http://en.wikipedia.org/wiki/Linus_Torvalds
[5] github - social coding - http://github.com
[6] git/git - repositório do git - https://github.com/git/git
[7] Dist::Zilla - primeiro commit? - https://github.com/rjbs/dist-zilla/commit/f3854f7c675a11c6b3832dc111f72e6d705c09fa
[8] Ricardo Signes - Módulos no CPAN - http://search.cpan.org/~rjbs/
[9] Dist::Zilla - "distribution builder; installer not included!" - http://search.cpan.org/perldoc?Dist::Zilla
[10] Dist::Zilla - index.t Page - http://dzil.org/
[11] Dist::Zilla - Tutorials - http://dzil.org/tutorial/start.html
[12] Dist::Zilla - "Converting a Dist to Dist::Zilla" - http://dzil.org/tutorial/convert-dist.html
[13] Queue::Base - "Simple OO style queue implementation" - http://search.cpan.org/perldoc?Queue::Base
[14]
Queue::Base/dist.ini - primeira versão do dist.ini
no Queue::Base - https://github.com/russoz/Queue-Base/blob/3702c381595c0dfa6e7644bd945987b95af2e20c/dist.ini
[15] Module::Install - "Standalone, extensible Perl module installer" - http://search.cpan.org/perldoc?Module::Install
[16] Dist::Zilla::Plugin::GatherDir - "gather all the files in a directory" - http://search.cpan.org/perldoc?Dist::Zilla::Plugin::GatherDir
[17] Dist::Zilla::Plugin::MetaYAML - "produce a META.yml" - http://search.cpan.org/perldoc?Dist::Zilla::Plugin::MetaYAML
[18] Dist::Zilla::Plugin::ModuleInstall - "Build Module::Install based Distributions with Dist::Zilla" - http://search.cpan.org/perldoc?Dist::Zilla::Plugin::ModuleInstall
[19] Dist::Zilla::Plugin::Manifest - "build a MANIFEST file" - http://search.cpan.org/perldoc?Dist::Zilla::Plugin::Manifest
[20] Kent Frederic - Módulos no CPAN - http://search.cpan.org/~kentnl/
[21] CPAN - Search "Dist::Zilla::Plugin" - http://search.cpan.org/search?query=Dist::Zilla::Plugin&mode=all
[22] Dist::Zilla::PluginBundle::Basic - "the basic plugins to maintain and release CPAN dists" - http://search.cpan.org/perldoc?Dist::Zilla::PluginBundle::Basic
[23] Pod::Weaver - "weave together a Pod document from an outline" - http://search.cpan.org/perldoc?Pod::Weaver
[24]
Queue::Base/weaver.ini - exemplo de arquivo weaver.ini
- https://github.com/russoz/Queue-Base/blob/master/weaver.ini
[25] Perl::Tidy - "Parses and beautifies perl source" - http://search.cpan.org/perldoc?Perl::Tidy
[26] Jerome Quelin - Módulos no CPAN - http://search.cpan.org/~jquelin/
[27] Subversion - "Enterprise-class centralized version control for the masses" - http://subversion.apache.org/
[28] Mercurial - "Mercurial is a free, distributed source control management tool. It efficiently handles projects of any size and offers an easy and intuitive interface" - http://mercurial.selenic.com/
Pelo Dist::Zilla e pela sua prestatividade.
Pelo companheirismo, pelas infinitas risadas, pela dedicação com que todos zelam pela nossa linguagem de programação predileta.
Obrigado pelo olho clínico, revisando este artigo.
Alexei "Russo" Znamensky < russoz no cpan org >
O fonte deste artigo encontra-se disponível em:
https://github.com/russoz/artigos/tree/master/2011/03-sppm-equinocio/distzilla
Este texto está licenciado sob os termos da Creative Commons by-sa, http://creativecommons.org/licenses/by-sa/3.0/br/