Skip to content

Commit 38aa799

Browse files
committed
switch to v2 bootstrap.py script
1 parent 1a3408d commit 38aa799

File tree

1 file changed

+62
-169
lines changed

1 file changed

+62
-169
lines changed

bootstrap.py

Lines changed: 62 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -18,75 +18,14 @@
1818
use the -c option to specify an alternate configuration file.
1919
"""
2020

21-
import os, shutil, sys, tempfile, urllib, urllib2, subprocess
22-
from optparse import OptionParser
23-
24-
if sys.platform == 'win32':
25-
def quote(c):
26-
if ' ' in c:
27-
return '"%s"' % c # work around spawn lamosity on windows
28-
else:
29-
return c
30-
else:
31-
quote = str
32-
33-
# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
34-
stdout, stderr = subprocess.Popen(
35-
[sys.executable, '-Sc',
36-
'try:\n'
37-
' import ConfigParser\n'
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 # imported because of its side effects
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'
21+
import os
22+
import shutil
23+
import sys
24+
import tempfile
7425

26+
from optparse import OptionParser
7527

76-
# parsing arguments
77-
def normalize_to_url(option, opt_str, value, parser):
78-
if value:
79-
if '://' not in value: # It doesn't smell like a URL.
80-
value = 'file://%s' % (
81-
urllib.pathname2url(
82-
os.path.abspath(os.path.expanduser(value))),)
83-
if opt_str == '--download-base' and not value.endswith('/'):
84-
# Download base needs a trailing slash to make the world happy.
85-
value += '/'
86-
else:
87-
value = None
88-
name = opt_str[2:].replace('-', '_')
89-
setattr(parser.values, name, value)
28+
tmpeggs = tempfile.mkdtemp()
9029

9130
usage = '''\
9231
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
@@ -96,31 +35,13 @@ def normalize_to_url(http://github.com/option,%20opt_str,%20value,%20parser):
9635
Simply run this script in a directory containing a buildout.cfg, using the
9736
Python that you want bin/buildout to use.
9837
99-
Note that by using --setup-source and --download-base to point to
100-
local resources, you can keep this script from going over the network.
38+
Note that by using --find-links to point to local resources, you can keep
39+
this script from going over the network.
10140
'''
10241

10342
parser = OptionParser(usage=usage)
104-
parser.add_option("-v", "--version", dest="version",
105-
help="use a specific zc.buildout version")
106-
parser.add_option("-d", "--distribute",
107-
action="store_true", dest="use_distribute", default=False,
108-
help="Use Distribute rather than Setuptools.")
109-
parser.add_option("--setup-source", action="callback", dest="setup_source",
110-
callback=normalize_to_url, nargs=1, type="string",
111-
help=("Specify a URL or file location for the setup file. "
112-
"If you use Setuptools, this will default to " +
113-
setuptools_source + "; if you use Distribute, this "
114-
"will default to " + distribute_source + "."))
115-
parser.add_option("--download-base", action="callback", dest="download_base",
116-
callback=normalize_to_url, nargs=1, type="string",
117-
help=("Specify a URL or directory for downloading "
118-
"zc.buildout and either Setuptools or Distribute. "
119-
"Defaults to PyPI."))
120-
parser.add_option("--eggs",
121-
help=("Specify a directory for storing eggs. Defaults to "
122-
"a temporary directory that is deleted when the "
123-
"bootstrap script completes."))
43+
parser.add_option("-v", "--version", help="use a specific zc.buildout version")
44+
12445
parser.add_option("-t", "--accept-buildout-test-releases",
12546
dest='accept_buildout_test_releases',
12647
action="store_true", default=False,
@@ -130,80 +51,65 @@ def normalize_to_url(http://github.com/option,%20opt_str,%20value,%20parser):
13051
"extensions for you. If you use this flag, "
13152
"bootstrap and buildout will get the newest releases "
13253
"even if they are alphas or betas."))
133-
parser.add_option("-c", None, action="store", dest="config_file",
134-
help=("Specify the path to the buildout configuration "
135-
"file to be used."))
54+
parser.add_option("-c", "--config-file",
55+
help=("Specify the path to the buildout configuration "
56+
"file to be used."))
57+
parser.add_option("-f", "--find-links",
58+
help=("Specify a URL to search for buildout releases"))
13659

137-
options, args = parser.parse_args()
13860

139-
if options.eggs:
140-
eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
141-
else:
142-
eggs_dir = tempfile.mkdtemp()
143-
144-
if options.setup_source is None:
145-
if options.use_distribute:
146-
options.setup_source = distribute_source
147-
else:
148-
options.setup_source = setuptools_source
61+
options, args = parser.parse_args()
14962

150-
if options.accept_buildout_test_releases:
151-
args.insert(0, 'buildout:accept-buildout-test-releases=true')
63+
######################################################################
64+
# load/install setuptools
15265

66+
to_reload = False
15367
try:
15468
import pkg_resources
155-
import setuptools # A flag. Sometimes pkg_resources is installed alone.
156-
if not hasattr(pkg_resources, '_distribute'):
157-
raise ImportError
69+
import setuptools
15870
except ImportError:
159-
ez_code = urllib2.urlopen(
160-
options.setup_source).read().replace('\r\n', '\n')
16171
ez = {}
162-
exec ez_code in ez
163-
setup_args = dict(to_dir=eggs_dir, download_delay=0)
164-
if options.download_base:
165-
setup_args['download_base'] = options.download_base
166-
if options.use_distribute:
167-
setup_args['no_fake'] = True
168-
if sys.version_info[:2] == (2, 4):
169-
setup_args['version'] = '0.6.32'
72+
73+
try:
74+
from urllib.request import urlopen
75+
except ImportError:
76+
from urllib2 import urlopen
77+
78+
# XXX use a more permanent ez_setup.py URL when available.
79+
exec(urlopen('https://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py'
80+
).read(), ez)
81+
setup_args = dict(to_dir=tmpeggs, download_delay=0)
17082
ez['use_setuptools'](**setup_args)
171-
if 'pkg_resources' in sys.modules:
172-
reload(sys.modules['pkg_resources'])
83+
84+
if to_reload:
85+
reload(pkg_resources)
17386
import pkg_resources
17487
# This does not (always?) update the default working set. We will
17588
# do it.
17689
for path in sys.path:
17790
if path not in pkg_resources.working_set.entries:
17891
pkg_resources.working_set.add_entry(path)
17992

180-
cmd = [quote(sys.executable),
181-
'-c',
182-
quote('from setuptools.command.easy_install import main; main()'),
183-
'-mqNxd',
184-
quote(eggs_dir)]
93+
######################################################################
94+
# Install buildout
95+
96+
ws = pkg_resources.working_set
18597

186-
if not has_broken_dash_S:
187-
cmd.insert(1, '-S')
98+
cmd = [sys.executable, '-c',
99+
'from setuptools.command.easy_install import main; main()',
100+
'-mZqNxd', tmpeggs]
188101

189-
find_links = options.download_base
190-
if not find_links:
191-
find_links = os.environ.get('bootstrap-testing-find-links')
192-
if not find_links and options.accept_buildout_test_releases:
193-
find_links = 'http://downloads.buildout.org/'
102+
find_links = os.environ.get(
103+
'bootstrap-testing-find-links',
104+
options.find_links or
105+
('http://downloads.buildout.org/'
106+
if options.accept_buildout_test_releases else None)
107+
)
194108
if find_links:
195-
cmd.extend(['-f', quote(find_links)])
109+
cmd.extend(['-f', find_links])
196110

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)
111+
setuptools_path = ws.find(
112+
pkg_resources.Requirement.parse('setuptools')).location
207113

208114
requirement = 'zc.buildout'
209115
version = options.version
@@ -218,7 +124,7 @@ def _final_version(parsed_version):
218124
return False
219125
return True
220126
index = setuptools.package_index.PackageIndex(
221-
search_path=[setup_requirement_path])
127+
search_path=[setuptools_path])
222128
if find_links:
223129
index.add_find_links((find_links,))
224130
req = pkg_resources.Requirement.parse(requirement)
@@ -227,8 +133,6 @@ def _final_version(parsed_version):
227133
bestv = None
228134
for dist in index[req.project_name]:
229135
distv = dist.parsed_version
230-
if distv >= pkg_resources.parse_version('2dev'):
231-
continue
232136
if _final_version(distv):
233137
if bestv is None or distv > bestv:
234138
best = [dist]
@@ -238,40 +142,29 @@ def _final_version(parsed_version):
238142
if best:
239143
best.sort()
240144
version = best[-1].version
241-
242145
if version:
243-
requirement += '=='+version
244-
else:
245-
requirement += '<2dev'
246-
146+
requirement = '=='.join((requirement, version))
247147
cmd.append(requirement)
248148

249-
if is_jython:
250-
import subprocess
251-
exitcode = subprocess.Popen(cmd, env=env).wait()
252-
else: # Windows prefers this, apparently; otherwise we would prefer subprocess
253-
exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
254-
if exitcode != 0:
255-
sys.stdout.flush()
256-
sys.stderr.flush()
257-
print ("An error occurred when trying to install zc.buildout. "
258-
"Look above this message for any errors that "
259-
"were output by easy_install.")
260-
sys.exit(exitcode)
149+
import subprocess
150+
if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
151+
raise Exception(
152+
"Failed to execute command:\n%s",
153+
repr(cmd)[1:-1])
261154

262-
ws.add_entry(eggs_dir)
155+
######################################################################
156+
# Import and run buildout
157+
158+
ws.add_entry(tmpeggs)
263159
ws.require(requirement)
264160
import zc.buildout.buildout
265161

266-
# If there isn't already a command in the args, add bootstrap
267162
if not [a for a in args if '=' not in a]:
268163
args.append('bootstrap')
269164

270-
271-
# if -c was provided, we push it back into args for buildout's main function
165+
# if -c was provided, we push it back into args for buildout' main function
272166
if options.config_file is not None:
273167
args[0:0] = ['-c', options.config_file]
274168

275169
zc.buildout.buildout.main(args)
276-
if not options.eggs: # clean up temporary egg directory
277-
shutil.rmtree(eggs_dir)
170+
shutil.rmtree(tmpeggs)

0 commit comments

Comments
 (0)