Mercurial > hg > ltpdarepo
comparison bootstrap.py @ 11:66101b35a8c0
Upgrade buildout bootstrap.py to latest version.
author | Daniele Nicolodi <daniele@grinta.net> |
---|---|
date | Sat, 25 Jun 2011 17:47:51 +0200 |
parents | c812c3020b63 |
children | 773d9567dcb2 |
comparison
equal
deleted
inserted
replaced
10:ec561d030fc2 | 11:66101b35a8c0 |
---|---|
1 ############################################################################## | 1 ############################################################################## |
2 # | 2 # |
3 # Copyright (c) 2006 Zope Corporation and Contributors. | 3 # Copyright (c) 2006 Zope Foundation and Contributors. |
4 # All Rights Reserved. | 4 # All Rights Reserved. |
5 # | 5 # |
6 # This software is subject to the provisions of the Zope Public License, | 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. | 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 | 8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
14 """Bootstrap a buildout-based project | 14 """Bootstrap a buildout-based project |
15 | 15 |
16 Simply run this script in a directory containing a buildout.cfg. | 16 Simply run this script in a directory containing a buildout.cfg. |
17 The script accepts buildout command-line options, so you can | 17 The script accepts buildout command-line options, so you can |
18 use the -c option to specify an alternate configuration file. | 18 use the -c option to specify an alternate configuration file. |
19 | |
20 $Id: bootstrap.py 105417 2009-11-01 15:15:20Z tarek $ | |
21 """ | 19 """ |
22 | 20 |
23 import os, shutil, sys, tempfile, urllib2 | 21 import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess |
24 from optparse import OptionParser | 22 from optparse import OptionParser |
25 | |
26 tmpeggs = tempfile.mkdtemp() | |
27 | |
28 is_jython = sys.platform.startswith('java') | |
29 | |
30 # parsing arguments | |
31 parser = OptionParser() | |
32 parser.add_option("-v", "--version", dest="version", | |
33 help="use a specific zc.buildout version") | |
34 parser.add_option("-d", "--distribute", | |
35 action="store_true", dest="distribute", default=False, | |
36 help="Use Disribute rather than Setuptools.") | |
37 | |
38 parser.add_option("-c", None, action="store", dest="config_file", | |
39 help=("Specify the path to the buildout configuration " | |
40 "file to be used.")) | |
41 | |
42 options, args = parser.parse_args() | |
43 | |
44 # if -c was provided, we push it back into args for buildout' main function | |
45 if options.config_file is not None: | |
46 args += ['-c', options.config_file] | |
47 | |
48 if options.version is not None: | |
49 VERSION = '==%s' % options.version | |
50 else: | |
51 VERSION = '' | |
52 | |
53 USE_DISTRIBUTE = options.distribute | |
54 args = args + ['bootstrap'] | |
55 | |
56 to_reload = False | |
57 try: | |
58 import pkg_resources | |
59 if not hasattr(pkg_resources, '_distribute'): | |
60 to_reload = True | |
61 raise ImportError | |
62 except ImportError: | |
63 ez = {} | |
64 if USE_DISTRIBUTE: | |
65 exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' | |
66 ).read() in ez | |
67 ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) | |
68 else: | |
69 exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' | |
70 ).read() in ez | |
71 ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) | |
72 | |
73 if to_reload: | |
74 reload(pkg_resources) | |
75 else: | |
76 import pkg_resources | |
77 | 23 |
78 if sys.platform == 'win32': | 24 if sys.platform == 'win32': |
79 def quote(c): | 25 def quote(c): |
80 if ' ' in c: | 26 if ' ' in c: |
81 return '"%s"' % c # work around spawn lamosity on windows | 27 return '"%s"' % c # work around spawn lamosity on windows |
82 else: | 28 else: |
83 return c | 29 return c |
84 else: | 30 else: |
85 def quote (c): | 31 quote = str |
86 return c | 32 |
87 | 33 # See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. |
88 cmd = 'from setuptools.command.easy_install import main; main()' | 34 stdout, stderr = subprocess.Popen( |
89 ws = pkg_resources.working_set | 35 [sys.executable, '-Sc', |
90 | 36 'try:\n' |
91 if USE_DISTRIBUTE: | 37 ' import ConfigParser\n' |
92 requirement = 'distribute' | 38 'except ImportError:\n' |
39 ' print 1\n' | |
40 'else:\n' | |
41 ' print 0\n'], | |
42 stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() | |
43 has_broken_dash_S = bool(int(stdout.strip())) | |
44 | |
45 # In order to be more robust in the face of system Pythons, we want to | |
46 # run without site-packages loaded. This is somewhat tricky, in | |
47 # particular because Python 2.6's distutils imports site, so starting | |
48 # with the -S flag is not sufficient. However, we'll start with that: | |
49 if not has_broken_dash_S and 'site' in sys.modules: | |
50 # We will restart with python -S. | |
51 args = sys.argv[:] | |
52 args[0:0] = [sys.executable, '-S'] | |
53 args = map(quote, args) | |
54 os.execv(sys.executable, args) | |
55 # Now we are running with -S. We'll get the clean sys.path, import site | |
56 # because distutils will do it later, and then reset the path and clean | |
57 # out any namespace packages from site-packages that might have been | |
58 # loaded by .pth files. | |
59 clean_path = sys.path[:] | |
60 import site | |
61 sys.path[:] = clean_path | |
62 for k, v in sys.modules.items(): | |
63 if k in ('setuptools', 'pkg_resources') or ( | |
64 hasattr(v, '__path__') and | |
65 len(v.__path__)==1 and | |
66 not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): | |
67 # This is a namespace package. Remove it. | |
68 sys.modules.pop(k) | |
69 | |
70 is_jython = sys.platform.startswith('java') | |
71 | |
72 setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' | |
73 distribute_source = 'http://python-distribute.org/distribute_setup.py' | |
74 | |
75 # parsing arguments | |
76 def normalize_to_url(option, opt_str, value, parser): | |
77 if value: | |
78 if '://' not in value: # It doesn't smell like a URL. | |
79 value = 'file://%s' % ( | |
80 urllib.pathname2url( | |
81 os.path.abspath(os.path.expanduser(value))),) | |
82 if opt_str == '--download-base' and not value.endswith('/'): | |
83 # Download base needs a trailing slash to make the world happy. | |
84 value += '/' | |
85 else: | |
86 value = None | |
87 name = opt_str[2:].replace('-', '_') | |
88 setattr(parser.values, name, value) | |
89 | |
90 usage = '''\ | |
91 [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] | |
92 | |
93 Bootstraps a buildout-based project. | |
94 | |
95 Simply run this script in a directory containing a buildout.cfg, using the | |
96 Python that you want bin/buildout to use. | |
97 | |
98 Note that by using --setup-source and --download-base to point to | |
99 local resources, you can keep this script from going over the network. | |
100 ''' | |
101 | |
102 parser = OptionParser(usage=usage) | |
103 parser.add_option("-v", "--version", dest="version", | |
104 help="use a specific zc.buildout version") | |
105 parser.add_option("-d", "--distribute", | |
106 action="store_true", dest="use_distribute", default=False, | |
107 help="Use Distribute rather than Setuptools.") | |
108 parser.add_option("--setup-source", action="callback", dest="setup_source", | |
109 callback=normalize_to_url, nargs=1, type="string", | |
110 help=("Specify a URL or file location for the setup file. " | |
111 "If you use Setuptools, this will default to " + | |
112 setuptools_source + "; if you use Distribute, this " | |
113 "will default to " + distribute_source +".")) | |
114 parser.add_option("--download-base", action="callback", dest="download_base", | |
115 callback=normalize_to_url, nargs=1, type="string", | |
116 help=("Specify a URL or directory for downloading " | |
117 "zc.buildout and either Setuptools or Distribute. " | |
118 "Defaults to PyPI.")) | |
119 parser.add_option("--eggs", | |
120 help=("Specify a directory for storing eggs. Defaults to " | |
121 "a temporary directory that is deleted when the " | |
122 "bootstrap script completes.")) | |
123 parser.add_option("-t", "--accept-buildout-test-releases", | |
124 dest='accept_buildout_test_releases', | |
125 action="store_true", default=False, | |
126 help=("Normally, if you do not specify a --version, the " | |
127 "bootstrap script and buildout gets the newest " | |
128 "*final* versions of zc.buildout and its recipes and " | |
129 "extensions for you. If you use this flag, " | |
130 "bootstrap and buildout will get the newest releases " | |
131 "even if they are alphas or betas.")) | |
132 parser.add_option("-c", None, action="store", dest="config_file", | |
133 help=("Specify the path to the buildout configuration " | |
134 "file to be used.")) | |
135 | |
136 options, args = parser.parse_args() | |
137 | |
138 # if -c was provided, we push it back into args for buildout's main function | |
139 if options.config_file is not None: | |
140 args += ['-c', options.config_file] | |
141 | |
142 if options.eggs: | |
143 eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) | |
93 else: | 144 else: |
94 requirement = 'setuptools' | 145 eggs_dir = tempfile.mkdtemp() |
146 | |
147 if options.setup_source is None: | |
148 if options.use_distribute: | |
149 options.setup_source = distribute_source | |
150 else: | |
151 options.setup_source = setuptools_source | |
152 | |
153 if options.accept_buildout_test_releases: | |
154 args.append('buildout:accept-buildout-test-releases=true') | |
155 args.append('bootstrap') | |
156 | |
157 try: | |
158 import pkg_resources | |
159 import setuptools # A flag. Sometimes pkg_resources is installed alone. | |
160 if not hasattr(pkg_resources, '_distribute'): | |
161 raise ImportError | |
162 except ImportError: | |
163 ez_code = urllib2.urlopen( | |
164 options.setup_source).read().replace('\r\n', '\n') | |
165 ez = {} | |
166 exec ez_code in ez | |
167 setup_args = dict(to_dir=eggs_dir, download_delay=0) | |
168 if options.download_base: | |
169 setup_args['download_base'] = options.download_base | |
170 if options.use_distribute: | |
171 setup_args['no_fake'] = True | |
172 ez['use_setuptools'](**setup_args) | |
173 if 'pkg_resources' in sys.modules: | |
174 reload(sys.modules['pkg_resources']) | |
175 import pkg_resources | |
176 # This does not (always?) update the default working set. We will | |
177 # do it. | |
178 for path in sys.path: | |
179 if path not in pkg_resources.working_set.entries: | |
180 pkg_resources.working_set.add_entry(path) | |
181 | |
182 cmd = [quote(sys.executable), | |
183 '-c', | |
184 quote('from setuptools.command.easy_install import main; main()'), | |
185 '-mqNxd', | |
186 quote(eggs_dir)] | |
187 | |
188 if not has_broken_dash_S: | |
189 cmd.insert(1, '-S') | |
190 | |
191 find_links = options.download_base | |
192 if not find_links: | |
193 find_links = os.environ.get('bootstrap-testing-find-links') | |
194 if find_links: | |
195 cmd.extend(['-f', quote(find_links)]) | |
196 | |
197 if options.use_distribute: | |
198 setup_requirement = 'distribute' | |
199 else: | |
200 setup_requirement = 'setuptools' | |
201 ws = pkg_resources.working_set | |
202 setup_requirement_path = ws.find( | |
203 pkg_resources.Requirement.parse(setup_requirement)).location | |
204 env = dict( | |
205 os.environ, | |
206 PYTHONPATH=setup_requirement_path) | |
207 | |
208 requirement = 'zc.buildout' | |
209 version = options.version | |
210 if version is None and not options.accept_buildout_test_releases: | |
211 # Figure out the most recent final version of zc.buildout. | |
212 import setuptools.package_index | |
213 _final_parts = '*final-', '*final' | |
214 def _final_version(parsed_version): | |
215 for part in parsed_version: | |
216 if (part[:1] == '*') and (part not in _final_parts): | |
217 return False | |
218 return True | |
219 index = setuptools.package_index.PackageIndex( | |
220 search_path=[setup_requirement_path]) | |
221 if find_links: | |
222 index.add_find_links((find_links,)) | |
223 req = pkg_resources.Requirement.parse(requirement) | |
224 if index.obtain(req) is not None: | |
225 best = [] | |
226 bestv = None | |
227 for dist in index[req.project_name]: | |
228 distv = dist.parsed_version | |
229 if _final_version(distv): | |
230 if bestv is None or distv > bestv: | |
231 best = [dist] | |
232 bestv = distv | |
233 elif distv == bestv: | |
234 best.append(dist) | |
235 if best: | |
236 best.sort() | |
237 version = best[-1].version | |
238 if version: | |
239 requirement = '=='.join((requirement, version)) | |
240 cmd.append(requirement) | |
95 | 241 |
96 if is_jython: | 242 if is_jython: |
97 import subprocess | 243 import subprocess |
98 | 244 exitcode = subprocess.Popen(cmd, env=env).wait() |
99 assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', | 245 else: # Windows prefers this, apparently; otherwise we would prefer subprocess |
100 quote(tmpeggs), 'zc.buildout' + VERSION], | 246 exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) |
101 env=dict(os.environ, | 247 if exitcode != 0: |
102 PYTHONPATH= | 248 sys.stdout.flush() |
103 ws.find(pkg_resources.Requirement.parse(requirement)).location | 249 sys.stderr.flush() |
104 ), | 250 print ("An error occurred when trying to install zc.buildout. " |
105 ).wait() == 0 | 251 "Look above this message for any errors that " |
106 | 252 "were output by easy_install.") |
107 else: | 253 sys.exit(exitcode) |
108 assert os.spawnle( | 254 |
109 os.P_WAIT, sys.executable, quote (sys.executable), | 255 ws.add_entry(eggs_dir) |
110 '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION, | 256 ws.require(requirement) |
111 dict(os.environ, | |
112 PYTHONPATH= | |
113 ws.find(pkg_resources.Requirement.parse(requirement)).location | |
114 ), | |
115 ) == 0 | |
116 | |
117 ws.add_entry(tmpeggs) | |
118 ws.require('zc.buildout' + VERSION) | |
119 import zc.buildout.buildout | 257 import zc.buildout.buildout |
120 zc.buildout.buildout.main(args) | 258 zc.buildout.buildout.main(args) |
121 shutil.rmtree(tmpeggs) | 259 if not options.eggs: # clean up temporary egg directory |
260 shutil.rmtree(eggs_dir) |