[Checkins] SVN: zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/ continue factoring

Jim Fulton jim at zope.com
Tue Aug 29 13:44:45 EDT 2006


Log message for revision 69870:
  continue factoring

Changed:
  D   zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.py
  D   zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.txt
  U   zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/tests.py

-=-
Deleted: zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.py
===================================================================
--- zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.py	2006-08-29 17:43:08 UTC (rev 69869)
+++ zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.py	2006-08-29 17:44:45 UTC (rev 69870)
@@ -1,711 +0,0 @@
-#############################################################################
-#
-# Copyright (c) 2005 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Buildout main script
-
-$Id$
-"""
-
-import logging
-import md5
-import os
-import pprint
-import re
-import shutil
-import sys
-import ConfigParser
-
-import zc.buildout.easy_install
-import pkg_resources
-import zc.buildout.easy_install
-
-class UserError(Exception):
-    """Errors made by a user 
-    """
-
-    def __str__(self):
-        return " ".join(map(str, self))
-
-class MissingOption(UserError, KeyError):
-    """A required option was missing
-    """
-
-class MissingSection(UserError, KeyError):
-    """A required section is missinh
-    """
-
-class Options(dict):
-
-    def __init__(self, buildout, section, data):
-        self.buildout = buildout
-        self.section = section
-        super(Options, self).__init__(data)
-
-    def __getitem__(self, option):
-        try:
-            return super(Options, self).__getitem__(option)
-        except KeyError:
-            raise MissingOption("Missing option: %s:%s"
-                                % (self.section, option))
-
-    # XXX need test
-    def __setitem__(self, option, value):
-        if not isinstance(value, str):
-            raise TypeError('Option values must be strings', value)
-        super(Options, self).__setitem__(option, value)
-
-    def copy(self):
-        return Options(self.buildout, self.section, self)
-
-class Buildout(dict):
-
-    def __init__(self, config_file, cloptions):
-        config_file = os.path.abspath(config_file)
-        self._config_file = config_file
-        if not os.path.exists(config_file):
-            print 'Warning: creating', config_file
-            open(config_file, 'w').write('[buildout]\nparts = \n')
-
-        super(Buildout, self).__init__()
-
-        # default options
-        data = dict(buildout={
-            'directory': os.path.dirname(config_file),
-            'eggs-directory': 'eggs',
-            'develop-eggs-directory': 'develop-eggs',
-            'bin-directory': 'bin',
-            'parts-directory': 'parts',
-            'installed': '.installed.cfg',
-            'python': 'buildout',
-            'executable': sys.executable,
-            'log-level': 'WARNING',
-            'log-format': '%(name)s: %(message)s',
-            })
-
-        # load user defaults, which override defaults
-        if 'HOME' in os.environ:
-            user_config = os.path.join(os.environ['HOME'],
-                                       '.buildout', 'default.cfg')
-            if os.path.exists(user_config):
-                _update(data, _open(os.path.dirname(user_config), user_config,
-                                    []))
-
-        # load configuration files
-        _update(data, _open(os.path.dirname(config_file), config_file, []))
-
-        # apply command-line options
-        for (section, option, value) in cloptions:
-            options = data.get(section)
-            if options is None:
-                options = self[section] = {}
-            options[option] = value
-                # The egg dire
-
-        # do substitutions
-        converted = {}
-        for section, options in data.iteritems():
-            for option, value in options.iteritems():
-                if '$' in value:
-                    value = self._dosubs(section, option, value,
-                                         data, converted, [])
-                    options[option] = value
-                converted[(section, option)] = value
-
-        # copy data into self:
-        for section, options in data.iteritems():
-            self[section] = Options(self, section, options)
-        
-        # initialize some attrs and buildout directories.
-        options = self['buildout']
-
-        links = options.get('find-links', '')
-        self._links = links and links.split() or ()
-
-        self._buildout_dir = options['directory']
-        for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
-            d = self._buildout_path(options[name+'-directory'])
-            options[name+'-directory'] = d
-
-        options['installed'] = os.path.join(options['directory'],
-                                            options['installed'])
-
-        self._setup_logging()
-
-    def _dosubs(self, section, option, value, data, converted, seen):
-        key = section, option
-        r = converted.get(key)
-        if r is not None:
-            return r
-        if key in seen:
-            raise UserError("Circular reference in substitutions.\n"
-                            "We're evaluating %s\nand are referencing: %s.\n"
-                            % (", ".join([":".join(k) for k in seen]),
-                               ":".join(key)
-                               )
-                            )
-        seen.append(key)
-        value = '$$'.join([self._dosubs_esc(s, data, converted, seen)
-                           for s in value.split('$$')
-                           ])
-        seen.pop()
-        return value
-
-    _template_split = re.compile('([$]{[^}]*})').split
-    _simple = re.compile('[-a-zA-Z0-9 ._]+$').match
-    _valid = re.compile('[-a-zA-Z0-9 ._]+:[-a-zA-Z0-9 ._]+$').match
-    def _dosubs_esc(self, value, data, converted, seen):
-        value = self._template_split(value)
-        subs = []
-        for ref in value[1::2]:
-            s = tuple(ref[2:-1].split(':'))
-            if not self._valid(ref):
-                if len(s) < 2:
-                    raise UserError("The substitution, %s,\n"
-                                    "doesn't contain a colon."
-                                    % ref)
-                if len(s) > 2:
-                    raise UserError("The substitution, %s,\n"
-                                    "has too many colons."
-                                    % ref)
-                if not self._simple(s[0]):
-                    raise UserError("The section name in substitution, %s,\n"
-                                    "has invalid characters."
-                                    % ref)
-                if not self._simple(s[1]):
-                    raise UserError("The option name in substitution, %s,\n"
-                                    "has invalid characters."
-                                    % ref)
-                
-            v = converted.get(s)
-            if v is None:
-                options = data.get(s[0])
-                if options is None:
-                    raise MissingSection(
-                        "Referenced section does not exist", s[0])
-                v = options.get(s[1])
-                if v is None:
-                    raise MissingOption("Referenced option does not exist:",
-                                        *s)
-                if '$' in v:
-                    v = self._dosubs(s[0], s[1], v, data, converted, seen)
-                    options[s[1]] = v
-                converted[s] = v
-            subs.append(v)
-        subs.append('')
-
-        return ''.join([''.join(v) for v in zip(value[::2], subs)])
-
-    def _buildout_path(self, *names):
-        return os.path.join(self._buildout_dir, *names)
-
-    def bootstrap(self, args):
-        self._setup_directories()
-
-        # Now copy buildout and setuptools eggs, amd record destination eggs:
-        entries = []
-        for name in 'setuptools', 'zc.buildout':
-            r = pkg_resources.Requirement.parse(name)
-            dist = pkg_resources.working_set.find(r)
-            if dist.precedence == pkg_resources.DEVELOP_DIST:
-                dest = os.path.join(self['buildout']['eggs-directory'],
-                                    name+'.egg-link')
-                open(dest, 'w').write(dist.location)
-                entries.append(dist.location)
-            else:
-                dest = os.path.join(self['buildout']['eggs-directory'],
-                                    os.path.basename(dist.location))
-                entries.append(dest)
-                if not os.path.exists(dest):
-                    if os.path.isdir(dist.location):
-                        shutil.copytree(dist.location, dest)
-                    else:
-                        shutil.copy2(dist.location, dest)
-
-        # Create buildout script
-        ws = pkg_resources.WorkingSet(entries)
-        ws.require('zc.buildout')
-        zc.buildout.easy_install.scripts(
-            ['zc.buildout'], ws, sys.executable,
-            self['buildout']['bin-directory'])
-
-    def install(self, install_parts):
-        self._setup_directories()
-
-        # Add develop-eggs directory to path so that it gets searched
-        # for eggs:
-        sys.path.insert(0, self['buildout']['develop-eggs-directory'])
-
-        # Build develop eggs
-        self._develop()
-
-        # load installed data
-        installed_part_options = self._read_installed_part_options()
-
-        # get configured and installed part lists
-        conf_parts = self['buildout']['parts']
-        conf_parts = conf_parts and conf_parts.split() or []
-        installed_parts = installed_part_options['buildout']['parts']
-        installed_parts = installed_parts and installed_parts.split() or []
-
-
-        # If install_parts is given, then they must be listed in parts
-        # and we don't uninstall anything. Otherwise, we install
-        # the configured parts and uninstall anything else.
-        if install_parts:
-            extra = [p for p in install_parts if p not in conf_parts]
-            if extra:
-                self._error('Invalid install parts:', *extra)
-            uninstall_missing = False
-        else:
-            install_parts = conf_parts
-            uninstall_missing = True
-
-        # load recipes
-        recipes = self._load_recipes(install_parts)
-
-        # compute new part recipe signatures
-        self._compute_part_signatures(install_parts)
-
-        try:
-            # uninstall parts that are no-longer used or who's configs
-            # have changed
-            for part in reversed(installed_parts):
-                if part in install_parts:
-                    old_options = installed_part_options[part].copy()
-                    old_options.pop('__buildout_installed__')
-                    new_options = self.get(part)
-                    if old_options == new_options:
-                        continue
-                    for k in old_options:
-                        if k not in new_options:
-                            self._logger.debug("Part: %s, dropped option %s",
-                                               part, k)
-                        elif old_options[k] != new_options[k]:
-                            self._logger.debug(
-                                "Part: %s, option %s, %r != %r",
-                                part, k, new_options[k], old_options[k],
-                                )
-                    for k in new_options:
-                        if k not in old_options:
-                            self._logger.debug("Part: %s, new option %s",
-                                               part, k)
-                elif not uninstall_missing:
-                    continue
-
-                # ununstall part
-                self._logger.info('Uninstalling %s', part)
-                self._uninstall(
-                    installed_part_options[part]['__buildout_installed__'])
-                installed_parts = [p for p in installed_parts if p != part]
-
-            # install new parts
-            for part in install_parts:
-                self._logger.info('Installing %s', part)
-                installed_part_options[part] = self[part].copy()
-                del self[part]['__buildout_signature__']
-                installed_files = recipes[part].install() or ()
-                if isinstance(installed_files, str):
-                    installed_files = [installed_files]
-                installed_part_options[part]['__buildout_installed__'] = (
-                    '\n'.join(installed_files)
-                    )
-                if part not in installed_parts:
-                    installed_parts.append(part)
-        finally:
-            installed_part_options['buildout']['parts'] = ' '.join(
-                [p for p in conf_parts if p in installed_parts]
-                +
-                [p for p in installed_parts if p not in conf_parts] 
-            )
-            self._save_installed_options(installed_part_options)
-
-    def _setup_directories(self):
-
-        # Create buildout directories
-        for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
-            d = self['buildout'][name+'-directory']
-            if not os.path.exists(d):
-                self._logger.info('Creating directory %s', d)
-                os.mkdir(d)
-
-    def _develop(self):
-        """Install sources by running setup.py develop on them
-        """
-        develop = self['buildout'].get('develop')
-        if develop:
-            here = os.getcwd()
-            try:
-                for setup in develop.split():
-                    setup = self._buildout_path(setup)
-                    if os.path.isdir(setup):
-                        setup = os.path.join(setup, 'setup.py')
-                    self._logger.info("Running %s -q develop ...", setup)
-                    os.chdir(os.path.dirname(setup))
-                    os.spawnle(
-                        os.P_WAIT, sys.executable, sys.executable,
-                        zc.buildout.easy_install._safe_arg(setup),
-                        '-q', 'develop', '-m', '-x', '-N',
-                        '-f', zc.buildout.easy_install._safe_arg(
-                                  ' '.join(self._links)
-                                  ),
-                        '-d', zc.buildout.easy_install._safe_arg(
-                                  self['buildout']['develop-eggs-directory']
-                                  ),
-                        {'PYTHONPATH':
-                         os.path.dirname(pkg_resources.__file__)},
-                        )
-            finally:
-                os.chdir(here)
-
-    def _load_recipes(self, parts):
-        recipes = {}
-        if not parts:
-            return recipes
-        
-        recipes_requirements = []
-        pkg_resources.working_set.add_entry(
-            self['buildout']['develop-eggs-directory'])
-        pkg_resources.working_set.add_entry(self['buildout']['eggs-directory'])
-
-        # Gather requirements
-        for part in parts:
-            options = self.get(part)
-            if options is None:
-                raise MissingSection("No section was specified for part", part)
-
-            recipe, entry = self._recipe(part, options)
-            recipes_requirements.append(recipe)
-
-        # Install the recipe distros
-        offline = self['buildout'].get('offline', 'false')
-        if offline not in ('true', 'false'):
-            self._error('Invalif value for offline option: %s', offline)
-        if offline == 'true':
-            ws = zc.buildout.easy_install.working_set(
-                recipes_requirements, sys.executable,
-                [self['buildout']['eggs-directory'],
-                 self['buildout']['develop-eggs-directory'],
-                 ],
-                )
-        else:
-            ws = zc.buildout.easy_install.install(
-                recipes_requirements, self['buildout']['eggs-directory'],
-                links=self._links, index=self['buildout'].get('index'),
-                path=[self['buildout']['develop-eggs-directory']])
-            
-        # Add the distros to the working set
-        pkg_resources.require(recipes_requirements)
-
-        # instantiate the recipes
-        for part in parts:
-            options = self[part]
-            recipe, entry = self._recipe(part, options)
-            recipe_class = pkg_resources.load_entry_point(
-                recipe, 'zc.buildout', entry)
-            recipes[part] = recipe_class(self, part, options)
-        
-        return recipes
-
-    def _compute_part_signatures(self, parts):
-        # Compute recipe signature and add to options
-        base = self['buildout']['eggs-directory'] + os.path.sep
-        for part in parts:
-            options = self.get(part)
-            if options is None:
-                options = self[part] = {}
-            recipe, entry = self._recipe(part, options)
-            req = pkg_resources.Requirement.parse(recipe)
-            sig = _dists_sig(pkg_resources.working_set.resolve([req]), base)
-            options['__buildout_signature__'] = ' '.join(sig)
-
-    def _recipe(self, part, options):
-        recipe = options['recipe']
-        if ':' in recipe:
-            recipe, entry = recipe.split(':')
-        else:
-            entry = 'default'
-
-        return recipe, entry
-
-    def _read_installed_part_options(self):
-        old = self._installed_path()
-        if os.path.isfile(old):
-            parser = ConfigParser.SafeConfigParser(_spacey_defaults)
-            parser.optionxform = lambda s: s
-            parser.read(old)
-            return dict([
-                (section,
-                 Options(self, section,
-                         [item for item in parser.items(section)
-                          if item[0] not in _spacey_defaults]
-                         )
-                 )
-                for section in parser.sections()])
-        else:
-            return {'buildout': Options(self, 'buildout', {'parts': ''})}
-
-    def _installed_path(self):        
-        return self._buildout_path(self['buildout']['installed'])
-
-    def _uninstall(self, installed):
-        for f in installed.split():
-            f = self._buildout_path(f)
-            if os.path.isdir(f):
-                shutil.rmtree(f)
-            elif os.path.isfile(f):
-                os.remove(f)
-                
-    def _install(self, part):
-        options = self[part]
-        recipe, entry = self._recipe(part, options)
-        recipe_class = pkg_resources.load_entry_point(
-            recipe, 'zc.buildout', entry)
-        installed = recipe_class(self, part, options).install()
-        if installed is None:
-            installed = []
-        elif isinstance(installed, basestring):
-            installed = [installed]
-        base = self._buildout_path('')
-        installed = [d.startswith(base) and d[len(base):] or d
-                     for d in installed]
-        return ' '.join(installed)
-
-
-    def _save_installed_options(self, installed_options):
-        f = open(self._installed_path(), 'w')
-        _save_options('buildout', installed_options['buildout'], f)
-        for part in installed_options['buildout']['parts'].split():
-            print >>f
-            _save_options(part, installed_options[part], f)
-        f.close()
-
-    def _error(self, message, *args, **kw):
-        self._logger.error(message, *args, **kw)
-        sys.exit(1)
-
-    def _setup_logging(self):
-        root_logger = logging.getLogger()
-        handler = logging.StreamHandler(sys.stdout)
-        handler.setFormatter(logging.Formatter(self['buildout']['log-format']))
-        root_logger.addHandler(handler)
-        self._logger = logging.getLogger('buildout')
-        level = self['buildout']['log-level']
-        if level in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
-            level = getattr(logging, level)
-        else:
-            try:
-                level = int(level)
-            except ValueError:
-                self._error("Invalid logging level %s", level)
-        verbosity = self['buildout'].get('verbosity', 0)
-        try:
-            verbosity = int(verbosity)
-        except ValueError:
-            self._error("Invalid verbosity %s", verbosity)
-
-        level -= verbosity
-        root_logger.setLevel(level)
-
-        if level <= logging.DEBUG:
-            sections = list(self)
-            sections.sort()
-            print 'Configuration data:'
-            for section in sections:
-                _save_options(section, self[section], sys.stdout)
-            print    
-
-_spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
-                        '|'
-                        '^[ \t\r\f\v]+'
-                        '|'
-                        '[ \t\r\f\v]+$'
-                        )
-
-def _quote_spacey_nl(match):
-    match = match.group(0).split('\n', 1)
-    result = '\n\t'.join(
-        [(s
-          .replace(' ', '%(__buildout_space__)s')
-          .replace('\r', '%(__buildout_space_r__)s')
-          .replace('\f', '%(__buildout_space_f__)s')
-          .replace('\v', '%(__buildout_space_v__)s')
-          .replace('\n', '%(__buildout_space_n__)s')
-          )
-         for s in match]
-        )
-    return result
-
-_spacey_defaults = dict(
-    __buildout_space__   = ' ',
-    __buildout_space_r__ = '\r',
-    __buildout_space_f__ = '\f',
-    __buildout_space_v__ = '\v',
-    __buildout_space_n__ = '\n',
-    )
-
-def _save_options(section, options, f):
-    print >>f, '[%s]' % section
-    items = options.items()
-    items.sort()
-    for option, value in items:
-        value = value.replace('%', '%%')
-        value = _spacey_nl.sub(_quote_spacey_nl, value)
-        if value.startswith('\n\t'):
-            value = '%(__buildout_space_n__)s' + value[2:]
-        if value.endswith('\n\t'):
-            value = value[:-2] + '%(__buildout_space_n__)s'
-        print >>f, option, '=', value
-            
-    
-
-def _open(base, filename, seen):
-    """Open a configuration file and return the result as a dictionary,
-
-    Recursively open other files based on buildout options found.
-    """
-
-    filename = os.path.join(base, filename)
-    if filename in seen:
-        raise UserError("Recursive file include", seen, filename)
-
-    base = os.path.dirname(filename)
-    seen.append(filename)
-
-    result = {}
-
-    parser = ConfigParser.SafeConfigParser()
-    parser.optionxform = lambda s: s
-    parser.readfp(open(filename))
-    extends = extended_by = None
-    for section in parser.sections():
-        options = dict(parser.items(section))
-        if section == 'buildout':
-            extends = options.pop('extends', extends)
-            extended_by = options.pop('extended-by', extended_by)
-        result[section] = options
-
-    if extends:
-        extends = extends.split()
-        extends.reverse()
-        for fname in extends:
-            result = _update(_open(base, fname, seen), result)
-
-    if extended_by:
-        for fname in extended_by.split():
-            result = _update(result, _open(base, fname, seen))
-
-    seen.pop()
-    return result
-    
-
-def _dir_hash(dir):
-    hash = md5.new()
-    for (dirpath, dirnames, filenames) in os.walk(dir):
-        filenames[:] = [f for f in filenames
-                        if not (f.endswith('pyc') or f.endswith('pyo'))
-                        ]
-        hash.update(' '.join(dirnames))
-        hash.update(' '.join(filenames))
-        for name in filenames:
-            hash.update(open(os.path.join(dirpath, name)).read())
-    return hash.digest().encode('base64').strip()
-    
-def _dists_sig(dists, base):
-    result = []
-    for dist in dists:
-        location = dist.location
-        if dist.precedence == pkg_resources.DEVELOP_DIST:
-            result.append(dist.project_name + '-' + _dir_hash(location))
-        else:
-            if location.startswith(base):
-                location = location[len(base):]
-            result.append(location)
-    return result
-
-def _update(d1, d2):
-    for section in d2:
-        if section in d1:
-            d1[section].update(d2[section])
-        else:
-            d1[section] = d2[section]
-    return d1
-
-def _error(*message):
-    sys.stderr.write('Error: ' + ' '.join(message) +'\n')
-    sys.exit(1)
-
-def main(args=None):
-    if args is None:
-        args = sys.argv[1:]
-
-    config_file = 'buildout.cfg'
-    verbosity = 0
-    options = []
-    while args:
-        if args[0][0] == '-':
-            op = orig_op = args.pop(0)
-            op = op[1:]
-            while op and op[0] in 'vq':
-                if op[0] == 'v':
-                    verbosity += 10
-                else:
-                    verbosity -= 10
-                op = op[1:]
-                
-            if op[:1] == 'c':
-                op = op[1:]
-                if op:
-                    config_file = op
-                else:
-                    if args:
-                        config_file = args.pop(0)
-                    else:
-                        _error("No file name specified for option", orig_op)
-            elif op:
-                _error("Invalid option", '-'+op[0])
-        elif '=' in args[0]:
-            option, value = args.pop(0).split('=', 1)
-            if len(option.split(':')) != 2:
-                _error('Invalid option:', option)
-            section, option = option.split(':')
-            options.append((section.strip(), option.strip(), value.strip()))
-        else:
-            # We've run out of command-line options and option assignnemnts
-            # The rest should be commands, so we'll stop here
-            break
-
-    if verbosity:
-        options.append(('buildout', 'verbosity', str(verbosity)))
-
-    if args:
-        command = args.pop(0)
-        if command not in ('install', 'bootstrap'):
-            _error('invalid command:', command)
-    else:
-        command = 'install'
-
-    try:
-        try:
-            buildout = Buildout(config_file, options)
-            getattr(buildout, command)(args)
-        except UserError, v:
-            _error(str(v))
-            
-    finally:
-            logging.shutdown()
-
-if sys.version_info[:2] < (2, 4):
-    def reversed(iterable):
-        result = list(iterable);
-        result.reverse()
-        return result

Deleted: zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.txt
===================================================================
--- zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.txt	2006-08-29 17:43:08 UTC (rev 69869)
+++ zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/buildout.txt	2006-08-29 17:44:45 UTC (rev 69870)
@@ -1,1201 +0,0 @@
-Buildouts
-=========
-
-The word "buildout" refers to a description of a set of parts and the
-software to create and assemble them.  It is often used informally to
-refer to an installed system based on a buildout definition.  For
-example, if we are creating an application named "Foo", then "the Foo
-buildout" is the collection of configuration and application-specific
-software that allows an instance of the application to be created.  We
-may refer to such an instance of the application informally as "a Foo
-buildout".  
-
-This document describes how to define buildouts using buildout
-configuration files and recipes.  There are three ways to set up the
-buildout software and create a buildout instance:
-
-1. Install the zc.buildout egg with easy_install and use the buildout
-   script installed in a Python scripts area.
-
-2. Use the buildout bootstrap script to create a buildout that
-   includes both the setuptools and zc.buildout eggs.  This allows you
-   to use the buildout software without modifying a Python install.
-   The buildout script is installed into your buildout local scripts
-   area.
-
-3. Use a buildoput command from an already installed buildout to 
-   bootstrap a new buildout.  (See the section on bootstraping later
-   in this document.)
-
-Often, a software project will be managed in a software repository,
-such as a subversion repository, that includes some software source
-directories, buildout configuration files, and a copy of the buildout
-bootstrap script,  To work on the project, one would check out the
-project from the repository and run the bootstrap script which
-installs setuptools and zc.buildout into the checkout as well as any
-parts defined.
-
-We have a sample buildout that we created using the bootstrap command
-of an existing buildout (method 3 above).  It has the absolute minimum
-information.  We have bin, develop-eggs, eggs and parts directories,
-and a configuration file:
-    
-    >>> ls(sample_buildout)
-    d  bin
-    -  buildout.cfg
-    d  develop-eggs
-    d  eggs
-    d  parts
-
-The bin directory contains scripts.
-
-    >>> ls(sample_buildout, 'bin')
-    -  buildout
-    -  py-zc.buildout
-
-    >>> ls(sample_buildout, 'eggs')
-    -  setuptools-0.6-py2.4.egg
-    -  zc.buildout-1.0-py2.4.egg
-
-The develop-eggs and parts directories are initially empty:
-
-    >>> ls(sample_buildout, 'develop-eggs')
-    >>> ls(sample_buildout, 'parts')
-
-The develop-eggs directory holds egg links for software being
-developed in the buildout.  We separate develop-eggs and other eggs to
-allow eggs directories to be shared across multiple buildouts.  For
-example, a common developer technique is to define a common eggs
-directory in their home that all non-develop eggs are stored in.  This
-allows larger buildouts to be set up much more quickly and saves disk
-space.
-
-The parts directory provides an area where recipes can install
-part data.  For example, if we built a custom Python, we would
-install it in the part directory.  Part data is stored in a
-sub-directory of the parts directory with the same name as the part.
-
-Buildouts are defined using configuration files.  These are in the
-format defined by the Python ConfigParser module, with extensions
-that we'll describe later.  By default, when a buildout is run, it
-looks for the file buildout.cfg in the directory where the buildout is
-run.
-
-The minimal configuration file has a buildout section that defines no
-parts:
-
-    >>> cat(sample_buildout, 'buildout.cfg')
-    [buildout]
-    parts =
-
-A part is simply something to be created by a buildout.  It can be
-almost anything, such as a Python package, a program, a directory, or
-even a configuration file.  
-
-A part is created by a recipe.  Recipes are always installed as Python
-eggs. They can be downloaded from a package server, such as the
-Python Package Index, or they can be developed as part of a project.
-Let's create a recipe as part of the sample project.  We'll create a
-recipe for creating directories.  
-
-First, we'll create a recipes directory for
-our local recipes:
-
-    >>> mkdir(sample_buildout, 'recipes')
-
-and then we'll create a source file for our mkdir recipe:
-
-    >>> write(sample_buildout, 'recipes', 'mkdir.py', 
-    ... """
-    ... import logging, os
-    ...
-    ... class Mkdir:
-    ...
-    ...     def __init__(self, buildout, name, options):
-    ...         self.buildout = buildout
-    ...         self.name = name
-    ...         self.options = options
-    ...         options['path'] = os.path.join(
-    ...                               buildout['buildout']['directory'],
-    ...                               options['path'],
-    ...                               )
-    ...
-    ...     def install(self):
-    ...         path = self.options['path']
-    ...         if not os.path.isdir(path):
-    ...             logging.getLogger(self.name).info(
-    ...                 'Creating directory %s', os.path.basename(path))
-    ...             os.mkdir(path)
-    ...         return path
-    ... """)
-
-The recipe defines a constructor that takes a buildout object, a part
-name, and an options dictionary. It saves them in instance attributes.
-
-If the path is relative, we'll interpret it as relative to the
-buildout directory.  The buildout object passed in is a mapping from
-section name to a mapping of options for that section. The buildout
-directory is available as the directory option of the buildout
-section.  We normalize the path and save it back into the options
-directory.  
-
-Any time we use data from another section, it is important to reflect
-that data in the recipe's options when the recipe is constructed.
-
-When buildout is run, it saves configuration data for installed parts
-in a file named installed.cfg.  In subsequent runs, it compares
-part-configuration data stored in the installed.cfg file and the
-part-configuration data loaded from the configuration files as
-modified by recipe constructors to decide if the configuration of a
-part has changed. If the configuration has changed, or if the recipe
-has changed, then the part is uninstalled before reinstalling it.  The
-buildout only looks at the part's options, so any data used to
-configure the part needs to be reflected in the part's options.  It is
-the job of a recipe constructor to make sure that the options include
-all rel event data.
-
-Of course, parts are also uninstalled if they are no-longer used.
-
-The install method is responsible for creating the part.  In this
-case, we need the path of the directory to create.  We'll use a
-path option from our options dictionary.
-
-The install method logs what it's doing using the Python logging call.
-
-We return the path that we installed.  If the part is uninstalled or
-reinstalled, then the path returned will be removed by the buildout
-machinery.  A recipe install method is expected to return None, a
-string, or an iterable of strings containing paths to be removed if a
-part is uninstalled.  For most recipes, this is all of the uninstall
-support needed.  A recipe can provide custom uninstall support as will
-be described later.
-
-We need to provide packaging information so that our recipe can be
-installed as an egg.  We need to define a setup script for this:
-
-    >>> write(sample_buildout, 'recipes', 'setup.py',
-    ... """
-    ... from setuptools import setup
-    ... 
-    ... setup(
-    ...     name = "recipes",
-    ...     entry_points = {'zc.buildout': ['mkdir = mkdir:Mkdir']},
-    ...     )
-    ... """)
-
-This setup script is incomplete.  It doesn't describe what is to be 
-included in a distribution.  This is fine if we never actually create
-a distribution. If recipes are going to be used only internally in a
-buildout, then we needn't include distribution information.  If we
-wanted to use the same recipes in multiple buildouts, then we'd need
-to include proper distribution data.  To find out more about creating
-distributions, see the setuptools documentation.
-
-Our setup script defines an entry point. Entry points provide
-a way for an egg to define the services it provides.  Here we've said
-that we define a zc.buildout entry point named default.  Recipe
-classes must be exposed as entry points in the zc.buildout group.  we
-give entry points names within the group.  The name "default" is
-somewhat special because it allows a recipe to be referenced using a
-package name without naming an entry point.
-
-We also need a README.txt for our recipes to avoid an annoying warning
-from distutils, on which setuptools and zc.buildout are based:
-
-    >>> write(sample_buildout, 'recipes', 'README.txt', " ")
-
-Now let's update our buildout.cfg:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data-dir
-    ... log-level = INFO
-    ...
-    ... [data-dir]
-    ... recipe = recipes:mkdir
-    ... path = mystuff
-    ... """)
-
-Let's go through the changes one by one::
-
-    develop = recipes
-
-This tells the buildout to install a development egg for our recipes.
-Any number of paths can be listed.  The paths can be relative or
-absolute.  If relative, they are treated as relative to the buildout
-directory.  They can be directory or file paths.  If a file path is
-given, it should point to a Python setup script.  If a directory path
-is given, it should point to a directory containing a setup.py file.
-Development eggs are installed before building any parts, as they may
-provide locally-defined recipes needed by the parts.
-
-::
-
-    parts = data-dir
-
-Here we've named a part to be "built".  We can use any name we want
-except that different part names must be unique and recipes will often
-use the part name to decide what to do.
-
-::
-
-    log-level = INFO
-
-The default level is WARNING, which is fairly quite.  In this example,
-we set the level to INFO so we can see more details about what the
-buildout and recipes are doing.
-
-::
-
-    [data-dir]
-    recipe = recipes:mkdir
-    path = mystuff    
-
-
-When we name a part, we also create a section of the same
-name that contains part data.  In this section, we'll define
-the recipe to be used to install the part.  In this case, we also
-specify the path to be created.
-
-Let's run the buildout.  We do so by running the build script in the
-buildout:
-
-    >>> import os
-    >>> os.chdir(sample_buildout)
-    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
-    >>> print system(buildout),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Installing data-dir
-    data-dir: Creating directory mystuff
-
-We see that the recipe created the directory, as expected:
-
-    >>> ls(sample_buildout)
-    -  .installed.cfg
-    d  bin
-    -  buildout.cfg
-    d  develop-eggs
-    d  eggs
-    d  mystuff
-    d  parts
-    d  recipes
-
-In addition, .installed.cfg has been created containing information
-about the part we installed:
-
-    >>> cat(sample_buildout, '.installed.cfg')
-    [buildout]
-    parts = data-dir
-    <BLANKLINE>
-    [data-dir]
-    __buildout_installed__ = /tmp/sample-buildout/mystuff
-    __buildout_signature__ = recipes-c7vHV6ekIDUPy/7fjAaYjg==
-    path = /tmp/sample-buildout/mystuff
-    recipe = recipes:mkdir
-
-Note that the directory we installed is included in .installed.cfg.
-In addition, the path option includes the actual destination
-directory. 
-
-If we change the name of the directory in the configuration file,
-we'll see that the directory gets removed and recreated:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data-dir
-    ... log-level = INFO
-    ...
-    ... [data-dir]
-    ... recipe = recipes:mkdir
-    ... path = mydata
-    ... """)
-
-    >>> print system(buildout),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling data-dir
-    buildout: Installing data-dir
-    data-dir: Creating directory mydata
-
-    >>> ls(sample_buildout)
-    -  .installed.cfg
-    d  bin
-    -  buildout.cfg
-    d  develop-eggs
-    d  eggs
-    d  mydata
-    d  parts
-    d  recipes
-
-Configuration file syntax
--------------------------
-
-As mentioned earlier, buildout configuration files use the format
-defined by the Python ConfigParser module with extensions.  The
-extensions are:
-
-- option names are case sensitive
-
-- option values can ue a substitution syntax, described below, to
-  refer to option values in specific sections.
-
-The ConfigParser syntax is very flexible.  Section names can contain
-any characters other than newlines and right square braces ("]").
-Option names can contain any characters other than newlines, colons,
-and equal signs, can not start with a space, and don't include
-trailing spaces.
-
-It is likely that, in the future, some characters will be given
-special buildout-defined meanings.  This is already true of the
-characters ":", "$", "%", "(", and ")".  For now, it is a good idea to
-keep section and option names simple, sticking to alphanumeric
-characters, hyphens, and periods.
-
-Variable substitutions
-----------------------
-
-Buildout configuration files support two kinds of substitutions,
-standard ConfigParser substitutions, and string-template
-substitutions.  To illustrate this, we'll create an debug recipe to
-allow us to see interactions with the buildout:
-
-    >>> write(sample_buildout, 'recipes', 'debug.py', 
-    ... """
-    ... class Debug:
-    ...
-    ...     def __init__(self, buildout, name, options):
-    ...         self.buildout = buildout
-    ...         self.name = name
-    ...         self.options = options
-    ...
-    ...     def install(self):
-    ...         items = self.options.items()
-    ...         items.sort()
-    ...         for option, value in items:
-    ...             print option, value
-    ... """)
-
-In this example, we've used a simple base class that provides a
-boilerplate constructor.  This recipe doesn't actually create
-anything. The install method doesn't return anything, because it
-didn't create any files or directories.
-
-We also have to update our setup script:
-
-    >>> write(sample_buildout, 'recipes', 'setup.py',
-    ... """
-    ... from setuptools import setup
-    ... entry_points = (
-    ... '''
-    ... [zc.buildout]
-    ... mkdir = mkdir:Mkdir
-    ... debug = debug:Debug
-    ... ''')
-    ... setup(name="recipes", entry_points=entry_points)
-    ... """)
-
-We've rearranged the script a bit to make the entry points easier to
-edit.  In particular, entry points are now defined as a configuration
-string, rather than a dictionary.
-
-Let's update our configuration to provide variable substitution
-examples:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data-dir debug
-    ... log-level = INFO
-    ...
-    ... [debug]
-    ... recipe = recipes:debug
-    ... File 1 = ${data-dir:path}/file
-    ... File 2 = %(File 1)s.out
-    ... File 3 = %(base)s/file3
-    ... File 4 = ${debug:File 3}/log
-    ...
-    ... [data-dir]
-    ... recipe = recipes:mkdir
-    ... path = mydata
-    ...
-    ... [DEFAULT]
-    ... base = var
-    ... """)
-
-In this example, we've used ConfigParser substitutions for file2 and
-file3.  This type of substitution uses Python string format syntax.
-Valid names are options in the same section and options defined in the
-DEFAULT section.  
-
-We used a string-template substitution for file1.  This type of
-substitution uses the string.Template syntax.  Names substituted are
-qualified option names, consisting of a section name and option name
-joined by a colon.
-
-Now, if we run the buildout, we'll see the options with the values
-substituted. 
-
-    >>> print system(buildout),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling data-dir
-    buildout: Installing data-dir
-    data-dir: Creating directory mydata
-    buildout: Installing debug
-    File 1 mydata/file
-    File 2 mydata/file.out
-    File 3 var/file3
-    File 4 var/file3/log
-    base var
-    recipe recipes:debug
-
-It might seem surprising that mydata was created again.  This is
-because we changed our recipes package by adding the debug module.
-The buildout system didn't know if this module could effect the mkdir
-recipe, so it assumed it could and reinstalled mydata.  If we rerun
-the buildout:
-
-    >>> print system(buildout),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Installing data-dir
-    buildout: Installing debug
-    File 1 mydata/file
-    File 2 mydata/file.out
-    File 3 var/file3
-    File 4 var/file3/log
-    base var
-    recipe recipes:debug
-
-We can see that mydata was not recreated.
-
-Note that, in this case, we didn't specify a log level, so
-we didn't get output about what the buildout was doing.
-
-Section and option names in variable substitutions are only allowed to
-contain alphanumeric characters, hyphens, periods and spaces. This
-restriction might be relaxed in future releases.
-
-Multiple configuration files
-----------------------------
-
-You can use multiple configuration files.  From your main
-configuration file, you can include other configuration files in 2
-ways:
-
-- Your configuration file can "extend" another configuration file.
-  Option are read from the other configuration file if they aren't
-  already defined by your configuration file.
-
-- Your configuration file can be "extended-by" another configuration
-  file, In this case, the options in the other configuration file
-  override options in your configuration file. 
-
-The configuration files your file extends or is extended by can extend
-or be extended by other configuration files.  The same file may be
-used more than once although, of course, cycles aren't allowed.
-
-To see how this works, we use an example:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... extends = base.cfg
-    ...
-    ... [debug]
-    ... op = buildout
-    ... """)
-
-    >>> write(sample_buildout, 'base.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug
-    ...
-    ... [debug]
-    ... recipe = recipes:debug
-    ... op = base
-    ... """)
-
-    >>> print system(buildout),
-    op buildout
-    recipe recipes:debug
-
-The example is pretty trivial, but the pattern it illustrates is
-pretty common.  In a more practical example, the base buildout might
-represent a product and the extending buildout might be a
-customization. 
-
-Here is a more elaborate example. 
-
-    >>> extensions = mkdtemp()
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... extends = b1.cfg b2.cfg
-    ... extended-by = e1.cfg %(e2)s
-    ...
-    ... [debug]
-    ... op = %%(name)s
-    ...
-    ... [DEFAULT]
-    ... name = buildout
-    ... """ % dict(e2=os.path.join(extensions, 'e2.cfg')))
-
-    >>> write(sample_buildout, 'b1.cfg',
-    ... """
-    ... [buildout]
-    ... extends = base.cfg
-    ...
-    ... [debug]
-    ... op1 = %(name)s 1
-    ... op2 = %(name)s 2
-    ... op3 = %(name)s 3
-    ...
-    ... [DEFAULT]
-    ... name = b1
-    ... """)
-
-    >>> write(sample_buildout, 'b2.cfg',
-    ... """
-    ... [buildout]
-    ... extends = base.cfg
-    ...
-    ... [debug]
-    ... op3 = %(name)s 3
-    ... op4 = %(name)s 4
-    ... op5 = %(name)s 5
-    ...
-    ... [DEFAULT]
-    ... name = b2
-    ... """)
-
-    >>> write(sample_buildout, 'base.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug
-    ...
-    ... [debug]
-    ... recipe = recipes:debug
-    ... name = base
-    ... """)
-
-    >>> write(sample_buildout, 'e1.cfg',
-    ... """
-    ... [debug]
-    ... op1 = %(name)s 1
-    ...
-    ... [DEFAULT]
-    ... name = e1
-    ... """)
-
-    >>> write(extensions, 'e2.cfg',
-    ... """
-    ... [buildout]
-    ... extends = eb.cfg
-    ... extended-by = ee.cfg
-    ... """)
-
-    >>> write(extensions, 'eb.cfg',
-    ... """
-    ... [debug]
-    ... op5 = %(name)s 5
-    ...
-    ... [DEFAULT]
-    ... name = eb
-    ... """)
-
-    >>> write(extensions, 'ee.cfg',
-    ... """
-    ... [debug]
-    ... op6 = %(name)s 6
-    ...
-    ... [DEFAULT]
-    ... name = ee
-    ... """)
-
-    >>> print system(buildout),
-    name ee
-    op buildout
-    op1 e1 1
-    op2 b1 2
-    op3 b2 3
-    op4 b2 4
-    op5 eb 5
-    op6 ee 6
-    recipe recipes:debug
-
-There are several things to note about this example:
-
-- We can name multiple files in an extends or extended-by option.
-
-- We can reference files recursively.
-
-- DEFAULT sections only directly affect the configuration file they're
-  used in, but they can have secondary effects.  For example, the name
-  option showed up in the debug section because it was defined in the
-  debug sections in several of the input files by virtue of being in
-  their DEFAULT sections.
-
-- Relative file names in extended and extended-by options are
-  interpreted relative to the directory containing the referencing
-  configuration file.  The files eb.cfg and ee.cfg were found in the
-  extensions directory because they were referenced from a file in
-  that directory.
-
-User defaults
--------------
-
-If the file $HOME/.buildout/defaults.cfg, exists, it is read before
-reading the configuration file.  ($HOME is the value of the HOME
-environment variable. The '/' is replaced by the operating system file
-delimiter.)
-
-    >>> home = mkdtemp()
-    >>> mkdir(home, '.buildout')
-    >>> write(home, '.buildout', 'default.cfg',
-    ... """
-    ... [debug]
-    ... op1 = 1
-    ... op7 = 7
-    ... """)
-
-    >>> os.environ['HOME'] = home
-    >>> print system(buildout),
-    name ee
-    op buildout
-    op1 e1 1
-    op2 b1 2
-    op3 b2 3
-    op4 b2 4
-    op5 eb 5
-    op6 ee 6
-    op7 7
-    recipe recipes:debug
-
-    >>> del os.environ['HOME']
-
-Command-line usage
-------------------
-
-A number of arguments can be given on the buildout command line.  The
-command usage is::
-
-  buildout [-c file] [-q] [-v] [assignments] [command [command arguments]]
-
-The -c option can be used to specify a configuration file, rather than
-buildout.cfg in the current directory.  
-
-The -q and -v decrement and increment the verbosity by 10.  The
-verbosity is used to adjust the logging level.  The verbosity is
-subtracted from the numeric value of the log-level option specified in
-the configuration file.
-
-Assignments are of the form::
-
-  section_name:option_name=value
-
-Options and assignments can be given in any order.
-
-Here's an example:
-
-    >>> write(sample_buildout, 'other.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug
-    ... installed = .other.cfg
-    ...
-    ... [debug]
-    ... name = other
-    ... recipe = recipes:debug
-    ... """)
-
-Note that we used the installed buildout option to specify an
-alternate file to store information about installed parts.
-    
-    >>> print system(buildout+' -c other.cfg debug:op1=foo -v'),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Installing debug
-    name other
-    op1 foo
-    recipe recipes:debug
-
-Here we used the -c option to specify an alternate configuration file, 
-and the -v option to increase the level of logging from the default,
-WARNING.
-
-Options can also be combined in the usual Unix way, as in:
-    
-    >>> print system(buildout+' -vcother.cfg debug:op1=foo'),
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Installing debug
-    name other
-    op1 foo
-    recipe recipes:debug
-
-Here we combined the -v and -c options with the configuration file
-name.  Note that the -c option has to be last, because it takes an
-argument.
-
-    >>> os.remove(os.path.join(sample_buildout, 'other.cfg'))
-    >>> os.remove(os.path.join(sample_buildout, '.other.cfg'))
-
-The most commonly used command is 'install' and it takes a
-list of parts to install. if any parts are specified, then they must
-be listed in the buildout parts option and only those parts are
-installed.  To illustrate this, we'll update our configuration and run
-the buildout in the usual way:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug d1 d2 d3
-    ...
-    ... [d1]
-    ... recipe = recipes:mkdir
-    ... path = d1
-    ...
-    ... [d2]
-    ... recipe = recipes:mkdir
-    ... path = d2
-    ...
-    ... [d3]
-    ... recipe = recipes:mkdir
-    ... path = d3
-    ...
-    ... [debug]
-    ... recipe = recipes:debug
-    ... """)
-
-    >>> print system(buildout+' -v'),
-    buildout: Running /sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling debug
-    buildout: Installing debug
-    recipe recipes:debug
-    buildout: Installing d1
-    d1: Creating directory d1
-    buildout: Installing d2
-    d2: Creating directory d2
-    buildout: Installing d3
-    d3: Creating directory d3
-    
-    >>> ls(sample_buildout)
-    -  .installed.cfg
-    -  b1.cfg
-    -  b2.cfg
-    -  base.cfg
-    d  bin
-    -  buildout.cfg
-    d  d1
-    d  d2
-    d  d3
-    d  develop-eggs
-    -  e1.cfg
-    d  eggs
-    d  parts
-    d  recipes
-
-    >>> cat(sample_buildout, '.installed.cfg')
-    [buildout]
-    parts = debug d1 d2 d3
-    <BLANKLINE>
-    [debug]
-    __buildout_installed__ = 
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    recipe = recipes:debug
-    <BLANKLINE>
-    [d1]
-    __buildout_installed__ = /tmp/sample-buildout/d1
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/d1
-    recipe = recipes:mkdir
-    <BLANKLINE>
-    [d2]
-    __buildout_installed__ = /tmp/sample-buildout/d2
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/d2
-    recipe = recipes:mkdir
-    <BLANKLINE>
-    [d3]
-    __buildout_installed__ = /tmp/sample-buildout/d3
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/d3
-    recipe = recipes:mkdir
-
-Now we'll update our configuration file:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug d2 d3 d4
-    ...
-    ... [d2]
-    ... recipe = recipes:mkdir
-    ... path = data2
-    ...
-    ... [d3]
-    ... recipe = recipes:mkdir
-    ... path = data3
-    ...
-    ... [d4]
-    ... recipe = recipes:mkdir
-    ... path = data4
-    ...
-    ... [debug]
-    ... recipe = recipes:debug
-    ... x = 1
-    ... """)
-
-and run the buildout specifying just d3 and d4:
-
-    >>> print system(buildout+' -v install d3 d4'),
-    buildout: Running /sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling d3
-    buildout: Installing d3
-    d3: Creating directory data3
-    buildout: Installing d4
-    d4: Creating directory data4
-    
-    >>> ls(sample_buildout)
-    -  .installed.cfg
-    -  b1.cfg
-    -  b2.cfg
-    -  base.cfg
-    d  bin
-    -  buildout.cfg
-    d  d1
-    d  d2
-    d  data3
-    d  data4
-    d  develop-eggs
-    -  e1.cfg
-    d  eggs
-    d  parts
-    d  recipes
-    
-Only the d3 and d4 recipes ran.  d3 was removed and data3 and data4
-were created.
-
-The .installed.cfg is only updated for the recipes that ran:
-
-    >>> cat(sample_buildout, '.installed.cfg')
-    [buildout]
-    parts = debug d2 d3 d4 d1
-    <BLANKLINE>
-    [debug]
-    __buildout_installed__ = 
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    recipe = recipes:debug
-    <BLANKLINE>
-    [d2]
-    __buildout_installed__ = /tmp/sample-buildout/d2
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/d2
-    recipe = recipes:mkdir
-    <BLANKLINE>
-    [d3]
-    __buildout_installed__ = /tmp/sample-buildout/data3
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/data3
-    recipe = recipes:mkdir
-    <BLANKLINE>
-    [d4]
-    __buildout_installed__ = /tmp/sample-buildout/data4
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/data4
-    recipe = recipes:mkdir
-    <BLANKLINE>
-    [d1]
-    __buildout_installed__ = /tmp/sample-buildout/d1
-    __buildout_signature__ = recipes-PiIFiO8ny5yNZ1S3JfT0xg==
-    path = /tmp/sample-buildout/d1
-    recipe = recipes:mkdir
-
-Note that the installed data for debug, d1, and d2 haven't changed,
-because we didn't install those parts and that the d1 and d2
-directories are still there.
-
-Now, if we run the buildout without the install command:
-
-    >>> print system(buildout+' -v'),
-    buildout: Running /sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling d1
-    buildout: Uninstalling d2
-    buildout: Uninstalling debug
-    buildout: Installing debug
-    recipe recipes:debug
-    x 1
-    buildout: Installing d2
-    d2: Creating directory data2
-    buildout: Installing d3
-    buildout: Installing d4
-
-We see the output of the debug recipe and that data2 was created.  We
-also see that d1 and d2 have gone away:
-
-    >>> ls(sample_buildout)
-    -  .installed.cfg
-    -  b1.cfg
-    -  b2.cfg
-    -  base.cfg
-    d  bin
-    -  buildout.cfg
-    d  data2
-    d  data3
-    d  data4
-    d  develop-eggs
-    -  e1.cfg
-    d  eggs
-    d  parts
-    d  recipes
-
-Alternate directory and file locations
---------------------------------------
-
-The buildout normally puts the bin, eggs, and parts directories in the
-directory in the directory containing the configuration file. You can
-provide alternate locations, and even names for these directories.
-
-    >>> alt = mkdtemp('sample-alt')
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts = 
-    ... develop-eggs-directory = %(developbasket)s
-    ... eggs-directory = %(basket)s
-    ... bin-directory = %(scripts)s
-    ... parts-directory = %(work)s
-    ... """ % dict(
-    ...    developbasket = os.path.join(alt, 'developbasket'),
-    ...    basket = os.path.join(alt, 'basket'),
-    ...    scripts = os.path.join(alt, 'scripts'),
-    ...    work = os.path.join(alt, 'work'),
-    ... ))
-
-    >>> print system(buildout+' -v'),
-    buildout: Creating directory /tmp/sample-alt/scripts
-    buildout: Creating directory /tmp/sample-alt/work
-    buildout: Creating directory /tmp/sample-alt/basket
-    buildout: Creating directory /sample-alt/developbasket
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-    buildout: Uninstalling d4
-    buildout: Uninstalling d3
-    buildout: Uninstalling d2
-    buildout: Uninstalling debug
-
-    >>> ls(alt)
-    d  basket
-    d  developbasket
-    d  scripts
-    d  work
-
-    >>> ls(alt, 'developbasket')    
-    -  recipes.egg-link
-
-You can also specify an alternate buildout directory:
-
-    >>> alt = mkdtemp('sample-alt')
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... directory = %(alt)s
-    ... develop = %(recipes)s
-    ... parts = 
-    ... """ % dict(
-    ...    alt=alt,
-    ...    recipes=os.path.join(sample_buildout, 'recipes'),
-    ...    ))
- 
-    >>> print system(buildout+' -v'),
-    buildout: Creating directory /tmp/sample-alt/bin
-    buildout: Creating directory /tmp/sample-alt/parts
-    buildout: Creating directory /tmp/sample-alt/eggs
-    buildout: Creating directory /tmp/sample-alt/develop-eggs
-    buildout: Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-
-    >>> ls(alt)
-    -  .installed.cfg
-    d  bin
-    d  develop-eggs
-    d  eggs
-    d  parts
-
-    >>> ls(alt, 'develop-eggs')    
-    -  recipes.egg-link
-
-Logging control
----------------
-
-Three buildout options are used to control logging:
-
-log-level 
-   specifies the log level
-
-verbosity 
-   adjusts the log level
-
-log-format
-   allows an alternate logging for mat to be specified
-
-We've already seen the log level and verbosity.  Let's look at an example
-of changing the format:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... develop = recipes
-    ... parts =
-    ... log-level = 25
-    ... verbosity = 5
-    ... log-format = %%(levelname)s %%(message)s
-    ... """)
- 
-Here, we've changed the format to include the log-level name, rather
-than the logger name.  Note that we had to double percent signs,
-because configuration options allow ConfigParser variable substitution.
-
-We've also illustrated, with a contrived example, that the log level
-can be a numeric value and that the verbosity can be specified in the
-configuration file.  Because the verbosity is subtracted from the log
-level, we get a final log level of 20, which is the INFO level.
-
-    >>> print system(buildout),
-    INFO Running /tmp/sample-buildout/recipes/setup.py -q develop ...
-
-Predefined buildout options
----------------------------
-
-Buildouts have a number of predefined options that recipes can use
-and that users can override in their configuration files.  To see
-these, we'll run a minimal buildout configuration with a debug logging
-level.  One of the features of debug logging is that the configuration
-database is shown.
-         
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... """
-    ... [buildout]
-    ... parts =
-    ... """)
-
-    >>> print system(buildout+' -vv'),
-    Configuration data:
-    [buildout]
-    bin-directory = /tmp/sample-buildout/bin
-    develop-eggs-directory = /tmp/sample-buildout/develop-eggs
-    directory = /tmp/sample-buildout
-    eggs-directory = /tmp/sample-buildout/eggs
-    executable = /usr/local/bin/python2.3
-    installed = /tmp/sample-buildout/.installed.cfg
-    log-format = %%(name)s: %%(message)s
-    log-level = WARNING
-    parts = 
-    parts-directory = /tmp/sample-buildout/parts
-    python = buildout
-    verbosity = 20
-    <BLANKLINE>
-
-All of these options can be overridden by configuration files or by
-command-line assignments.  We've discussed most of these options
-already, but let's review them and touch on some we haven't discussed:
-
-bin-directory
-   The directory path where scripts are written.  This can be a
-   relative path, which is interpreted relative to the directory
-   option.
-
-develop-eggs-directory
-   The directory path where development egg links are created for software
-   being created in the local project.  This can be a relative path,
-   which is interpreted relative to the directory option.
-
-directory
-   The buildout directory.  This is the base for other buildout file
-   and directory locations, when relative locations are used.
-
-eggs-directory
-   The directory path where downloaded eggs are put.  It is common to share
-   this directory across buildouts. Eggs in this directory should
-   *never* be modified.  This can be a relative path, which is
-   interpreted relative to the directory option.
-
-executable
-   The Python executable used to run the buildout.  See the python
-   option below.
-
-installed
-   The file path where information about the results of the previous
-   buildout run is written.  This can be a relative path, which is
-   interpreted relative to the directory option.  This file provides
-   an inventory of installed parts with information needed to decide
-   which if any parts need to be uninstalled.
-
-log-format
-   The format used for logging messages.
-
-log-level
-   The log level before verbosity adjustment
-
-parts
-   A white space separated list of parts to be installed.
-
-parts-directory
-   A working directory that parts can used to store data.
-
-python
-   The name of a section containing information about the default
-   Python interpreter.  Recipes that need a installation
-   typically have options to tell them which Python installation to
-   use.  By convention, if a section-specific option isn't used, the
-   option is looked for in the buildout section.  The option must
-   point to a section with an executable option giving the path to a
-   Python executable.  By default, the buildout section defines the
-   default Python as the Python used to run the buildout.
-
-verbosity
-   A log-level adjustment.  Typically, this is set via the -q and -v
-   command-line options.
-
-
-Bootstrapping
--------------
-
-If zc.buildout is installed, you can use it to create a new buildout
-with it's own local copies of zc.buildout and setuptools and with
-local buildout scripts. 
-
-    >>> sample_bootstrapped = mkdtemp('sample-bootstrapped')
-
-    >>> print system(buildout
-    ...              +' -c'+os.path.join(sample_bootstrapped, 'setup.cfg')
-    ...              +' bootstrap'),
-    Warning: creating /sample-bootstrapped/setup.cfg
-
-Note that a basic setup.cfg was created for us.
-
-    >>> ls(sample_bootstrapped)
-    d  bin
-    d  develop-eggs
-    d  eggs
-    d  parts
-    -  setup.cfg
-
-    >>> ls(sample_bootstrapped, 'bin')
-    -  buildout
-    -  py-zc.buildout
-
-    >>> ls(sample_bootstrapped, 'eggs')
-    -  setuptools-0.6-py2.3.egg
-    -  zc.buildout-1.0-py2.3.egg
-
-Note that the buildout script was installed but not run.  To run
-the buildout, we'd have to run the installed buildout script.

