Buildout - Parte I

In this part you will:

  • Learn about Buildout

Topics covered:

  • Buildout
  • Recetas

  • Buildout Configuration
  • mr.developer

Buildout compone su aplicacion por usted, de acuerdo a sus reglas.

To compose your application you must define the eggs you need, which version, what configuration files Buildout has to generate for you, what to download and compile, and so on. Buildout downloads the eggs you requested and resolves all dependencies. You might need five different eggs, but in the end, Buildout has to install 300 eggs, all with the correct version in order to resolve all the dependencies.

Buildout does this without touching your system Python or affecting any other package. The commands created by buildout bring all the required packages into the Python environment. Each command it creates may use different libraries or even different versions of the same library.

Plone necesita carpetas para los archivos de registro, bases de datos y archivos de configuración. Buildout ensambla todo esto para usted.

You will need a lot of functionality that Buildout does not provide out of the box, so you’ll need several extensions. Some extensions provide new functionality, like mr.developer, the best way to manage your checked out sources.

Sintaxis

La sintaxis de los archivos de configuración de despliegue es similar a los archivos clásicos ini. Usted escribe un nombre de parámetro, un signo igual y el valor. Si introduce otro valor en la siguiente línea y sangría a ella, Buildout entiende que ambos valores pertenecen al nombre del parámetro y el parámetro almacena todos los valores en forma de lista.

A Buildout consta de múltiples secciones. Secciones comienzan con el nombre de la sección entre corchetes. Cada sección declara una parte diferente de su aplicación. Como analogía aproximada, su archivo Buildout es un libro de cocina con múltiples recetas.

There is a special section, called [buildout]. This section can change the behavior of Buildout itself. The variable parts defines, which of the existing sections should actually be used.

Recetas

Buildout itself has no idea how to install Zope. Buildout is a plugin based system, it comes with a small set of plugins to create configuration files and download eggs with their dependencies and the proper version. To install a Zope site, you need a third-party plugin. The plugins provide new recipes that you have to declare and configure in their own respective sections.

Un ejemplo es esta sección.

[instance]
recipe = plone.recipe.zope2instance
user = admin:admin

This uses the python-package plone.recipe.zope2instance to create and configure the Zope 2 instance which we use to run Plone. All the lines after recipe = xyz are the configuration of the specified recipe.

Referencias

Buildout le permite usar referencias en la configuración. Una declaración de variable no sólo puede mantener el valor de variable, pero también una referencia al lugar donde buscar el valor de la variable.

Si usted tiene una gran instalación con muchos sitios Plone con pequeños cambios entre cada configuración, se puede generar una plantilla de configuración, y cada sitio hace referencia a todo, desde la plantilla y sobreescribe justo en lo que necesita ser cambiado.

Incluso en los buildouts más pequeños esta es una característica útil. Estamos utilizando collective.recipe.omelette. Una receta muy práctica que crea un directorio virtual que facilita la navegación al código fuente de cada paquete egg.

La receta omelette tiene que saber cuales son los paquetes eggs para hacer referencia. Queremos los mismos paquetes eggs, utiliza nuestro ejemplo, por lo que nos referimos a los paquetes eggs de la instancia en lugar de repetir toda la lista.

Otro ejemplo: Digamos que usted crea archivos de configuración para un servidor web como Nginx, puede definir el puerto de destino para el proxy inverso al mirar hacia arriba a partir de la receta zope2instance.

Configuración de sistemas complejos siempre implica una gran cantidad de duplicación de la información. El uso de referencias en la configuración buildout le permite minimizar estas duplicaciones.

Un ejemplo de la vida real

Examinemos el archivo buildout.cfg para el entrenamiento y miremos algunas de las variables mas importantes:

[buildout]
extends =
# The coredev for Plone 5: https://github.com/plone/buildout.coredev/tree/5.0
# We only use the versions and checkouts
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/sources.cfg
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/checkouts.cfg
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/versions.cfg

# We add our own versions
    versions.cfg

versions = versions

# Tell mr.developer to ask before updating a chckout.
# The default in coredev is 'force' which always updates.
always-checkout = true
show-picked-versions = true
find-links = http://dist.plone.org
extensions = mr.developer
sources = sources

