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 28__version__ = '2015-07-01' 29# See zc.buildout's changelog if this version is up to date. 30 31tmpeggs = tempfile.mkdtemp(prefix='bootstrap-') 32 33usage = '''\ 34[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] 35 36Bootstraps a buildout-based project. 37 38Simply run this script in a directory containing a buildout.cfg, using the 39Python that you want bin/buildout to use. 40 41Note that by using --find-links to point to local resources, you can keep 42this script from going over the network. 43''' 44 45parser = OptionParser(usage=usage) 46parser.add_option("--version", 47 action="store_true", default=False, 48 help=("Return bootstrap.py version.")) 49parser.add_option("-t", "--accept-buildout-test-releases", 50 dest='accept_buildout_test_releases', 51 action="store_true", default=False, 52 help=("Normally, if you do not specify a --version, the " 53 "bootstrap script and buildout gets the newest " 54 "*final* versions of zc.buildout and its recipes and " 55 "extensions for you. If you use this flag, " 56 "bootstrap and buildout will get the newest releases " 57 "even if they are alphas or betas.")) 58parser.add_option("-c", "--config-file", 59 help=("Specify the path to the buildout configuration " 60 "file to be used.")) 61parser.add_option("-f", "--find-links", 62 help=("Specify a URL to search for buildout releases")) 63parser.add_option("--allow-site-packages", 64 action="store_true", default=False, 65 help=("Let bootstrap.py use existing site packages")) 66parser.add_option("--buildout-version", 67 help="Use a specific zc.buildout version") 68parser.add_option("--setuptools-version", 69 help="Use a specific setuptools version") 70parser.add_option("--setuptools-to-dir", 71 help=("Allow for re-use of existing directory of " 72 "setuptools versions")) 73 74options, args = parser.parse_args() 75if options.version: 76 print("bootstrap.py version %s" % __version__) 77 sys.exit(0) 78 79 80###################################################################### 81# load/install setuptools 82 83try: 84 from urllib.request import urlopen 85except ImportError: 86 from urllib2 import urlopen 87 88ez = {} 89if os.path.exists('ez_setup.py'): 90 exec(open('ez_setup.py').read(), ez) 91else: 92 exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) 93 94if not options.allow_site_packages: 95 # ez_setup imports site, which adds site packages 96 # this will remove them from the path to ensure that incompatible versions 97 # of setuptools are not in the path 98 import site 99 # inside a virtualenv, there is no 'getsitepackages'. 100 # We can't remove these reliably 101 if hasattr(site, 'getsitepackages'): 102 for sitepackage_path in site.getsitepackages(): 103 # Strip all site-packages directories from sys.path that 104 # are not sys.prefix; this is because on Windows 105 # sys.prefix is a site-package directory. 106 if sitepackage_path != sys.prefix: 107 sys.path[:] = [x for x in sys.path 108 if sitepackage_path not in x] 109 110setup_args = dict(to_dir=tmpeggs, download_delay=0) 111 112if options.setuptools_version is not None: 113 setup_args['version'] = options.setuptools_version 114if options.setuptools_to_dir is not None: 115 setup_args['to_dir'] = options.setuptools_to_dir 116 117ez['use_setuptools'](**setup_args) 118import setuptools 119import pkg_resources 120 121# This does not (always?) update the default working set. We will 122# do it. 123for path in sys.path: 124 if path not in pkg_resources.working_set.entries: 125 pkg_resources.working_set.add_entry(path) 126 127###################################################################### 128# Install buildout 129 130ws = pkg_resources.working_set 131 132setuptools_path = ws.find( 133 pkg_resources.Requirement.parse('setuptools')).location 134 135# Fix sys.path here as easy_install.pth added before PYTHONPATH 136cmd = [sys.executable, '-c', 137 'import sys; sys.path[0:0] = [%r]; ' % setuptools_path + 138 'from setuptools.command.easy_install import main; main()', 139 '-mZqNxd', tmpeggs] 140 141find_links = os.environ.get( 142 'bootstrap-testing-find-links', 143 options.find_links or 144 ('http://downloads.buildout.org/' 145 if options.accept_buildout_test_releases else None) 146 ) 147if find_links: 148 cmd.extend(['-f', find_links]) 149 150requirement = 'zc.buildout' 151version = options.buildout_version 152if version is None and not options.accept_buildout_test_releases: 153 # Figure out the most recent final version of zc.buildout. 154 import setuptools.package_index 155 _final_parts = '*final-', '*final' 156 157 def _final_version(parsed_version): 158 try: 159 return not parsed_version.is_prerelease 160 except AttributeError: 161 # Older setuptools 162 for part in parsed_version: 163 if (part[:1] == '*') and (part not in _final_parts): 164 return False 165 return True 166 167 index = setuptools.package_index.PackageIndex( 168 search_path=[setuptools_path]) 169 if find_links: 170 index.add_find_links((find_links,)) 171 req = pkg_resources.Requirement.parse(requirement) 172 if index.obtain(req) is not None: 173 best = [] 174 bestv = None 175 for dist in index[req.project_name]: 176 distv = dist.parsed_version 177 if _final_version(distv): 178 if bestv is None or distv > bestv: 179 best = [dist] 180 bestv = distv 181 elif distv == bestv: 182 best.append(dist) 183 if best: 184 best.sort() 185 version = best[-1].version 186if version: 187 requirement = '=='.join((requirement, version)) 188cmd.append(requirement) 189 190import subprocess 191if subprocess.call(cmd) != 0: 192 raise Exception( 193 "Failed to execute command:\n%s" % repr(cmd)[1:-1]) 194 195###################################################################### 196# Import and run buildout 197 198ws.add_entry(tmpeggs) 199ws.require(requirement) 200import zc.buildout.buildout 201 202if not [a for a in args if '=' not in a]: 203 args.append('bootstrap') 204 205# if -c was provided, we push it back into args for buildout' main function 206if options.config_file is not None: 207 args[0:0] = ['-c', options.config_file] 208 209zc.buildout.buildout.main(args) 210shutil.rmtree(tmpeggs) 211