18
18
use the -c option to specify an alternate configuration file.
19
19
"""
20
20
21
- import os
22
- import shutil
23
- import sys
24
- import tempfile
25
-
21
+ import os , shutil , sys , tempfile , urllib , urllib2 , subprocess
26
22
from optparse import OptionParser
27
23
28
- tmpeggs = tempfile .mkdtemp ()
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 )
29
90
30
91
usage = '''\
31
92
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
35
96
Simply run this script in a directory containing a buildout.cfg, using the
36
97
Python that you want bin/buildout to use.
37
98
38
- Note that by using --find-links to point to local resources, you can keep
39
- this script from going over the network.
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.
40
101
'''
41
102
42
103
parser = OptionParser (usage = usage )
43
- parser .add_option ("-v" , "--version" , help = "use a specific zc.buildout version" )
44
-
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." ))
45
124
parser .add_option ("-t" , "--accept-buildout-test-releases" ,
46
125
dest = 'accept_buildout_test_releases' ,
47
126
action = "store_true" , default = False ,
51
130
"extensions for you. If you use this flag, "
52
131
"bootstrap and buildout will get the newest releases "
53
132
"even if they are alphas or betas." ))
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" ))
59
- parser .add_option ("--allow-site-packages" ,
60
- action = "store_true" , default = False ,
61
- help = ("Let bootstrap.py use existing site packages" ))
62
-
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." ))
63
136
64
137
options , args = parser .parse_args ()
65
138
66
- ######################################################################
67
- # load/install setuptools
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
149
+
150
+ if options .accept_buildout_test_releases :
151
+ args .insert (0 , 'buildout:accept-buildout-test-releases=true' )
68
152
69
153
try :
70
- if options . allow_site_packages :
71
- import setuptools
72
- import pkg_resources
73
- from urllib . request import urlopen
154
+ import pkg_resources
155
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
156
+ if not hasattr ( pkg_resources , '_distribute' ):
157
+ raise ImportError
74
158
except ImportError :
75
- from urllib2 import urlopen
76
-
77
- ez = {}
78
- exec (urlopen ('https://bootstrap.pypa.io/ez_setup.py'
79
- ).read (), ez )
80
- if not options .allow_site_packages :
81
- # ez_setup imports site, which adds site packages
82
- # this will remove them from the path to ensure that incompatible versions
83
- # of setuptools are not in the path
84
- import site
85
- # inside a virtualenv, there is no 'getsitepackages'.
86
- # We can't remove these reliably
87
- if hasattr (site , 'getsitepackages' ):
88
- for sitepackage_path in site .getsitepackages ():
89
- sys .path [:] = [x for x in sys .path if sitepackage_path not in x ]
90
-
91
- setup_args = dict (to_dir = tmpeggs , download_delay = 0 )
92
- ez ['use_setuptools' ](** setup_args )
93
- import setuptools
94
- import pkg_resources
95
-
96
- # This does not (always?) update the default working set. We will
97
- # do it.
98
- for path in sys .path :
99
- if path not in pkg_resources .working_set .entries :
100
- pkg_resources .working_set .add_entry (path )
101
-
102
- ######################################################################
103
- # Install buildout
159
+ ez_code = urllib2 .urlopen (
160
+ options .setup_source ).read ().replace ('\r \n ' , '\n ' )
161
+ 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'
170
+ ez ['use_setuptools' ](** setup_args )
171
+ if 'pkg_resources' in sys .modules :
172
+ reload (sys .modules ['pkg_resources' ])
173
+ import pkg_resources
174
+ # This does not (always?) update the default working set. We will
175
+ # do it.
176
+ for path in sys .path :
177
+ if path not in pkg_resources .working_set .entries :
178
+ pkg_resources .working_set .add_entry (path )
104
179
105
- ws = pkg_resources .working_set
180
+ cmd = [quote (sys .executable ),
181
+ '-c' ,
182
+ quote ('from setuptools.command.easy_install import main; main()' ),
183
+ '-mqNxd' ,
184
+ quote (eggs_dir )]
106
185
107
- cmd = [sys .executable , '-c' ,
108
- 'from setuptools.command.easy_install import main; main()' ,
109
- '-mZqNxd' , tmpeggs ]
186
+ if not has_broken_dash_S :
187
+ cmd .insert (1 , '-S' )
110
188
111
- find_links = os .environ .get (
112
- 'bootstrap-testing-find-links' ,
113
- options .find_links or
114
- ('http://downloads.buildout.org/'
115
- if options .accept_buildout_test_releases else None )
116
- )
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/'
117
194
if find_links :
118
- cmd .extend (['-f' , find_links ])
195
+ cmd .extend (['-f' , quote ( find_links ) ])
119
196
120
- setuptools_path = ws .find (
121
- pkg_resources .Requirement .parse ('setuptools' )).location
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 )
122
207
123
208
requirement = 'zc.buildout'
124
209
version = options .version
@@ -133,7 +218,7 @@ def _final_version(parsed_version):
133
218
return False
134
219
return True
135
220
index = setuptools .package_index .PackageIndex (
136
- search_path = [setuptools_path ])
221
+ search_path = [setup_requirement_path ])
137
222
if find_links :
138
223
index .add_find_links ((find_links ,))
139
224
req = pkg_resources .Requirement .parse (requirement )
@@ -142,6 +227,8 @@ def _final_version(parsed_version):
142
227
bestv = None
143
228
for dist in index [req .project_name ]:
144
229
distv = dist .parsed_version
230
+ if distv >= pkg_resources .parse_version ('2dev' ):
231
+ continue
145
232
if _final_version (distv ):
146
233
if bestv is None or distv > bestv :
147
234
best = [dist ]
@@ -151,29 +238,40 @@ def _final_version(parsed_version):
151
238
if best :
152
239
best .sort ()
153
240
version = best [- 1 ].version
241
+
154
242
if version :
155
- requirement = '==' .join ((requirement , version ))
156
- cmd .append (requirement )
243
+ requirement += '==' + version
244
+ else :
245
+ requirement += '<2dev'
157
246
158
- import subprocess
159
- if subprocess .call (cmd , env = dict (os .environ , PYTHONPATH = setuptools_path )) != 0 :
160
- raise Exception (
161
- "Failed to execute command:\n %s" ,
162
- repr (cmd )[1 :- 1 ])
247
+ cmd .append (requirement )
163
248
164
- ######################################################################
165
- # Import and run buildout
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 )
166
261
167
- ws .add_entry (tmpeggs )
262
+ ws .add_entry (eggs_dir )
168
263
ws .require (requirement )
169
264
import zc .buildout .buildout
170
265
266
+ # If there isn't already a command in the args, add bootstrap
171
267
if not [a for a in args if '=' not in a ]:
172
268
args .append ('bootstrap' )
173
269
174
- # if -c was provided, we push it back into args for buildout' main function
270
+
271
+ # if -c was provided, we push it back into args for buildout's main function
175
272
if options .config_file is not None :
176
273
args [0 :0 ] = ['-c' , options .config_file ]
177
274
178
275
zc .buildout .buildout .main (args )
179
- shutil .rmtree (tmpeggs )
276
+ if not options .eggs : # clean up temporary egg directory
277
+ shutil .rmtree (eggs_dir )
0 commit comments