diff -r 5ff1fc726848 -r c6bca38c1cbf eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/buildout.py --- /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