18
18
use the -c option to specify an alternate configuration file.
19
19
"""
20
20
21
- import os , shutil , sys , tempfile , urllib , urllib2 , subprocess
21
+ import os
22
+ import shutil
23
+ import sys
24
+ import tempfile
25
+
22
26
from optparse import OptionParser
23
27
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'
74
-
75
-
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
+ __version__ = '2015-07-01'
29
+ # See zc.buildout's changelog if this version is up to date.
30
+
31
+ tmpeggs = tempfile .mkdtemp (prefix = 'bootstrap-' )
90
32
91
33
usage = '''\
92
34
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
@@ -96,130 +38,134 @@ def normalize_to_url(option, opt_str, value, parser):
96
38
Simply run this script in a directory containing a buildout.cfg, using the
97
39
Python that you want bin/buildout to use.
98
40
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.
41
+ Note that by using --find-links to point to local resources, you can keep
42
+ this script from going over the network.
101
43
'''
102
44
103
45
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." ))
46
+ parser .add_option ("--version" ,
47
+ action = "store_true" , default = False ,
48
+ help = ("Return bootstrap.py version." ))
124
49
parser .add_option ("-t" , "--accept-buildout-test-releases" ,
125
50
dest = 'accept_buildout_test_releases' ,
126
51
action = "store_true" , default = False ,
127
- help = ("Normally, if you do not specify a --version, the "
128
- "bootstrap script and buildout gets the newest "
52
+ help = ("Normally, if you do not specify a --buildout- version, "
53
+ "the bootstrap script and buildout gets the newest "
129
54
"*final* versions of zc.buildout and its recipes and "
130
55
"extensions for you. If you use this flag, "
131
56
"bootstrap and buildout will get the newest releases "
132
57
"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." ))
58
+ parser .add_option ("-c" , "--config-file" ,
59
+ help = ("Specify the path to the buildout configuration "
60
+ "file to be used." ))
61
+ parser .add_option ("-f" , "--find-links" ,
62
+ help = ("Specify a URL to search for buildout releases" ))
63
+ parser .add_option ("--allow-site-packages" ,
64
+ action = "store_true" , default = False ,
65
+ help = ("Let bootstrap.py use existing site packages" ))
66
+ parser .add_option ("--buildout-version" ,
67
+ help = "Use a specific zc.buildout version" )
68
+ parser .add_option ("--setuptools-version" ,
69
+ help = "Use a specific setuptools version" )
70
+ parser .add_option ("--setuptools-to-dir" ,
71
+ help = ("Allow for re-use of existing directory of "
72
+ "setuptools versions" ))
136
73
137
74
options , args = parser .parse_args ()
75
+ if options .version :
76
+ print ("bootstrap.py version %s" % __version__ )
77
+ sys .exit (0 )
138
78
139
- # if -c was provided, we push it back into args for buildout's main function
140
- if options .config_file is not None :
141
- args += ['-c' , options .config_file ]
142
-
143
- if options .eggs :
144
- eggs_dir = os .path .abspath (os .path .expanduser (options .eggs ))
145
- else :
146
- eggs_dir = tempfile .mkdtemp ()
147
79
148
- if options .setup_source is None :
149
- if options .use_distribute :
150
- options .setup_source = distribute_source
151
- else :
152
- options .setup_source = setuptools_source
153
-
154
- if options .accept_buildout_test_releases :
155
- args .append ('buildout:accept-buildout-test-releases=true' )
156
- args .append ('bootstrap' )
80
+ ######################################################################
81
+ # load/install setuptools
157
82
158
83
try :
159
- import pkg_resources
160
- import setuptools # A flag. Sometimes pkg_resources is installed alone.
161
- if not hasattr (pkg_resources , '_distribute' ):
162
- raise ImportError
84
+ from urllib .request import urlopen
163
85
except ImportError :
164
- ez_code = urllib2 .urlopen (
165
- options .setup_source ).read ().replace ('\r \n ' , '\n ' )
166
- ez = {}
167
- exec ez_code in ez
168
- setup_args = dict (to_dir = eggs_dir , download_delay = 0 )
169
- if options .download_base :
170
- setup_args ['download_base' ] = options .download_base
171
- if options .use_distribute :
172
- setup_args ['no_fake' ] = True
173
- ez ['use_setuptools' ](** setup_args )
174
- if 'pkg_resources' in sys .modules :
175
- reload (sys .modules ['pkg_resources' ])
176
- import pkg_resources
177
- # This does not (always?) update the default working set. We will
178
- # do it.
179
- for path in sys .path :
180
- if path not in pkg_resources .working_set .entries :
181
- pkg_resources .working_set .add_entry (path )
182
-
183
- cmd = [quote (sys .executable ),
184
- '-c' ,
185
- quote ('from setuptools.command.easy_install import main; main()' ),
186
- '-mqNxd' ,
187
- quote (eggs_dir )]
188
-
189
- if not has_broken_dash_S :
190
- cmd .insert (1 , '-S' )
191
-
192
- find_links = options .download_base
193
- if not find_links :
194
- find_links = os .environ .get ('bootstrap-testing-find-links' )
195
- if find_links :
196
- cmd .extend (['-f' , quote (find_links )])
86
+ from urllib2 import urlopen
197
87
198
- if options .use_distribute :
199
- setup_requirement = 'distribute'
88
+ ez = {}
89
+ if os .path .exists ('ez_setup.py' ):
90
+ exec (open ('ez_setup.py' ).read (), ez )
200
91
else :
201
- setup_requirement = 'setuptools'
92
+ exec (urlopen ('https://bootstrap.pypa.io/ez_setup.py' ).read (), ez )
93
+
94
+ if 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
+
110
+ setup_args = dict (to_dir = tmpeggs , download_delay = 0 )
111
+
112
+ if options .setuptools_version is not None :
113
+ setup_args ['version' ] = options .setuptools_version
114
+ if options .setuptools_to_dir is not None :
115
+ setup_args ['to_dir' ] = options .setuptools_to_dir
116
+
117
+ ez ['use_setuptools' ](** setup_args )
118
+ import setuptools
119
+ import pkg_resources
120
+
121
+ # This does not (always?) update the default working set. We will
122
+ # do it.
123
+ for 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
+
202
130
ws = pkg_resources .working_set
203
- setup_requirement_path = ws .find (
204
- pkg_resources .Requirement .parse (setup_requirement )).location
205
- env = dict (
206
- os .environ ,
207
- PYTHONPATH = setup_requirement_path )
131
+
132
+ setuptools_path = ws .find (
133
+ pkg_resources .Requirement .parse ('setuptools' )).location
134
+
135
+ # Fix sys.path here as easy_install.pth added before PYTHONPATH
136
+ cmd = [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
+
141
+ find_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
+ )
147
+ if find_links :
148
+ cmd .extend (['-f' , find_links ])
208
149
209
150
requirement = 'zc.buildout'
210
- version = options .version
151
+ version = options .buildout_version
211
152
if version is None and not options .accept_buildout_test_releases :
212
153
# Figure out the most recent final version of zc.buildout.
213
154
import setuptools .package_index
214
155
_final_parts = '*final-' , '*final'
215
156
216
157
def _final_version (parsed_version ):
217
- for part in parsed_version :
218
- if (part [:1 ] == '*' ) and (part not in _final_parts ):
219
- return False
220
- return True
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
+
221
167
index = setuptools .package_index .PackageIndex (
222
- search_path = [setup_requirement_path ])
168
+ search_path = [setuptools_path ])
223
169
if find_links :
224
170
index .add_find_links ((find_links ,))
225
171
req = pkg_resources .Requirement .parse (requirement )
@@ -241,22 +187,24 @@ def _final_version(parsed_version):
241
187
requirement = '==' .join ((requirement , version ))
242
188
cmd .append (requirement )
243
189
244
- if is_jython :
245
- import subprocess
246
- exitcode = subprocess .Popen (cmd , env = env ).wait ()
247
- else : # Windows prefers this, apparently; otherwise we would prefer subprocess
248
- exitcode = os .spawnle (* ([os .P_WAIT , sys .executable ] + cmd + [env ]))
249
- if exitcode != 0 :
250
- sys .stdout .flush ()
251
- sys .stderr .flush ()
252
- print ("An error occurred when trying to install zc.buildout. "
253
- "Look above this message for any errors that "
254
- "were output by easy_install." )
255
- sys .exit (exitcode )
256
-
257
- ws .add_entry (eggs_dir )
190
+ import subprocess
191
+ if 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
+
198
+ ws .add_entry (tmpeggs )
258
199
ws .require (requirement )
259
200
import zc .buildout .buildout
201
+
202
+ if 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
206
+ if options .config_file is not None :
207
+ args [0 :0 ] = ['-c' , options .config_file ]
208
+
260
209
zc .buildout .buildout .main (args )
261
- if not options .eggs : # clean up temporary egg directory
262
- shutil .rmtree (eggs_dir )
210
+ shutil .rmtree (tmpeggs )
0 commit comments