Egg Recipe API for other Recipes
================================

It is common for recipes to accept a collection of egg specifications
and generate scripts based on the resulting working sets.  The egg
recipe provides an API that other recipes can use.

A recipe can reuse the egg recipe, supporting the eggs, find-links,
index, and extra-paths options.  This is done by creating an
egg recipe instance in a recipes's constructor.  In the recipe's
install script, the egg-recipe instance's working_set method is used
to collect the requested eggs and working set.

To illustrate, we create a sample recipe that is a very thin layer
around the egg recipe:

    >>> mkdir(sample_buildout, 'sample')
    >>> write(sample_buildout, 'sample', 'sample.py', 
    ... """
    ... import logging, os, sys
    ... import zc.recipe.egg
    ...
    ... def print_(*args):
    ...     sys.stdout.write(' '.join(map(str, args)) + '\\n')
    ...
    ... class Sample:
    ...
    ...     def __init__(self, buildout, name, options):
    ...         self.egg = zc.recipe.egg.Scripts(buildout, name, options)
    ...         self.name = name
    ...         self.options = options
    ...
    ...     def install(self):
    ...         extras = self.options['extras'].split()
    ...         requirements, ws = self.egg.working_set(extras)
    ...         print_('Part:', self.name)
    ...         print_('Egg requirements:')
    ...         for r in requirements:
    ...             print_(r)
    ...         print_('Working set:')
    ...         for d in ws:
    ...             print_(d)
    ...         print_('extra paths:', self.egg.extra_paths)
    ...         return ()
    ...
    ...     update = install
    ... """)

Here we instantiated the egg recipe in the constructor, saving it in
an attribute.  This also initialized the options dictionary.

In our install method, we called the working_set method on the
instance we saved.  The working_set method takes an optional sequence
of extra requirements to be included in the working set.

    >>> write(sample_buildout, 'sample', 'setup.py',
    ... """
    ... from setuptools import setup
    ... 
    ... setup(
    ...     name = "sample",
    ...     entry_points = {'zc.buildout': ['default = sample:Sample']},
    ...     install_requires = 'zc.recipe.egg',
    ...     )
    ... """)


    >>> write(sample_buildout, 'sample', 'README.txt', " ")

    >>> write(sample_buildout, 'buildout.cfg',
    ... """
    ... [buildout]
    ... develop = sample
    ... parts = sample-part
    ...
    ... [sample-part]
    ... recipe = sample
    ... eggs = demo<0.3
    ... find-links = %(server)s
    ... index = %(server)sindex
    ... extras = other
    ... """ % dict(server=link_server))

    >>> import os
    >>> os.chdir(sample_buildout)
    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
    >>> print_(system(buildout + ' -q'), end='')
    Part: sample-part
    Egg requirements:
    demo<0.3
    Working set:
    demoneeded 1.1
    other 1.0
    demo 0.2
    extra paths: []

We can see that the options were augmented with additional data
computed by the egg recipe by looking at .installed.cfg:

    >>> cat(sample_buildout, '.installed.cfg')
    [buildout]
    installed_develop_eggs = /sample-buildout/develop-eggs/sample.egg-link
    parts = sample-part
    <BLANKLINE>
    [sample-part]
    __buildout_installed__ = 
    __buildout_signature__ = ...
    _b = /sample-buildout/bin
    _d = /sample-buildout/develop-eggs
    _e = /sample-buildout/eggs
    bin-directory = /sample-buildout/bin
    develop-eggs-directory = /sample-buildout/develop-eggs
    eggs = demo<0.3
    eggs-directory = /sample-buildout/eggs
    extras = other
    find-links = http://localhost:27071/
    index = http://localhost:27071/index
    recipe = sample

If we use the extra-paths option:


    >>> write(sample_buildout, 'buildout.cfg',
    ... """
    ... [buildout]
    ... develop = sample
    ... parts = sample-part
    ...
    ... [sample-part]
    ... recipe = sample
    ... eggs = demo<0.3
    ... find-links = %(server)s
    ... index = %(server)sindex
    ... extras = other
    ... extra-paths = /foo/bar
    ...               /spam/eggs
    ... """ % dict(server=link_server))

Then we'll see that reflected in the extra_paths attribute in the egg
recipe instance:

    >>> print_(system(buildout + ' -q'), end='')
    Part: sample-part
    Egg requirements:
    demo<0.3
    Working set:
    demo 0.2
    other 1.0
    demoneeded 1.1
    extra paths: ['/foo/bar', '/spam/eggs']

