1############################################################################## 2# 3# Copyright (c) 2006 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE. 12# 13############################################################################## 14"""Bootstrap a buildout-based project 15 16Simply run this script in a directory containing a buildout.cfg. 17The script accepts buildout command-line options, so you can 18use the -c option to specify an alternate configuration file. 19""" 20 21import os 22import shutil 23import sys 24import tempfile 25 26from optparse import OptionParser 27 28tmpeggs = tempfile.mkdtemp() 29 30usage = '''\ 31[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] 32 33Bootstraps a buildout-based project. 34 35Simply run this script in a directory containing a buildout.cfg, using the 36Python that you want bin/buildout to use. 37 38Note that by using --find-links to point to local resources, you can keep 39this script from going over the network. 40''' 41 42parser = OptionParser(usage=usage) 43parser.add_option("-v", "--version", help="use a specific zc.buildout version") 44 45parser.add_option("-t", "--accept-buildout-test-releases", 46 dest='accept_buildout_test_releases', 47 action="store_true", default=False, 48 help=("Normally, if you do not specify a --version, the " 49 "bootstrap script and buildout gets the newest " 50 "*final* versions of zc.buildout and its recipes and " 51 "extensions for you. If you use this flag, " 52 "bootstrap and buildout will get the newest releases " 53 "even if they are alphas or betas.")) 54parser.add_option("-c", "--config-file", 55 help=("Specify the path to the buildout configuration " 56 "file to be used.")) 57parser.add_option("-f", "--find-links", 58 help=("Specify a URL to search for buildout releases")) 59parser.add_option("--allow-site-packages", 60 action="store_true", default=False, 61 help=("Let bootstrap.py use existing site packages")) 62parser.add_option("--setuptools-version", 63 help="use a specific setuptools version") 64 65 66options, args = parser.parse_args() 67 68###################################################################### 69# load/install setuptools 70 71try: 72 if options.allow_site_packages: 73 import setuptools 74 import pkg_resources 75 from urllib.request import urlopen 76except ImportError: 77 from urllib2 import urlopen 78 79ez = {} 80exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) 81 82if not options.allow_site_packages: 83 # ez_setup imports site, which adds site packages 84 # this will remove them from the path to ensure that incompatible versions 85 # of setuptools are not in the path 86 import site 87 # inside a virtualenv, there is no 'getsitepackages'. 88 # We can't remove these reliably 89 if hasattr(site, 'getsitepackages'): 90 for sitepackage_path in site.getsitepackages(): 91 sys.path[:] = [x for x in sys.path if sitepackage_path not in x] 92 93setup_args = dict(to_dir=tmpeggs, download_delay=0) 94 95if options.setuptools_version is not None: 96 setup_args['version'] = options.setuptools_version 97 98ez['use_setuptools'](**setup_args) 99import setuptools 100import pkg_resources 101 102# This does not (always?) update the default working set. We will 103# do it. 104for path in sys.path: 105 if path not in pkg_resources.working_set.entries: 106 pkg_resources.working_set.add_entry(path) 107 108###################################################################### 109# Install buildout 110 111ws = pkg_resources.working_set 112 113cmd = [sys.executable, '-c', 114 'from setuptools.command.easy_install import main; main()', 115 '-mZqNxd', tmpeggs] 116 117find_links = os.environ.get( 118 'bootstrap-testing-find-links', 119 options.find_links or 120 ('http://downloads.buildout.org/' 121 if options.accept_buildout_test_releases else None) 122 ) 123if find_links: 124 cmd.extend(['-f', find_links]) 125 126setuptools_path = ws.find( 127 pkg_resources.Requirement.parse('setuptools')).location 128 129requirement = 'zc.buildout' 130version = options.version 131if version is None and not options.accept_buildout_test_releases: 132 # Figure out the most recent final version of zc.buildout. 133 import setuptools.package_index 134 _final_parts = '*final-', '*final' 135 136 def _final_version(parsed_version): 137 try: 138 return not parsed_version.is_prerelease 139 except AttributeError: 140 # Older setuptools 141 for part in parsed_version: 142 if (part[:1] == '*') and (part not in _final_parts): 143 return False 144 return True 145 146 index = setuptools.package_index.PackageIndex( 147 search_path=[setuptools_path]) 148 if find_links: 149 index.add_find_links((find_links,)) 150 req = pkg_resources.Requirement.parse(requirement) 151 if index.obtain(req) is not None: 152 best = [] 153 bestv = None 154 for dist in index[req.project_name]: 155 distv = dist.parsed_version 156 if _final_version(distv): 157 if bestv is None or distv > bestv: 158 best = [dist] 159 bestv = distv 160 elif distv == bestv: 161 best.append(dist) 162 if best: 163 best.sort() 164 version = best[-1].version 165if version: 166 requirement = '=='.join((requirement, version)) 167cmd.append(requirement) 168 169import subprocess 170if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0: 171 raise Exception( 172 "Failed to execute command:\n%s" % repr(cmd)[1:-1]) 173 174###################################################################### 175# Import and run buildout 176 177ws.add_entry(tmpeggs) 178ws.require(requirement) 179import zc.buildout.buildout 180 181if not [a for a in args if '=' not in a]: 182 args.append('bootstrap') 183 184# if -c was provided, we push it back into args for buildout' main function 185if options.config_file is not None: 186 args[0:0] = ['-c', options.config_file] 187 188zc.buildout.buildout.main(args) 189shutil.rmtree(tmpeggs) 190