# Put checkouts in src-mrd. We keep our own package in src
sources-dir = src-mrd

# The directory this buildout is in. Modified when using vagrant.
buildout_dir = ${buildout:directory}

# Extend the coredevs-checkouts with our own
auto-checkout +=
    Products.PloneFormGen
    bobtemplates.plone
    ploneconf.site_sneak
#    starzel.votable_behavior
#    ploneconf.site


parts =
    checkversions
    codeintel
    instance
    mrbob
    packages
    robot
    test
    zopepy

eggs =
    Plone
    Pillow

# development tools
    z3c.jbot
    plone.api
    plone.reload
    Products.PDBDebugMode
    plone.app.debugtoolbar

# TTW Forms (based on Archetypes)
    Products.PloneFormGen

# The addon we develop in the training
#    ploneconf.site

# Voting on content
#    starzel.votable_behavior

zcml =

test-eggs +=
#    ploneconf.site [test]

[instance]
recipe = plone.recipe.zope2instance
user = admin:admin
http-address = 8080
debug-mode = on
verbose-security = on
deprecation-warnings = on
eggs = ${buildout:eggs}
zcml = ${buildout:zcml}
file-storage = ${buildout:buildout_dir}/var/filestorage/Data.fs
blob-storage = ${buildout:buildout_dir}/var/blobstorage

[test]
recipe = zc.recipe.testrunner
eggs = ${buildout:test-eggs}
defaults = ['--exit-with-status', '--auto-color', '--auto-progress']

[robot]
recipe = zc.recipe.egg
eggs =
    ${buildout:test-eggs}
    Pillow
    plone.app.robotframework[ride,reload,debug]

[packages]
recipe = collective.recipe.omelette
eggs = ${buildout:eggs}
location = ${buildout:buildout_dir}/packages

[codeintel]
recipe = corneti.recipes.codeintel
eggs = ${buildout:eggs}

[code-analysis]
recipe = plone.recipe.codeanalysis
directory = ${buildout:directory}/src/ploneconf.site/src/
pep3101 = False
imports = True
debug-statements = True
prefer-single-quotes = True
utf8-header = True
deprecated-aliases = True

[checkversions]
recipe = zc.recipe.egg
eggs = z3c.checkversions [buildout]

[zopepy]
recipe = zc.recipe.egg
eggs = ${buildout:eggs}
interpreter = zopepy

[mrbob]
recipe = zc.recipe.egg
eggs =
    mr.bob
    bobtemplates.plone

[sources]
ploneconf.site = fs ploneconf.site path=src
starzel.votable_behavior = git https://github.com/collective/starzel.votable_behavior.git pushurl=git://github.com/collective/starzel.votable_behavior.git path=src

# Checkouts to make addons we use work with Plone 5
Products.PloneFormGen = git https://github.com/starzel/Products.PloneFormGen.git pushurl=git@github.com:starzel/Products.PloneFormGen.git rev=fa2b4df60c8ab1ab88bf1497904b958d5ed214d4

# We use the unreleased version of bobtemplates.plone since it asks less questions
bobtemplates.plone = git https://github.com/plone/bobtemplates.plone.git rev=b09362f314b4fd6cce22691898e1d79e9cf2f27f

# This is no egg but folders each containing the egg of ploneconf.site for one chapter
ploneconf.site_sneak = git https://github.com/collective/ploneconf.site_sneak.git path=src egg=false

Cuando usted ejecuta ./bin/buildout sin argumentos, Buildout buscara por este archivo:

Echemos un vistazo más de cerca a algunas variables.

extends =
# The coredev for Plone 5: https://github.com/plone/buildout.coredev/tree/5.0
# We only use the versions and checkouts
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/sources.cfg
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/checkouts.cfg
    https://raw.githubusercontent.com/plone/buildout.coredev/5.0/versions.cfg

# We add our own versions
    versions.cfg

This line tells Buildout to read more configuration files. You can refer to configuration files on your computer or to configuration files on the Internet, reachable via http. You can use multiple configuration files to share configurations between multiple Buildouts, or to separate different aspects of your configuration into different files. Typical examples are version specifications, or configurations that differ between different environments.