Modified: zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/tests.py
===================================================================
--- zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/tests.py	2006-08-29 17:43:08 UTC (rev 69869)
+++ zc.buildout/trunk/zc.buildoutsupport/zc/buildoutsupport/tests.py	2006-08-29 17:44:45 UTC (rev 69870)
@@ -24,203 +24,6 @@
 if os_path_sep == '\\':
     os_path_sep *= 2
 
-def buildout_error_handling():
-    r"""Buildout error handling
-
-Asking for a section that doesn't exist, yields a key error:
-
-    >>> import os
-    >>> os.chdir(sample_buildout)
-    >>> import zc.buildout.buildout
-    >>> buildout = zc.buildout.buildout.Buildout('buildout.cfg', [])
-    >>> buildout['eek']
-    Traceback (most recent call last):
-    ...
-    KeyError: 'eek'
-
-Asking for an option that doesn't exist, a MissingOption error is raised:
-
-    >>> buildout['buildout']['eek']
-    Traceback (most recent call last):
-    ...
-    MissingOption: Missing option: buildout:eek
-
-It is an error to create a variable-reference cycle:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data_dir debug
-    ... x = ${buildout:y}
-    ... y = ${buildout:z}
-    ... z = ${buildout:x}
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
-    Error: Circular reference in substitutions.
-    We're evaluating buildout:y, buildout:z, buildout:x
-    and are referencing: buildout:y.
-
-It is an error to use funny characters in variable refereces:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data_dir debug
-    ... x = ${bui$ldout:y}
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: The section name in substitution, ${bui$ldout:y},
-    has invalid characters.
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data_dir debug
-    ... x = ${buildout:y{z}
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: The option name in substitution, ${buildout:y{z},
-    has invalid characters.
-
-and too have too many or too few colons:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data_dir debug
-    ... x = ${parts}
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: The substitution, ${parts},
-    doesn't contain a colon.
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = data_dir debug
-    ... x = ${buildout:y:z}
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: The substitution, ${buildout:y:z},
-    has too many colons.
-
-Al parts have to have a section:
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... parts = x
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: No section was specified for part x
-
-and all parts have to have a specified recipe:
-
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... parts = x
-    ...
-    ... [x]
-    ... foo = 1
-    ... ''')
-
-    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
-    Error: Missing option: x:recipe
-
-"""
- 
-def test_comparing_saved_options_with_funny_characters():
-    """
-    If an option has newlines, extra/odd spaces or a %, we need to make
-    sure the comparison with the saved value works correctly.
-
-    >>> mkdir(sample_buildout, 'recipes')
-    >>> write(sample_buildout, 'recipes', 'debug.py', 
-    ... '''
-    ... class Debug:
-    ...     def __init__(self, buildout, name, options):
-    ...         options['debug'] = \"\"\"  <zodb>
-    ...
-    ...   <filestorage>
-    ...     path foo
-    ...   </filestorage>
-    ...
-    ... </zodb>  
-    ...      \"\"\"
-    ...         options['debug1'] = \"\"\"
-    ... <zodb>
-    ...
-    ...   <filestorage>
-    ...     path foo
-    ...   </filestorage>
-    ...
-    ... </zodb>  
-    ... \"\"\"
-    ...         options['debug2'] = '  x  '
-    ...         options['debug3'] = '42'
-    ...         options['format'] = '%3d'
-    ...
-    ...     def install(self):
-    ...         open('t', 'w').write('t')
-    ...         return 't'
-    ... ''')
-
-
-    >>> write(sample_buildout, 'recipes', 'setup.py',
-    ... '''
-    ... from setuptools import setup
-    ... setup(
-    ...     name = "recipes",
-    ...     entry_points = {'zc.buildout': ['default = debug:Debug']},
-    ...     )
-    ... ''')
-
-    >>> write(sample_buildout, 'recipes', 'README.txt', " ")
-
-    >>> write(sample_buildout, 'buildout.cfg',
-    ... '''
-    ... [buildout]
-    ... develop = recipes
-    ... parts = debug
-    ...
-    ... [debug]
-    ... recipe = recipes
-    ... ''')
-
-    >>> os.chdir(sample_buildout)
-    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
-
-    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
-    buildout: Running ...setup.py -q develop ...
-    buildout: Installing debug
-
-If we run the buildout again, we shoudn't get a message about
-uninstalling anything because the configuration hasn't changed.
-
-    >>> print system(buildout+' -v'),
-    buildout: Running setup.py -q develop ...
-    buildout: Installing debug
-"""
-
-def linkerSetUp(test):
-    zc.buildout.testing.buildoutSetUp(test, clear_home=False)
-    zc.buildout.testing.multi_python(test)
-    zc.buildout.testing.setUpServer(test, zc.buildout.testing.make_tree(test))
-
 def easy_install_SetUp(test):
     zc.buildout.testing.buildoutSetUp(test)
     zc.buildout.testing.multi_python(test)
