Personal tools
You are here: Home Documentation Tutorials Introduction to zc.buildout Writing your own recipes

Writing your own recipes

Use the zc.buildout recipe API
Jim Fulton's tutorial for using buildout, originally given at DZUG 2007
Page 12 of 17.

Writing recipes

  • The recipe API

    • install

      • __init__

        handout

        The initializer is responsible for computing a part's options. After the initializer call, the options directory must reflect the full configuration of the part. In particular, if a recipe reads any data from other sections, it must be reflected in the options. The options data after the initializer is called is used to determine if a configuration has changed when deciding if a part has to be reinstalled. When a part is reinstalled, it is uninstalled and then installed.

      • install

        handout

        The install method installs the part. It is used when a part is added to a buildout, or when a part is reinstalled.

        The install recipe must return a sequence of paths that that should be removed when the part is uninstalled. Most recipes just create files or directories and removing these is sufficient for uninstalling the part.

      • update

        handout

        The update method is used when a part is already installed and it's configuration hasn't changed from previous buildouts. It can return None or a sequence of paths. If paths are returned, they are added to the set of installed paths.

    • uninstall

      handout

      Most recipes simply create files or directories and the built-in buildout uninstall support is sufficient. If a recipe does more than simply create files, then an uninstall recipe will likely be needed.

Install Recipes

mkdirrecipe.py:

import logging, os, zc.buildout

class Mkdir:

    def __init__(self, buildout, name, options):
        self.name, self.options = name, options
        options['path'] = os.path.join(
                              buildout['buildout']['directory'],
                              options['path'],
                              )
        if not os.path.isdir(os.path.dirname(options['path'])):
            logging.getLogger(self.name).error(
                'Cannot create %s. %s is not a directory.',
                options['path'], os.path.dirname(options['path']))
            raise zc.buildout.UserError('Invalid Path')
handout
  • The path option in our recipe is interpreted relative to the buildout. We reflect this by saving the adjusted path in the options.
  • If there is a user error, we:
    • Log error details using the Python logger module.
    • Raise a zc.buildout.UserError exception.

mkdirrecipe.py continued

def install(self):
    path = self.options['path']
    logging.getLogger(self.name).info(
        'Creating directory %s', os.path.basename(path))
    os.mkdir(path)
    return path

def update(self):
    pass
handout

A well-written recipe will log what it's doing.

Often the update method is empty, as in this case.

Uninstall recipes

servicerecipe.py:

import os

class Service:

    def __init__(self, buildout, name, options):
        self.options = options

    def install(self):
        os.system("chkconfig --add %s" % self.options['script'])
        return ()

    def update(self):
        pass

def uninstall_service(name, options):
    os.system("chkconfig --del %s" % options['script'])
handout
Uninstall recipes are callables that are passed the part name and the original options.

Buildout entry points

setup.py:

from setuptools import setup

entry_points = """
[zc.buildout]
mkdir = mkdirrecipe:Mkdir
service = servicerecipe:Service
default = mkdirrecipe:Mkdir

[zc.buildout.uninstall]
service = servicerecipe:uninstall_service
"""

setup(name='recipes', entry_points=entry_points)