eggs =
    Plone
    Pillow

# development tools
    z3c.jbot
    plone.api
    plone.reload
    Products.PDBDebugMode
    plone.app.debugtoolbar

# TTW Forms (based on Archetypes)
    Products.PloneFormGen

# The addon we develop in the training
#    ploneconf.site

# Voting on content
#    starzel.votable_behavior

zcml =

test-eggs +=
#    ploneconf.site [test]

Esta es la lista de los paquetes eggs que nosotros configuramos a estar disponible para Zope. Estos paquetes eggs se ponen en la ruta de python del script bin/instance con el cual se iniciara y detendrá con Plone.

El paquete egg Plone es una envoltura sin código. Entre sus dependencias es Products.CMFPlone que es el paquete egg que está en el centro de Plone.

El resto son complementos que ya hemos usado o usará más tarde. Los últimos paquetes eggs están comentadas por lo que no se instalarán por Buildout.

The file versions.cfg that is included by the extends = ... statement hold the version pins:

[versions]
# dev tools
Products.PDBDebugMode = 1.3.1
corneti.recipes.codeintel = 0.3
plone.api = 1.3.2
plone.app.debugtoolbar = 1.0
z3c.jbot = 0.7.2

# pinns for some Addons
Products.PloneFormGen = 1.7.16
Products.PythonField = 1.1.3
...

This is another special section. It has become a special section by declaration. In our [buildout] section we set a variable versions = versions. This told buildout that there is a section named versions, containing version information. When Buildout installs eggs it will use the versions defined in this section.

¡Hola mr.developer!

There are many more important things to know, and we can’t go through them all in detail but I want to focus on one specific feature: mr.developer

With mr.developer you can declare which packages you want to check out from which version control system and which repository URL. You can check out sources from git, svn, bzr, hg and maybe more. Also, you can say that some sources are in your local file system.

mr.developer comes with a command, ./bin/develop. You can use it to update your code, to check for changes and so on. You can activate and deactivate your source checkouts. If you develop your extensions in eggs with separate checkouts, which is a good practice, you can plan releases by having all source checkouts deactivated, and only activate them when you write changes that require a new release. You can activate and deactivate eggs via the develop command or the Buildout configuration. You should always use the Buildout way. Your commit serves as documentation.

Extensible

You might have noticed that most if not all functionality is only available via plugins. One of the things that Buildout excels at without any plugin is the dependency resolution. You can help Plone in dependency resolution by declaring exactly which version of an egg you want. This is only one use case. Another one is much more important: If you want to have a repeatable Buildout, one that works two months from now also, you must declare all your egg versions. Else Buildout might install newer versions.

Sea un McGuyver

As you can see, you can build very complex systems with Buildout. It is time for some warnings. Be selective in your recipes. Supervisor is a program to manage running servers, and it’s pretty good. There is a recipe for it.

The configuration for this recipe is more complicated than the supervisor configuration itself! By using this recipe, you force others to understand the recipe’s specific configuration syntax and the supervisor syntax. For such cases, collective.recipe.template is a better match.

Another problem is error handling. Buildout tries to install a weird dependency you do not actually want? Buildout will not tell you where it is coming from.

If there is a problem, you can always run Buildout with -v to get more verbose output, sometimes it helps.

$ ./bin/buildout -v

Si se solicitan las versiones de paquetes eggs extraños, verifique la declaración de las dependencias de los paquetes eggs y su versión definida.

Some parts of Buildout interpret egg names case sensitive, others won’t. This can result in funny problems.

Verifique siempre el orden de su configuraciones extendidas, utilice siempre el comando annotate de Buildout para ver si se interpreta la configuración diferente a la que usted definió. Restringirse a los archivos de despliegue simples. Puede hacer referencia a variables de otras secciones, incluso se puede utilizar toda una sección como plantilla. Hemos aprendido que esto no funciona bien con jerarquías complejas y se tuvo que abandonar esa característica.

In the chapter Buildout II: Getting Ready for Deployment we will have a look at a production-ready buildout for Plone that has many useful features.