eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/buildout.py
changeset 307 c6bca38c1cbf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/buildout.py	Sat Jan 08 11:20:57 2011 +0530
@@ -0,0 +1,1835 @@
+##############################################################################
+#
+# Copyright (c) 2005-2009 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
+"""
+
+from rmtree import rmtree
+try:
+    from hashlib import md5
+except ImportError:
+    # Python 2.4 and older
+    from md5 import md5
+
+import ConfigParser
+import copy
+import distutils.errors
+import glob
+import itertools
+import logging
+import os
+import pkg_resources
+import re
+import shutil
+import sys
+import tempfile
+import UserDict
+import warnings
+import zc.buildout
+import zc.buildout.download
+import zc.buildout.easy_install
+
+
+realpath = zc.buildout.easy_install.realpath
+
+pkg_resources_loc = pkg_resources.working_set.find(
+    pkg_resources.Requirement.parse('setuptools')).location
+
+_isurl = re.compile('([a-zA-Z0-9+.-]+)://').match
+
+is_jython = sys.platform.startswith('java')
+
+if is_jython:
+    import subprocess
+
+_sys_executable_has_broken_dash_S = (
+    zc.buildout.easy_install._has_broken_dash_S(sys.executable))
+
+class MissingOption(zc.buildout.UserError, KeyError):
+    """A required option was missing.
+    """
+
+class MissingSection(zc.buildout.UserError, KeyError):
+    """A required section is missing.
+    """
+
+    def __str__(self):
+        return "The referenced section, %r, was not defined." % self[0]
+
+
+def _annotate_section(section, note):
+    for key in section:
+        section[key] = (section[key], note)
+    return section
+
+def _annotate(data, note):
+    for key in data:
+        data[key] = _annotate_section(data[key], note)
+    return data
+
+def _print_annotate(data):
+    sections = data.keys()
+    sections.sort()
+    print
+    print "Annotated sections"
+    print "="*len("Annotated sections")
+    for section in sections:
+        print
+        print '[%s]' % section
+        keys = data[section].keys()
+        keys.sort()
+        for key in keys:
+            value, notes = data[section][key]
+            keyvalue = "%s= %s" % (key, value)
+            print keyvalue
+            line = '   '
+            for note in notes.split():
+                if note == '[+]':
+                    line = '+= '
+                elif note == '[-]':
+                    line = '-= '
+                else:
+                    print line, note
+                    line = '   '
+    print
+
+
+def _unannotate_section(section):
+    for key in section:
+        value, note = section[key]
+        section[key] = value
+    return section
+
+def _unannotate(data):
+    for key in data:
+        data[key] = _unannotate_section(data[key])
+    return data
+
+_buildout_default_options = _annotate_section({
+    'accept-buildout-test-releases': 'false',
+    'allow-hosts': '*',
+    'allow-picked-versions': 'true',
+    'allowed-eggs-from-site-packages': '*',
+    'bin-directory': 'bin',
+    'develop-eggs-directory': 'develop-eggs',
+    'eggs-directory': 'eggs',
+    'executable': sys.executable,
+    'exec-sitecustomize': 'true',
+    'find-links': '',
+    'include-site-packages': 'true',
+    'install-from-cache': 'false',
+    'installed': '.installed.cfg',
+    'log-format': '',
+    'log-level': 'INFO',
+    'newest': 'true',
+    'offline': 'false',
+    'parts-directory': 'parts',
+    'prefer-final': 'false',
+    'python': 'buildout',
+    'relative-paths': 'false',
+    'socket-timeout': '',
+    'unzip': 'false',
+    'use-dependency-links': 'true',
+    }, 'DEFAULT_VALUE')
+
+
+class Buildout(UserDict.DictMixin):
+
+    def __init__(self, config_file, cloptions,
+                 user_defaults=True, windows_restart=False, command=None):
+
+        __doing__ = 'Initializing.'
+
+        self.__windows_restart = windows_restart
+
+        # default options
+        data = dict(buildout=_buildout_default_options.copy())
+        self._buildout_dir = os.getcwd()
+
+        if not _isurl(config_file):
+            config_file = os.path.abspath(config_file)
+            base = os.path.dirname(config_file)
+            if not os.path.exists(config_file):
+                if command == 'init':
+                    print 'Creating %r.' % config_file
+                    open(config_file, 'w').write('[buildout]\nparts = \n')
+                elif command == 'setup':
+                    # Sigh. This model of a buildout instance
+                    # with methods is breaking down. :(
+                    config_file = None
+                    data['buildout']['directory'] = ('.', 'COMPUTED_VALUE')
+                else:
+                    raise zc.buildout.UserError(
+                        "Couldn't open %s" % config_file)
+
+            if config_file:
+                data['buildout']['directory'] = (os.path.dirname(config_file),
+                    'COMPUTED_VALUE')
+        else:
+            base = None
+
+
+        cloptions = dict(
+            (section, dict((option, (value, 'COMMAND_LINE_VALUE'))
+                           for (_, option, value) in v))
+            for (section, v) in itertools.groupby(sorted(cloptions),
+                                                  lambda v: v[0])
+            )
+        override = cloptions.get('buildout', {}).copy()
+
+        # load user defaults, which override defaults
+        if user_defaults:
+            user_config = os.path.join(os.path.expanduser('~'),
+                                       '.buildout', 'default.cfg')
+            if os.path.exists(user_config):
+                _update(data, _open(os.path.dirname(user_config), user_config,
+                                    [], data['buildout'].copy(), override))
+
+        # load configuration files
+        if config_file:
+            _update(data, _open(os.path.dirname(config_file), config_file, [],
+                                data['buildout'].copy(), override))
+
+        # apply command-line options
+        _update(data, cloptions)
+
+        self._annotated = copy.deepcopy(data)
+        self._raw = _unannotate(data)
+        self._data = {}
+        self._parts = []
+        # provide some defaults before options are parsed
+        # because while parsing options those attributes might be
+        # used already (Gottfried Ganssauge)
+        buildout_section = data['buildout']
+
+        # Try to make sure we have absolute paths for standard
+        # directories. We do this before doing substitutions, in case
+        # a one of these gets read by another section.  If any
+        # variable references are used though, we leave it as is in
+        # _buildout_path.
+        if 'directory' in buildout_section:
+            self._buildout_dir = buildout_section['directory']
+            for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
+                d = self._buildout_path(buildout_section[name+'-directory'])
+                buildout_section[name+'-directory'] = d
+
+        # Attributes on this buildout object shouldn't be used by
+        # recipes in their __init__.  It can cause bugs, because the
+        # recipes will be instantiated below (``options = self['buildout']``)
+        # before this has completed initializing.  These attributes are
+        # left behind for legacy support but recipe authors should
+        # beware of using them.  A better practice is for a recipe to
+        # use the buildout['buildout'] options.
+        links = buildout_section['find-links']
+        self._links = links and links.split() or ()
+        allow_hosts = buildout_section['allow-hosts'].split('\n')
+        self._allow_hosts = tuple([host.strip() for host in allow_hosts
+                                   if host.strip() != ''])
+        self._logger = logging.getLogger('zc.buildout')
+        self.offline = (buildout_section['offline'] == 'true')
+        self.newest = (buildout_section['newest'] == 'true')
+        self.accept_buildout_test_releases = (
+            buildout_section['accept-buildout-test-releases'] == 'true')
+
+        ##################################################################
+        ## WARNING!!!
+        ## ALL ATTRIBUTES MUST HAVE REASONABLE DEFAULTS AT THIS POINT
+        ## OTHERWISE ATTRIBUTEERRORS MIGHT HAPPEN ANY TIME FROM RECIPES.
+        ## RECIPES SHOULD GENERALLY USE buildout['buildout'] OPTIONS, NOT
+        ## BUILDOUT ATTRIBUTES.
+        ##################################################################
+        # initialize some attrs and buildout directories.
+        options = self['buildout']
+
+        # now reinitialize
+        links = options.get('find-links', '')
+        self._links = links and links.split() or ()
+
+        allow_hosts = options['allow-hosts'].split('\n')
+        self._allow_hosts = tuple([host.strip() for host in allow_hosts
+                                   if host.strip() != ''])
+
+        self._buildout_dir = options['directory']
+
+        # Make sure we have absolute paths for standard directories.  We do this
+        # a second time here in case someone overrode these in their configs.
+        for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
+            d = self._buildout_path(options[name+'-directory'])
+            options[name+'-directory'] = d
+
+        if options['installed']:
+            options['installed'] = os.path.join(options['directory'],
+                                                options['installed'])
+
+        self._setup_logging()
+
+        versions = options.get('versions')
+        if versions:
+            zc.buildout.easy_install.default_versions(dict(self[versions]))
+
+
+        self.offline = options.get_bool('offline')
+        if self.offline:
+            options['newest'] = 'false'
+        self.newest = options.get_bool('newest')
+        zc.buildout.easy_install.prefer_final(
+            options.get_bool('prefer-final'))
+        self.accept_buildout_test_releases = options.get_bool(
+            'accept-buildout-test-releases')
+        zc.buildout.easy_install.use_dependency_links(
+            options.get_bool('use-dependency-links'))
+        zc.buildout.easy_install.allow_picked_versions(
+            options.get_bool('allow-picked-versions'))
+        zc.buildout.easy_install.install_from_cache(
+            options.get_bool('install-from-cache'))
+        zc.buildout.easy_install.always_unzip(options.get_bool('unzip'))
+        allowed_eggs = tuple(name.strip() for name in options[
+            'allowed-eggs-from-site-packages'].split('\n'))
+        self.include_site_packages = options.get_bool('include-site-packages')
+        self.exec_sitecustomize = options.get_bool('exec-sitecustomize')
+        if (_sys_executable_has_broken_dash_S and
+            (not self.include_site_packages or allowed_eggs != ('*',))):
+            # We can't do this if the executable has a broken -S.
+            warnings.warn(zc.buildout.easy_install.BROKEN_DASH_S_WARNING)
+            self.include_site_packages = True
+        zc.buildout.easy_install.allowed_eggs_from_site_packages(allowed_eggs)
+        zc.buildout.easy_install.include_site_packages(
+            self.include_site_packages)
+
+        download_cache = options.get('download-cache')
+        if download_cache:
+            download_cache = os.path.join(options['directory'], download_cache)
+            if not os.path.isdir(download_cache):
+                raise zc.buildout.UserError(
+                    'The specified download cache:\n'
+                    '%r\n'
+                    "Doesn't exist.\n"
+                    % download_cache)
+            download_cache = os.path.join(download_cache, 'dist')
+            if not os.path.isdir(download_cache):
+                os.mkdir(download_cache)
+
+            zc.buildout.easy_install.download_cache(download_cache)
+
+        # "Use" each of the defaults so they aren't reported as unused options.
+        for name in _buildout_default_options:
+            options[name]
+
+        # Do the same for extends-cache which is not among the defaults but
+        # wasn't recognized as having been used since it was used before
+        # tracking was turned on.
+        options.get('extends-cache')
+
+        os.chdir(options['directory'])
+
+    def _buildout_path(self, name):
+        if '${' in name:
+            return name
+        return os.path.join(self._buildout_dir, name)
+
+    def bootstrap(self, args):
+        __doing__ = 'Bootstrapping.'
+
+        self._setup_directories()
+
+        options = self['buildout']
+
+        # Get a base working set for our distributions that corresponds to the
+        # stated desires in the configuration.
+        distributions = ['setuptools', 'zc.buildout']
+        if options.get('offline') == 'true':
+            ws = zc.buildout.easy_install.working_set(
+                distributions, options['executable'],
+                [options['develop-eggs-directory'],
+                 options['eggs-directory']],
+                prefer_final=not self.accept_buildout_test_releases,
+                )
+        else:
+            ws = zc.buildout.easy_install.install(
+                distributions, options['eggs-directory'],
+                links=self._links,
+                index=options.get('index'),
+                executable=options['executable'],
+                path=[options['develop-eggs-directory']],
+                newest=self.newest,
+                allow_hosts=self._allow_hosts,
+                prefer_final=not self.accept_buildout_test_releases,
+                )
+
+        # Now copy buildout and setuptools eggs, and record destination eggs:
+        entries = []
+        for name in 'setuptools', 'zc.buildout':
+            r = pkg_resources.Requirement.parse(name)
+            dist = ws.find(r)
+            if dist.precedence == pkg_resources.DEVELOP_DIST:
+                dest = os.path.join(self['buildout']['develop-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.
+        # Ideally the (possibly) new version of buildout would get a
+        # chance to write the script.  Not sure how to do that.
+        ws = pkg_resources.WorkingSet(entries)
+        ws.require('zc.buildout')
+        partsdir = os.path.join(options['parts-directory'], 'buildout')
+        if not os.path.exists(partsdir):
+            os.mkdir(partsdir)
+        # (Honor the relative-paths option.)
+        relative_paths = options.get('relative-paths', 'false')
+        if relative_paths == 'true':
+            relative_paths = options['directory']
+        else:
+            assert relative_paths == 'false'
+            relative_paths = ''
+        if (self.accept_buildout_test_releases and
+            self._annotated['buildout']['accept-buildout-test-releases'][1] ==
+            'COMMAND_LINE_VALUE'):
+            # Bootstrap was called with '--accept-buildout-test-releases'.
+            # Continue to honor that setting.
+            script_initialization = _early_release_initialization_code
+        else:
+            script_initialization = ''
+        zc.buildout.easy_install.sitepackage_safe_scripts(
+            options['bin-directory'], ws, options['executable'], partsdir,
+            reqs=['zc.buildout'], relative_paths=relative_paths,
+            include_site_packages=self.include_site_packages,
+            script_initialization=script_initialization,
+            exec_sitecustomize=self.exec_sitecustomize,
+            )
+
+    init = bootstrap
+
+    def install(self, install_args):
+        __doing__ = 'Installing.'
+
+        self._load_extensions()
+        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'])
+
+        # Check for updates. This could cause the process to be restarted.
+        self._maybe_upgrade()
+
+        # load installed data
+        (installed_part_options, installed_exists
+         )= self._read_installed_part_options()
+
+        # Remove old develop eggs
+        self._uninstall(
+            installed_part_options['buildout'].get(
+                'installed_develop_eggs', '')
+            )
+
+        # Build develop eggs
+        installed_develop_eggs = self._develop()
+        installed_part_options['buildout']['installed_develop_eggs'
+                                           ] = installed_develop_eggs
+
+        if installed_exists:
+            self._update_installed(
+                installed_develop_eggs=installed_develop_eggs)
+
+        # 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_args:
+            install_parts = install_args
+            uninstall_missing = False
+        else:
+            install_parts = conf_parts
+            uninstall_missing = True
+
+        # load and initialize recipes
+        [self[part]['recipe'] for part in install_parts]
+        if not install_args:
+            install_parts = self._parts
+
+        if self._log_level < logging.DEBUG:
+            sections = list(self)
+            sections.sort()
+            print
+            print 'Configuration data:'
+            for section in self._data:
+                _save_options(section, self[section], sys.stdout)
+            print
+
+
+        # compute new part recipe signatures
+        self._compute_part_signatures(install_parts)
+
+        # uninstall parts that are no-longer used or whose configs
+        # have changed
+        for part in reversed(installed_parts):
+            if part in install_parts:
+                old_options = installed_part_options[part].copy()
+                installed_files = old_options.pop('__buildout_installed__')
+                new_options = self.get(part)
+                if old_options == new_options:
+                    # The options are the same, but are all of the
+                    # installed files still there?  If not, we should
+                    # reinstall.
+                    if not installed_files:
+                        continue
+                    for f in installed_files.split('\n'):
+                        if not os.path.exists(self._buildout_path(f)):
+                            break
+                    else:
+                        continue
+
+                # output debugging info
+                if self._logger.getEffectiveLevel() < logging.DEBUG:
+                    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 changed:\n%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
+
+            self._uninstall_part(part, installed_part_options)
+            installed_parts = [p for p in installed_parts if p != part]
+
+            if installed_exists:
+                self._update_installed(parts=' '.join(installed_parts))
+
+        # Check for unused buildout options:
+        _check_for_unused_options_in_section(self, 'buildout')
+
+        # install new parts
+        for part in install_parts:
+            signature = self[part].pop('__buildout_signature__')
+            saved_options = self[part].copy()
+            recipe = self[part].recipe
+            if part in installed_parts: # update
+                need_to_save_installed = False
+                __doing__ = 'Updating %s.', part
+                self._logger.info(*__doing__)
+                old_options = installed_part_options[part]
+                old_installed_files = old_options['__buildout_installed__']
+
+                try:
+                    update = recipe.update
+                except AttributeError:
+                    update = recipe.install
+                    self._logger.warning(
+                        "The recipe for %s doesn't define an update "
+                        "method. Using its install method.",
+                        part)
+
+                try:
+                    installed_files = self[part]._call(update)
+                except:
+                    installed_parts.remove(part)
+                    self._uninstall(old_installed_files)
+                    if installed_exists:
+                        self._update_installed(
+                            parts=' '.join(installed_parts))
+                    raise
+
+                old_installed_files = old_installed_files.split('\n')
+                if installed_files is None:
+                    installed_files = old_installed_files
+                else:
+                    if isinstance(installed_files, str):
+                        installed_files = [installed_files]
+                    else:
+                        installed_files = list(installed_files)
+
+                    need_to_save_installed = [
+                        p for p in installed_files
+                        if p not in old_installed_files]
+
+                    if need_to_save_installed:
+                        installed_files = (old_installed_files
+                                           + need_to_save_installed)
+
+            else: # install
+                need_to_save_installed = True
+                __doing__ = 'Installing %s.', part
+                self._logger.info(*__doing__)
+                installed_files = self[part]._call(recipe.install)
+                if installed_files is None:
+                    self._logger.warning(
+                        "The %s install returned None.  A path or "
+                        "iterable of paths should be returned.",
+                        part)
+                    installed_files = ()
+                elif isinstance(installed_files, str):
+                    installed_files = [installed_files]
+                else:
+                    installed_files = list(installed_files)
+
+            installed_part_options[part] = saved_options
+            saved_options['__buildout_installed__'
+                          ] = '\n'.join(installed_files)
+            saved_options['__buildout_signature__'] = signature
+
+            installed_parts = [p for p in installed_parts if p != part]
+            installed_parts.append(part)
+            _check_for_unused_options_in_section(self, part)
+
+            if need_to_save_installed:
+                installed_part_options['buildout']['parts'] = (
+                    ' '.join(installed_parts))
+                self._save_installed_options(installed_part_options)
+                installed_exists = True
+            else:
+                assert installed_exists
+                self._update_installed(parts=' '.join(installed_parts))
+
+        if installed_develop_eggs:
+            if not installed_exists:
+                self._save_installed_options(installed_part_options)
+        elif (not installed_parts) and installed_exists:
+            os.remove(self['buildout']['installed'])
+
+        self._unload_extensions()
+
+    def _update_installed(self, **buildout_options):
+        installed = self['buildout']['installed']
+        f = open(installed, 'a')
+        f.write('\n[buildout]\n')
+        for option, value in buildout_options.items():
+            _save_option(option, value, f)
+        f.close()
+
+    def _uninstall_part(self, part, installed_part_options):
+        # uninstall part
+        __doing__ = 'Uninstalling %s.', part
+        self._logger.info(*__doing__)
+
+        # run uninstall recipe
+        recipe, entry = _recipe(installed_part_options[part])
+        try:
+            uninstaller = _install_and_load(
+                recipe, 'zc.buildout.uninstall', entry, self)
+            self._logger.info('Running uninstall recipe.')
+            uninstaller(part, installed_part_options[part])
+        except (ImportError, pkg_resources.DistributionNotFound), v:
+            pass
+
+        # remove created files and directories
+        self._uninstall(
+            installed_part_options[part]['__buildout_installed__'])
+
+    def _setup_directories(self):
+        __doing__ = 'Setting up buildout directories'
+
+        # 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 %r.', d)
+                os.mkdir(d)
+
+    def _develop(self):
+        """Install sources by running setup.py develop on them
+        """
+        __doing__ = 'Processing directories listed in the develop option'
+
+        develop = self['buildout'].get('develop')
+        if not develop:
+            return ''
+
+        dest = self['buildout']['develop-eggs-directory']
+        old_files = os.listdir(dest)
+
+        env = dict(os.environ, PYTHONPATH=pkg_resources_loc)
+        here = os.getcwd()
+        try:
+            try:
+                for setup in develop.split():
+                    setup = self._buildout_path(setup)
+                    files = glob.glob(setup)
+                    if not files:
+                        self._logger.warn("Couldn't develop %r (not found)",
+                                          setup)
+                    else:
+                        files.sort()
+                    for setup in files:
+                        self._logger.info("Develop: %r", setup)
+                        __doing__ = 'Processing develop directory %r.', setup
+                        zc.buildout.easy_install.develop(setup, dest)
+            except:
+                # if we had an error, we need to roll back changes, by
+                # removing any files we created.
+                self._sanity_check_develop_eggs_files(dest, old_files)
+                self._uninstall('\n'.join(
+                    [os.path.join(dest, f)
+                     for f in os.listdir(dest)
+                     if f not in old_files
+                     ]))
+                raise
+
+            else:
+                self._sanity_check_develop_eggs_files(dest, old_files)
+                return '\n'.join([os.path.join(dest, f)
+                                  for f in os.listdir(dest)
+                                  if f not in old_files
+                                  ])
+
+        finally:
+            os.chdir(here)
+
+
+    def _sanity_check_develop_eggs_files(self, dest, old_files):
+        for f in os.listdir(dest):
+            if f in old_files:
+                continue
+            if not (os.path.isfile(os.path.join(dest, f))
+                    and f.endswith('.egg-link')):
+                self._logger.warning(
+                    "Unexpected entry, %r, in develop-eggs directory.", f)
+
+    def _compute_part_signatures(self, parts):
+        # Compute recipe signature and add to options
+        for part in parts:
+            options = self.get(part)
+            if options is None:
+                options = self[part] = {}
+            recipe, entry = _recipe(options)
+            req = pkg_resources.Requirement.parse(recipe)
+            sig = _dists_sig(pkg_resources.working_set.resolve([req]))
+            options['__buildout_signature__'] = ' '.join(sig)
+
+    def _read_installed_part_options(self):
+        old = self['buildout']['installed']
+        if old and os.path.isfile(old):
+            parser = ConfigParser.RawConfigParser()
+            parser.optionxform = lambda s: s
+            parser.read(old)
+            result = {}
+            for section in parser.sections():
+                options = {}
+                for option, value in parser.items(section):
+                    if '%(' in value:
+                        for k, v in _spacey_defaults:
+                            value = value.replace(k, v)
+                    options[option] = value
+                result[section] = Options(self, section, options)
+
+            return result, True
+        else:
+            return ({'buildout': Options(self, 'buildout', {'parts': ''})},
+                    False,
+                    )
+
+    def _uninstall(self, installed):
+        for f in installed.split('\n'):
+            if not f:
+                continue
+            f = self._buildout_path(f)
+            if os.path.isdir(f):
+                rmtree(f)
+            elif os.path.isfile(f):
+                try:
+                    os.remove(f)
+                except OSError:
+                    if not (
+                        sys.platform == 'win32' and
+                        (realpath(os.path.join(os.path.dirname(sys.argv[0]),
+                                               'buildout.exe'))
+                         ==
+                         realpath(f)
+                         )
+                        # Sigh. This is the exectable used to run the buildout
+                        # and, of course, it's in use. Leave it.
+                        ):
+                        raise
+
+    def _install(self, part):
+        options = self[part]
+        recipe, entry = _recipe(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):
+        installed = self['buildout']['installed']
+        if not installed:
+            return
+        f = open(installed, '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):
+        raise zc.buildout.UserError(message % args)
+
+    def _setup_logging(self):
+        root_logger = logging.getLogger()
+        self._logger = logging.getLogger('zc.buildout')
+        handler = logging.StreamHandler(sys.stdout)
+        log_format = self['buildout']['log-format']
+        if not log_format:
+            # No format specified. Use different formatter for buildout
+            # and other modules, showing logger name except for buildout
+            log_format = '%(name)s: %(message)s'
+            buildout_handler = logging.StreamHandler(sys.stdout)
+            buildout_handler.setFormatter(logging.Formatter('%(message)s'))
+            self._logger.propagate = False
+            self._logger.addHandler(buildout_handler)
+
+        handler.setFormatter(logging.Formatter(log_format))
+        root_logger.addHandler(handler)
+
+        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)
+        self._log_level = level
+
+    def _maybe_upgrade(self):
+        # See if buildout or setuptools need to be upgraded.
+        # If they do, do the upgrade and restart the buildout process.
+        __doing__ = 'Checking for upgrades.'
+
+        if not self.newest:
+            return
+
+        options = self['buildout']
+
+        specs = ['zc.buildout']
+        if zc.buildout.easy_install.is_distribute:
+            specs.append('distribute')
+        else:
+            specs.append('setuptools')
+        ws = zc.buildout.easy_install.install(
+            [
+            (spec + ' ' + options.get(spec+'-version', '')).strip()
+            for spec in specs
+            ],
+            options['eggs-directory'],
+            links = options.get('find-links', '').split(),
+            index = options.get('index'),
+            path = [options['develop-eggs-directory']],
+            allow_hosts = self._allow_hosts,
+            prefer_final=not self.accept_buildout_test_releases,
+            )
+
+        upgraded = []
+        for project in 'zc.buildout', 'setuptools':
+            req = pkg_resources.Requirement.parse(project)
+            project_location = pkg_resources.working_set.find(req).location
+            if ws.find(req).location != project_location:
+                upgraded.append(ws.find(req))
+
+        if not upgraded:
+            return
+
+        __doing__ = 'Upgrading.'
+
+        should_run = realpath(
+            os.path.join(os.path.abspath(options['bin-directory']),
+                         'buildout')
+            )
+        if sys.platform == 'win32':
+            should_run += '-script.py'
+
+        if (realpath(os.path.abspath(sys.argv[0])) != should_run):
+            self._logger.debug("Running %r.", realpath(sys.argv[0]))
+            self._logger.debug("Local buildout is %r.", should_run)
+            self._logger.warn("Not upgrading because not running a local "
+                              "buildout command.")
+            return
+
+        if sys.platform == 'win32' and not self.__windows_restart:
+            args = map(zc.buildout.easy_install._safe_arg, sys.argv)
+            args.insert(1, '-W')
+            if not __debug__:
+                args.insert(0, '-O')
+            args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable))
+            os.execv(sys.executable, args)
+
+        self._logger.info("Upgraded:\n  %s;\nrestarting.",
+                          ",\n  ".join([("%s version %s"
+                                       % (dist.project_name, dist.version)
+                                       )
+                                      for dist in upgraded
+                                      ]
+                                     ),
+                          )
+
+        # the new dist is different, so we've upgraded.
+        # Update the scripts and return True
+        # Ideally the new version of buildout would get a chance to write the
+        # script.  Not sure how to do that.
+        partsdir = os.path.join(options['parts-directory'], 'buildout')
+        if os.path.exists(partsdir):
+            # This is primarily for unit tests, in which .py files change too
+            # fast for Python to know to regenerate the .pyc/.pyo files.
+            shutil.rmtree(partsdir)
+        os.mkdir(partsdir)
+        if (self.accept_buildout_test_releases and
+            self._annotated['buildout']['accept-buildout-test-releases'][1] ==
+            'COMMAND_LINE_VALUE'):
+            # Bootstrap was called with '--accept-buildout-test-releases'.
+            # Continue to honor that setting.
+            script_initialization = _early_release_initialization_code
+        else:
+            script_initialization = ''
+        # (Honor the relative-paths option.)
+        relative_paths = options.get('relative-paths', 'false')
+        if relative_paths == 'true':
+            relative_paths = options['directory']
+        else:
+            assert relative_paths == 'false'
+            relative_paths = ''
+        zc.buildout.easy_install.sitepackage_safe_scripts(
+            options['bin-directory'], ws, options['executable'], partsdir,
+            reqs=['zc.buildout'], relative_paths=relative_paths,
+            include_site_packages=self.include_site_packages,
+            script_initialization=script_initialization,
+            exec_sitecustomize=self.exec_sitecustomize,
+            )
+
+        # Restart
+        args = map(zc.buildout.easy_install._safe_arg, sys.argv)
+        if not __debug__:
+            args.insert(0, '-O')
+        args.insert(0, zc.buildout.easy_install._safe_arg(sys.executable))
+        # We want to make sure that our new site.py is used for rerunning
+        # buildout, so we put the partsdir in PYTHONPATH for our restart.
+        # This overrides any set PYTHONPATH, but since we generally are
+        # trying to run with a completely "clean" python (only the standard
+        # library) then that should be fine.
+        env = os.environ.copy()
+        env['PYTHONPATH'] = partsdir
+        if is_jython:
+            sys.exit(
+                subprocess.Popen(
+                    [sys.executable] + list(args), env=env).wait())
+        else:
+            sys.exit(os.spawnve(os.P_WAIT, sys.executable, args, env))
+
+    def _load_extensions(self):
+        __doing__ = 'Loading extensions.'
+        specs = self['buildout'].get('extensions', '').split()
+        if specs:
+            path = [self['buildout']['develop-eggs-directory']]
+            if self.offline:
+                dest = None
+                path.append(self['buildout']['eggs-directory'])
+            else:
+                dest = self['buildout']['eggs-directory']
+                if not os.path.exists(dest):
+                    self._logger.info('Creating directory %r.', dest)
+                    os.mkdir(dest)
+
+            zc.buildout.easy_install.install(
+                specs, dest, path=path,
+                working_set=pkg_resources.working_set,
+                links = self['buildout'].get('find-links', '').split(),
+                index = self['buildout'].get('index'),
+                newest=self.newest, allow_hosts=self._allow_hosts,
+                prefer_final=not self.accept_buildout_test_releases)
+
+            # Clear cache because extensions might now let us read pages we
+            # couldn't read before.
+            zc.buildout.easy_install.clear_index_cache()
+
+            for ep in pkg_resources.iter_entry_points('zc.buildout.extension'):
+                ep.load()(self)
+
+    def _unload_extensions(self):
+        __doing__ = 'Unloading extensions.'
+        specs = self['buildout'].get('extensions', '').split()
+        if specs:
+            for ep in pkg_resources.iter_entry_points(
+                'zc.buildout.unloadextension'):
+                ep.load()(self)
+
+    def setup(self, args):
+        if not args:
+            raise zc.buildout.UserError(
+                "The setup command requires the path to a setup script or \n"
+                "directory containing a setup script, and its arguments."
+                )
+        setup = args.pop(0)
+        if os.path.isdir(setup):
+            setup = os.path.join(setup, 'setup.py')
+
+        self._logger.info("Running setup script %r.", setup)
+        setup = os.path.abspath(setup)
+
+        fd, tsetup = tempfile.mkstemp()
+        exe = zc.buildout.easy_install._safe_arg(sys.executable)
+        try:
+            os.write(fd, zc.buildout.easy_install.runsetup_template % dict(
+                setuptools=pkg_resources_loc,
+                setupdir=os.path.dirname(setup),
+                setup=setup,
+                __file__ = setup,
+                ))
+            if is_jython:
+                arg_list = list()
+
+                for a in args:
+                    arg_list.append(zc.buildout.easy_install._safe_arg(a))
+
+                subprocess.Popen([exe] + list(tsetup) + arg_list).wait()
+
+            else:
+                os.spawnl(os.P_WAIT, sys.executable, exe, tsetup,
+                        *[zc.buildout.easy_install._safe_arg(a)
+                            for a in args])
+        finally:
+            os.close(fd)
+            os.remove(tsetup)
+
+    runsetup = setup # backward compat.
+
+    def annotate(self, args):
+        _print_annotate(self._annotated)
+
+    def __getitem__(self, section):
+        __doing__ = 'Getting section %s.', section
+        try:
+            return self._data[section]
+        except KeyError:
+            pass
+
+        try:
+            data = self._raw[section]
+        except KeyError:
+            raise MissingSection(section)
+
+        options = Options(self, section, data)
+        self._data[section] = options
+        options._initialize()
+        return options
+
+    def __setitem__(self, key, value):
+        raise NotImplementedError('__setitem__')
+
+    def __delitem__(self, key):
+        raise NotImplementedError('__delitem__')
+
+    def keys(self):
+        return self._raw.keys()
+
+    def __iter__(self):
+        return iter(self._raw)
+
+
+def _install_and_load(spec, group, entry, buildout):
+    __doing__ = 'Loading recipe %r.', spec
+    try:
+        req = pkg_resources.Requirement.parse(spec)
+
+        buildout_options = buildout['buildout']
+        if pkg_resources.working_set.find(req) is None:
+            __doing__ = 'Installing recipe %s.', spec
+            if buildout.offline:
+                dest = None
+                path = [buildout_options['develop-eggs-directory'],
+                        buildout_options['eggs-directory'],
+                        ]
+            else:
+                dest = buildout_options['eggs-directory']
+                path = [buildout_options['develop-eggs-directory']]
+
+            zc.buildout.easy_install.install(
+                [spec], dest,
+                links=buildout._links,
+                index=buildout_options.get('index'),
+                path=path,
+                working_set=pkg_resources.working_set,
+                newest=buildout.newest,
+                allow_hosts=buildout._allow_hosts,
+                prefer_final=not buildout.accept_buildout_test_releases)
+
+        __doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry
+        return pkg_resources.load_entry_point(
+            req.project_name, group, entry)
+
+    except Exception, v:
+        buildout._logger.log(
+            1,
+            "Could't load %s entry point %s\nfrom %s:\n%s.",
+            group, entry, spec, v)
+        raise
+
+
+class Options(UserDict.DictMixin):
+
+    def __init__(self, buildout, section, data):
+        self.buildout = buildout
+        self.name = section
+        self._raw = data
+        self._cooked = {}
+        self._data = {}
+
+    def _initialize(self):
+        name = self.name
+        __doing__ = 'Initializing section %s.', name
+
+        if '<' in self._raw:
+            self._raw = self._do_extend_raw(name, self._raw, [])
+
+        # force substitutions
+        for k, v in self._raw.items():
+            if '${' in v:
+                self._dosub(k, v)
+
+        if self.name == 'buildout':
+            return # buildout section can never be a part
+
+        recipe = self.get('recipe')
+        if not recipe:
+            return
+
+        reqs, entry = _recipe(self._data)
+        buildout = self.buildout
+        recipe_class = _install_and_load(reqs, 'zc.buildout', entry, buildout)
+
+        __doing__ = 'Initializing part %s.', name
+        self.recipe = recipe_class(buildout, name, self)
+        buildout._parts.append(name)
+
+    def _do_extend_raw(self, name, data, doing):
+        if name == 'buildout':
+            return data
+        if name in doing:
+            raise zc.buildout.UserError("Infinite extending loop %r" % name)
+        doing.append(name)
+        try:
+            to_do = data.pop('<', None)
+            if to_do is None:
+                return data
+            __doing__ = 'Loading input sections for %r', name
+
+            result = {}
+            for iname in to_do.split('\n'):
+                iname = iname.strip()
+                if not iname:
+                    continue
+                raw = self.buildout._raw.get(iname)
+                if raw is None:
+                    raise zc.buildout.UserError("No section named %r" % iname)
+                result.update(self._do_extend_raw(iname, raw, doing))
+
+            result.update(data)
+            return result
+        finally:
+            assert doing.pop() == name
+
+    def _dosub(self, option, v):
+        __doing__ = 'Getting option %s:%s.', self.name, option
+        seen = [(self.name, option)]
+        v = '$$'.join([self._sub(s, seen) for s in v.split('$$')])
+        self._cooked[option] = v
+
+    def get(self, option, default=None, seen=None):
+        try:
+            return self._data[option]
+        except KeyError:
+            pass
+
+        v = self._cooked.get(option)
+        if v is None:
+            v = self._raw.get(option)
+            if v is None:
+                return default
+
+        __doing__ = 'Getting option %s:%s.', self.name, option
+
+        if '${' in v:
+            key = self.name, option
+            if seen is None:
+                seen = [key]
+            elif key in seen:
+                raise zc.buildout.UserError(
+                    "Circular reference in substitutions.\n"
+                    )
+            else:
+                seen.append(key)
+            v = '$$'.join([self._sub(s, seen) for s in v.split('$$')])
+            seen.pop()
+
+        self._data[option] = v
+        return v
+
+    _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 _sub(self, template, seen):
+        value = self._template_split(template)
+        subs = []
+        for ref in value[1::2]:
+            s = tuple(ref[2:-1].split(':'))
+            if not self._valid(ref):
+                if len(s) < 2:
+                    raise zc.buildout.UserError("The substitution, %s,\n"
+                                                "doesn't contain a colon."
+                                                % ref)
+                if len(s) > 2:
+                    raise zc.buildout.UserError("The substitution, %s,\n"
+                                                "has too many colons."
+                                                % ref)
+                if not self._simple(s[0]):
+                    raise zc.buildout.UserError(
+                        "The section name in substitution, %s,\n"
+                        "has invalid characters."
+                        % ref)
+                if not self._simple(s[1]):
+                    raise zc.buildout.UserError(
+                        "The option name in substitution, %s,\n"
+                        "has invalid characters."
+                        % ref)
+
+            section, option = s
+            if not section:
+                section = self.name
+            v = self.buildout[section].get(option, None, seen)
+            if v is None:
+                if option == '_buildout_section_name_':
+                    v = self.name
+                else:
+                    raise MissingOption("Referenced option does not exist:",
+                                        section, option)
+            subs.append(v)
+        subs.append('')
+
+        return ''.join([''.join(v) for v in zip(value[::2], subs)])
+
+    def __getitem__(self, key):
+        try:
+            return self._data[key]
+        except KeyError:
+            pass
+
+        v = self.get(key)
+        if v is None:
+            raise MissingOption("Missing option: %s:%s" % (self.name, key))
+        return v
+
+    def __setitem__(self, option, value):
+        if not isinstance(value, str):
+            raise TypeError('Option values must be strings', value)
+        self._data[option] = value
+
+    def __delitem__(self, key):
+        if key in self._raw:
+            del self._raw[key]
+            if key in self._data:
+                del self._data[key]
+            if key in self._cooked:
+                del self._cooked[key]
+        elif key in self._data:
+            del self._data[key]
+        else:
+            raise KeyError, key
+
+    def keys(self):
+        raw = self._raw
+        return list(self._raw) + [k for k in self._data if k not in raw]
+
+    def copy(self):
+        result = self._raw.copy()
+        result.update(self._cooked)
+        result.update(self._data)
+        return result
+
+    def _call(self, f):
+        buildout_directory = self.buildout['buildout']['directory']
+        self._created = []
+        try:
+            try:
+                os.chdir(buildout_directory)
+                return f()
+            except:
+                for p in self._created:
+                    if os.path.isdir(p):
+                        rmtree(p)
+                    elif os.path.isfile(p):
+                        os.remove(p)
+                    else:
+                        self.buildout._logger.warn("Couldn't clean up %r.", p)
+                raise
+        finally:
+            self._created = None
+            os.chdir(buildout_directory)
+
+    def created(self, *paths):
+        try:
+            self._created.extend(paths)
+        except AttributeError:
+            raise TypeError(
+                "Attempt to register a created path while not installing",
+                self.name)
+        return self._created
+
+    def query_bool(self, name, default=None):
+        """Given a name, return a boolean value for that name.
+
+        ``default``, if given, should be 'true', 'false', or None.
+        """
+        if default is not None:
+            value = self.setdefault(name, default=default)
+        else:
+            value = self.get(name)
+            if value is None:
+                return value
+        return _convert_bool(name, value)
+
+    def get_bool(self, name):
+        """Given a name, return a boolean value for that name.
+        """
+        return _convert_bool(name, self[name])
+
+
+def _convert_bool(name, value):
+    if value not in ('true', 'false'):
+        raise zc.buildout.UserError(
+            'Invalid value for %s option: %s' % (name, value))
+    else:
+        return value == 'true'
+
+_spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
+                        '|'
+                        '^[ \t\r\f\v]+'
+                        '|'
+                        '[ \t\r\f\v]+$'
+                        )
+
+_spacey_defaults = [
+    ('%(__buildout_space__)s',   ' '),
+    ('%(__buildout_space_n__)s', '\n'),
+    ('%(__buildout_space_r__)s', '\r'),
+    ('%(__buildout_space_f__)s', '\f'),
+    ('%(__buildout_space_v__)s', '\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
+
+def _save_option(option, value, f):
+    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 _save_options(section, options, f):
+    print >>f, '[%s]' % section
+    items = options.items()
+    items.sort()
+    for option, value in items:
+        _save_option(option, value, f)
+
+def _open(base, filename, seen, dl_options, override):
+    """Open a configuration file and return the result as a dictionary,
+
+    Recursively open other files based on buildout options found.
+    """
+    _update_section(dl_options, override)
+    _dl_options = _unannotate_section(dl_options.copy())
+    is_temp = False
+    download = zc.buildout.download.Download(
+        _dl_options, cache=_dl_options.get('extends-cache'), fallback=True,
+        hash_name=True)
+    if _isurl(filename):
+        path, is_temp = download(filename)
+        fp = open(path)
+        base = filename[:filename.rfind('/')]
+    elif _isurl(base):
+        if os.path.isabs(filename):
+            fp = open(filename)
+            base = os.path.dirname(filename)
+        else:
+            filename = base + '/' + filename
+            path, is_temp = download(filename)
+            fp = open(path)
+            base = filename[:filename.rfind('/')]
+    else:
+        filename = os.path.join(base, filename)
+        fp = open(filename)
+        base = os.path.dirname(filename)
+
+    if filename in seen:
+        if is_temp:
+            fp.close()
+            os.remove(path)
+        raise zc.buildout.UserError("Recursive file include", seen, filename)
+
+    root_config_file = not seen
+    seen.append(filename)
+
+    result = {}
+
+    parser = ConfigParser.RawConfigParser()
+    parser.optionxform = lambda s: s
+    parser.readfp(fp)
+    if is_temp:
+        fp.close()
+        os.remove(path)
+
+    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
+
+    result = _annotate(result, filename)
+
+    if root_config_file and 'buildout' in result:
+        dl_options = _update_section(dl_options, result['buildout'])
+
+    if extends:
+        extends = extends.split()
+        eresult = _open(base, extends.pop(0), seen, dl_options, override)
+        for fname in extends:
+            _update(eresult, _open(base, fname, seen, dl_options, override))
+        result = _update(eresult, result)
+
+    if extended_by:
+        self._logger.warn(
+            "The extendedBy option is deprecated.  Stop using it."
+            )
+        for fname in extended_by.split():
+            result = _update(result,
+                             _open(base, fname, seen, dl_options, override))
+
+    seen.pop()
+    return result
+
+
+ignore_directories = '.svn', 'CVS'
+def _dir_hash(dir):
+    hash = md5()
+    for (dirpath, dirnames, filenames) in os.walk(dir):
+        dirnames[:] = [n for n in dirnames if n not in ignore_directories]
+        filenames[:] = [f for f in filenames
+                        if (not (f.endswith('pyc') or f.endswith('pyo'))
+                            and os.path.exists(os.path.join(dirpath, f)))
+                        ]
+        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):
+    result = []
+    for dist in dists:
+        location = dist.location
+        if dist.precedence == pkg_resources.DEVELOP_DIST:
+            result.append(dist.project_name + '-' + _dir_hash(location))
+        else:
+            result.append(os.path.basename(location))
+    return result
+
+def _update_section(s1, s2):
+    s2 = s2.copy() # avoid mutating the second argument, which is unexpected
+    for k, v in s2.items():
+        v2, note2 = v
+        if k.endswith('+'):
+            key = k.rstrip(' +')
+            v1, note1 = s1.get(key, ("", ""))
+            newnote = ' [+] '.join((note1, note2)).strip()
+            s2[key] = "\n".join((v1).split('\n') +
+                v2.split('\n')), newnote
+            del s2[k]
+        elif k.endswith('-'):
+            key = k.rstrip(' -')
+            v1, note1 = s1.get(key, ("", ""))
+            newnote = ' [-] '.join((note1, note2)).strip()
+            s2[key] = ("\n".join(
+                [v for v in v1.split('\n')
+                   if v not in v2.split('\n')]), newnote)
+            del s2[k]
+
+    s1.update(s2)
+    return s1
+
+def _update(d1, d2):
+    for section in d2:
+        if section in d1:
+            d1[section] = _update_section(d1[section], d2[section])
+        else:
+            d1[section] = d2[section]
+    return d1
+
+def _recipe(options):
+    recipe = options['recipe']
+    if ':' in recipe:
+        recipe, entry = recipe.split(':')
+    else:
+        entry = 'default'
+
+    return recipe, entry
+
+def _doing():
+    _, v, tb = sys.exc_info()
+    message = str(v)
+    doing = []
+    while tb is not None:
+        d = tb.tb_frame.f_locals.get('__doing__')
+        if d:
+            doing.append(d)
+        tb = tb.tb_next
+
+    if doing:
+        sys.stderr.write('While:\n')
+        for d in doing:
+            if not isinstance(d, str):
+                d = d[0] % d[1:]
+            sys.stderr.write('  %s\n' % d)
+
+def _error(*message):
+    sys.stderr.write('Error: ' + ' '.join(message) +'\n')
+    sys.exit(1)
+
+_internal_error_template = """
+An internal error occurred due to a bug in either zc.buildout or in a
+recipe being used:
+"""
+
+def _check_for_unused_options_in_section(buildout, section):
+    options = buildout[section]
+    unused = [option for option in options._raw if option not in options._data]
+    if unused:
+        buildout._logger.warn("Unused options for %s: %s."
+                              % (section, ' '.join(map(repr, unused)))
+                              )
+
+_early_release_initialization_code = """\
+sys.argv.insert(1, 'buildout:accept-buildout-test-releases=true')
+print ('NOTE: Accepting early releases of build system packages.  Rerun '
+       'bootstrap without --accept-buildout-test-releases (-t) to return to '
+       'default behavior.')
+"""
+
+_usage = """\
+Usage: buildout [options] [assignments] [command [command arguments]]
+
+Options:
+
+  -h, --help
+
+     Print this message and exit.
+
+  -v
+
+     Increase the level of verbosity.  This option can be used multiple times.
+
+  -q
+
+     Decrease the level of verbosity.  This option can be used multiple times.
+
+  -c config_file
+
+     Specify the path to the buildout configuration file to be used.
+     This defaults to the file named "buildout.cfg" in the current
+     working directory.
+
+  -t socket_timeout
+
+     Specify the socket timeout in seconds.
+
+  -U
+
+     Don't read user defaults.
+
+  -o
+
+    Run in off-line mode.  This is equivalent to the assignment
+    buildout:offline=true.
+
+  -O
+
+    Run in non-off-line mode.  This is equivalent to the assignment
+    buildout:offline=false.  This is the default buildout mode.  The
+    -O option would normally be used to override a true offline
+    setting in a configuration file.
+
+  -n
+
+    Run in newest mode.  This is equivalent to the assignment
+    buildout:newest=true.  With this setting, which is the default,
+    buildout will try to find the newest versions of distributions
+    available that satisfy its requirements.
+
+  -N
+
+    Run in non-newest mode.  This is equivalent to the assignment
+    buildout:newest=false.  With this setting, buildout will not seek
+    new distributions if installed distributions satisfy it's
+    requirements.
+
+  -D
+
+    Debug errors.  If an error occurs, then the post-mortem debugger
+    will be started. This is especially useful for debuging recipe
+    problems.
+
+  -s
+
+    Squelch warnings about using an executable with a broken -S
+    implementation.
+
+Assignments are of the form: section:option=value and are used to
+provide configuration options that override those given in the
+configuration file.  For example, to run the buildout in offline mode,
+use buildout:offline=true.
+
+Options and assignments can be interspersed.
+
+Commands:
+
+  install [parts]
+
+    Install parts.  If no command arguments are given, then the parts
+    definition from the configuration file is used.  Otherwise, the
+    arguments specify the parts to be installed.
+
+    Note that the semantics differ depending on whether any parts are
+    specified.  If parts are specified, then only those parts will be
+    installed. If no parts are specified, then the parts specified by
+    the buildout parts option will be installed along with all of
+    their dependencies.
+
+  bootstrap
+
+    Create a new buildout in the current working directory, copying
+    the buildout and setuptools eggs and, creating a basic directory
+    structure and a buildout-local buildout script.
+
+  init
+
+    Initialize a buildout, creating a buildout.cfg file if it doesn't
+    exist and then performing the same actions as for the buildout
+    command.
+
+  setup script [setup command and options]
+
+    Run a given setup script arranging that setuptools is in the
+    script's path and and that it has been imported so that
+    setuptools-provided commands (like bdist_egg) can be used even if
+    the setup script doesn't import setuptools itself.
+
+    The script can be given either as a script path or a path to a
+    directory containing a setup.py script.
+
+  annotate
+
+    Display annotated sections. All sections are displayed, sorted
+    alphabetically. For each section, all key-value pairs are displayed,
+    sorted alphabetically, along with the origin of the value (file name or
+    COMPUTED_VALUE, DEFAULT_VALUE, COMMAND_LINE_VALUE).
+
+"""
+def _help():
+    print _usage
+    sys.exit(0)
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    config_file = 'buildout.cfg'
+    verbosity = 0
+    options = []
+    windows_restart = False
+    user_defaults = True
+    debug = False
+    ignore_broken_dash_s = False
+    while args:
+        if args[0][0] == '-':
+            op = orig_op = args.pop(0)
+            op = op[1:]
+            while op and op[0] in 'vqhWUoOnNDAs':
+                if op[0] == 'v':
+                    verbosity += 10
+                elif op[0] == 'q':
+                    verbosity -= 10
+                elif op[0] == 'W':
+                    windows_restart = True
+                elif op[0] == 'U':
+                    user_defaults = False
+                elif op[0] == 'o':
+                    options.append(('buildout', 'offline', 'true'))
+                elif op[0] == 'O':
+                    options.append(('buildout', 'offline', 'false'))
+                elif op[0] == 'n':
+                    options.append(('buildout', 'newest', 'true'))
+                elif op[0] == 'N':
+                    options.append(('buildout', 'newest', 'false'))
+                elif op[0] == 'D':
+                    debug = True
+                elif op[0] == 's':
+                    ignore_broken_dash_s = True
+                else:
+                    _help()
+                op = op[1:]
+
+            if op[:1] in  ('c', 't'):
+                op_ = op[:1]
+                op = op[1:]
+
+                if op_ == 'c':
+                    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_ == 't':
+                    try:
+                        timeout = int(args.pop(0))
+                    except IndexError:
+                        _error("No timeout value specified for option", orig_op)
+                    except ValueError:
+                        _error("No timeout value must be numeric", orig_op)
+
+                    import socket
+                    print 'Setting socket time out to %d seconds' % timeout
+                    socket.setdefaulttimeout(timeout)
+
+            elif op:
+                if orig_op == '--help':
+                    _help()
+                _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 < 0 or ignore_broken_dash_s:
+        broken_dash_S_filter_action = 'ignore'
+    elif verbosity == 0: # This is the default.
+        broken_dash_S_filter_action = 'once'
+    else:
+        broken_dash_S_filter_action = 'default'
+    warnings.filterwarnings(
+        broken_dash_S_filter_action,
+        re.escape(
+            zc.buildout.easy_install.BROKEN_DASH_S_WARNING),
+        UserWarning)
+    if verbosity:
+        options.append(('buildout', 'verbosity', str(verbosity)))
+
+    if args:
+        command = args.pop(0)
+        if command not in (
+            'install', 'bootstrap', 'runsetup', 'setup', 'init',
+            'annotate',
+            ):
+            _error('invalid command:', command)
+    else:
+        command = 'install'
+
+    try:
+        try:
+            buildout = Buildout(config_file, options,
+                                user_defaults, windows_restart, command)
+            getattr(buildout, command)(args)
+        except SystemExit:
+            pass
+        except Exception, v:
+            _doing()
+            exc_info = sys.exc_info()
+            import pdb, traceback
+            if debug:
+                traceback.print_exception(*exc_info)
+                sys.stderr.write('\nStarting pdb:\n')
+                pdb.post_mortem(exc_info[2])
+            else:
+                if isinstance(v, (zc.buildout.UserError,
+                                  distutils.errors.DistutilsError,
+                                  )
+                              ):
+                    _error(str(v))
+                else:
+                    sys.stderr.write(_internal_error_template)
+                    traceback.print_exception(*exc_info)
+                    sys.exit(1)
+
+
+    finally:
+        logging.shutdown()
+
+if sys.version_info[:2] < (2, 4):
+    def reversed(iterable):
+        result = list(iterable);
+        result.reverse()
+        return result