Olá pessoal, como estou estudando bastante sobre Buildout para uma apresentação no NSI Tech Talk, decidi escrever um post sobre ele. Então vamos começar!
Buildout
#1 : O que é?
Buildout é um um sistema feito em Python para criação, montagem e deploy de aplicações de múltiplas partes, que podem até serem feitas em outras linguagens. Com ele é possível criar uma configuração de buildout para que o mesmo software instalado em uma máquina seja reproduzida em outras sem problemas. Isso tudo ainda dentro de um ambiente completamente isolado do restante do seu sistema. Os pacotes são instalados localmente na pasta do buildout e ainda faz com que esses pacotes sejam carregados adequadamente pelo seu projeto.
Grandes projetos, zope, plone, django, grok, pylons, por exemplo, usam o buildout como ferramenta principal para distrubuir e gerenciar seu software.
“Buildout is an exceedingly civilized way to develop an app.” – Jacob Kaplan-Moss, creator of Django
#2: Tá, agora me dê um exemplo de uso disso tudo ai?
Suponhamos que você possui um grande projeto (feito em Python e open-source, claro). E esse projeto possui muitas, mas MUITAS dependências. Além de um processo de instalação bastante complicado. E um belo dia, um grande profissional da área resolve contribuir com o seu projeto. Ele acessa o repositório do código, faz o download do fonte e quando ele lê o README para saber como se instala o projeto ele se depara instruções muito complicadas. Então esse possível grande contribuidor decide abandonar o projeto visto as grandes dificuldades em apenas instalar o projeto em sua máquina.
Isso não seria muito legal né?
Se você tivesse um buildout esse contribuidor teria o projeto instalado e totalmente configurado, assim como todas as dependências devidamente instaladas em sua máquina, com a execução de apenas um comando:
bin/buildout
E o uso do Buildout não é plausível somente para esse caso. Em QUALQUER projeto, por menor que seja, você não quer gastar mais tempo para criar um tutorial ou script para instalação do seu projeto do que com o desenvolvimento do mesmo né?
E se você for um agilista (como eu \o/) e precisar de um deploy contínuo? Teria que fazer essa instalação chata frequentemente. E ainda sujar o seu sistema instalando coisas que não são necessárias para seu funcionamento básico. Como já disse o Guilherme, da Caelum, no Maré de Agilidade: “Você precisa fazer algo frequentemente? AUTOMATIZE JÁ!”
#3: Isso é muito útil! Mas como eu começo a utilizar isso no meu projeto?
Começar a utilizar o Buildout é fácil simples! Você não precisará nem instalar o Buildout propriamente dito no sistema. Ta achando que eu to zuando é? Preste atenção ai querido leitor. Vamos criar um buildout simples que baixará um egg direto do PyPi e rodará um código dependente dele.
Primeiro, vamos baixar um script chamado bootstrap.py que é encarregado de criar a estrutura básica necessária para o Buildout funcionar e um arquivo de configuração vazio.
wget http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py
Agora, crie um arquivo chamado buildout.cfg, preenchido da seguinte maneira:
[buildout]
parts = should_dsl create_dir
develop = .
[should_dsl]
recipe = zc.recipe.egg:eggs
eggs = should_dsl
[create_dir]
recipe = recipes:create_dir
dir = testando
Aquela primeira seção chamada ‘buildout’ é a seção principal e que deve existir em todo buildout.cfg. Ali definimos as ‘partes’ que compoem o nosso buildout. No caso definimos uma parte chamada should_dsl e outra chamada create_dir. Definimos também a variável ‘develop’ que diz para o buildout aonde estará o codigo fonte do projeto que estamos utilizando. O ‘.’ indica que o projeto estará dentro da raiz do buildout.
Logo abaixo, definimos a seção ‘should_dsl’ que será chamada pela parte ‘should_dsl’ definida anteriormente. Dentro dela definimos qual recipe será executado. No caso utilizaremos o zc.recipe.egg. Este recipe instala eggs diretamente do PyPi. E dizemos para ele instalar a variável eggs, que logo abaixo recebe ‘should_dsl’.
Na seção ‘create_dir’ utilizaremos o recipe ‘recipes:create_dir’ que seria uma “receita” que fará algo no projeto. Ele diz que usaremos o modulo ‘create_dir’ do pacote ‘recipes’. E setamos a variável ‘dir’, que representa o nome do diretório a ser criado como ’testando’. Simples, certo?
Agora, criaremos o nosso create_dir.py.
from subprocess import call
from should_dsl import *
class CreateDir:
def __init__(self, buildout, name, options):
self.buildout = buildout
self.name = name
self.options = options
def install(self):
call('mkdir %s' % self.options.get('dir'), shell=True)
update = install
Na primeira linha importamos a função call do modulo subprocess. Que será usada futuramente. Depois importamos o modulo should_dsl, só para ter certeza que o mesmo foi instalado. Então em seguida criamos uma classe chamada CreateDir. O seu método __init__ receberá três parâmetros: o buildout, seu nome e as opções, que são as variáveis definidas dentro da seção corresponde. Definimos logo abaixo o método install. Ele é chamado somente na primeira execução do nosso script. Esse método utiliza a função call para executar um mkdir com o nome da variável ‘dir’, definida no buildout.cfg, dentro de um shell.
A linha update = install diz que o método update será idêntico ao install. Esse método será chamado a partir da primeira execução do nosso script.
Calma pessoal, estamos quase lá!
Agora criaremos um setup.py para o nosso projeto (o recipe).
from setuptools import setup
setup(name="recipes",
version="0.0.1",
py_modules=['create_dir',],
entry_points={'zc.buildout': ['create_dir = create_dir:CreateDir',]},
install_requires = 'should_dsl', )
Definimos um pacote chamado recipes. A versão não importa. Então dizemos que o módulo ‘create_dir’ terá um entry_point do buildout chamado ‘create_dir’ que será chamado também ‘create_dir’ e pertence à classe CreateDir. E também dizemos que o pacote should_dsl é uma dependência do projeto, para que o buildout instale-o e torne-o visível ao nosso recipe.
Agora está tudo pronto! Rode o bootstrap.py com seu interpretador de python. Detalhe: o mesmo interpretador será usado pelo buildout todo, ou seja, se seu projeto precisa ser rodado com o python 2.4 então use o interpretador correspondente.
Após rodar bootstrap.py temos toda a estrutura básica do buildout montada. Agora execute o buildout:
bin/buildout
Note que após a execução do programa uma pasta chamada ‘testando’ é criada dentro da raiz do buildout. Isso indica que nosso buildout rodou com sucesso!
#4: Só isso?
Não! O poder do Buildout depende apenas da sua criatividade! É possível, por exemplo, ter dentro de um buildout um comando que rode TODOS os testes do seu projeto… algo parecido com:
bin/tests --all
Mas isso requer um estudo mais a fundo do Buildout e explicar essas coisas tornaria esse post mais extenso do que já está… fica pra um próximo post, quem sabe. Caso você queira estudar Buildout mais a fundo por conta própria, eu recomendo a documentação do site oficial do Buildout.
Até a próxima amigos leitores!