@@ -284,28 +87,6 @@
 def test_suite():
     return unittest.TestSuite((
         doctest.DocFileSuite(
-            'buildout.txt',
-            setUp=zc.buildout.testing.buildoutSetUp,
-            tearDown=zc.buildout.testing.buildoutTearDown,
-            checker=renormalizing.RENormalizing([
-               (re.compile('__buildout_signature__ = recipes-\S+'),
-                '__buildout_signature__ = recipes-SSSSSSSSSSS'),
-               (re.compile('\S+sample-(\w+)%s(\S+)' % os_path_sep),
-                r'/sample-\1/\2'),
-               (re.compile('\S+sample-(\w+)'), r'/sample-\1'),
-               (re.compile('executable = \S+python\S*'),
-                'executable = python'),
-               (re.compile('setuptools-\S+[.]egg'), 'setuptools.egg'),
-               (re.compile('zc.buildout(-\S+)?[.]egg(-link)?'),
-                'zc.buildout.egg'),
-               (re.compile('creating \S*setup.cfg'), 'creating setup.cfg'),
-               (re.compile('(\n?)-  ([a-zA-Z_.-]+)-script.py\n-  \\2.exe\n'),
-                '\\1-  \\2\n'),
-               (re.compile("(\w)%s(\w)" % os_path_sep), r"\1/\2"),
-               ])
-            ),
-        
-        doctest.DocFileSuite(
             'easy_install.txt', 
             setUp=easy_install_SetUp,
             tearDown=zc.buildout.testing.buildoutTearDown,
@@ -327,15 +108,6 @@
                (re.compile('#!\S+python\S+'), '#!python'),
                ]),
             ),
-        doctest.DocTestSuite(
-            setUp=zc.buildout.testing.buildoutSetUp,
-            tearDown=zc.buildout.testing.buildoutTearDown,
-
-            checker=PythonNormalizing([
-               (re.compile("buildout: Running \S*setup.py"),
-                'buildout: Running setup.py'),
-               ]),
-            )
         ))
 
 if __name__ == '__main__':



More information about the Checkins mailing list