blob: 18bd16c0c90115f6943ebdd44ffd3c1b7d655aef [file] [log] [blame]
Craig Citro903c5d42013-10-23 11:01:29 -07001#!/usr/bin/env python
Arthur D. Cherba471ac702015-10-24 07:54:38 -07002#
3# Copyright 2015 Google Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Craig Citro903c5d42013-10-23 11:01:29 -070017"""Bootstrap setuptools installation
18
19If you want to use setuptools in your package's setup.py, just include this
20file in the same directory with it, and add this to the top of your setup.py::
21
22 from ez_setup import use_setuptools
23 use_setuptools()
24
25If you want to require a specific version of setuptools, set a download
26mirror, or use an alternate download directory, you can do so by supplying
27the appropriate options to ``use_setuptools()``.
28
29This file can also be run as a script to install or upgrade setuptools.
30"""
31import sys
32DEFAULT_VERSION = "0.6c11"
33DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
34
35md5_data = {
36 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
37 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
38 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
39 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
40 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
41 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
42 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
43 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
44 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
45 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
46 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
47 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
48 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
49 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
50 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
51}
52
53import sys, os
54try: from hashlib import md5
55except ImportError: from md5 import md5
56
57def _validate_md5(egg_name, data):
58 if egg_name in md5_data:
59 digest = md5(data).hexdigest()
60 if digest != md5_data[egg_name]:
61 print >>sys.stderr, (
62 "md5 validation of %s failed! (Possible download problem?)"
63 % egg_name
64 )
65 sys.exit(2)
66 return data
67
68def use_setuptools(
69 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
70 download_delay=15
71):
72 """Automatically find/download setuptools and make it available on sys.path
73
74 `version` should be a valid setuptools version number that is available
75 as an egg for download under the `download_base` URL (which should end with
76 a '/'). `to_dir` is the directory where setuptools will be downloaded, if
77 it is not already available. If `download_delay` is specified, it should
78 be the number of seconds that will be paused before initiating a download,
79 should one be required. If an older version of setuptools is installed,
80 this routine will print a message to ``sys.stderr`` and raise SystemExit in
81 an attempt to abort the calling script.
82 """
83 was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
84 def do_download():
85 egg = download_setuptools(version, download_base, to_dir, download_delay)
86 sys.path.insert(0, egg)
87 import setuptools; setuptools.bootstrap_install_from = egg
88 try:
89 import pkg_resources
90 except ImportError:
91 return do_download()
92 try:
93 pkg_resources.require("setuptools>="+version); return
cclauss63603e72018-06-13 17:47:55 +020094 except pkg_resources.VersionConflict as e:
Craig Citro903c5d42013-10-23 11:01:29 -070095 if was_imported:
96 print >>sys.stderr, (
97 "The required version of setuptools (>=%s) is not available, and\n"
98 "can't be installed while this script is running. Please install\n"
99 " a more recent version first, using 'easy_install -U setuptools'."
100 "\n\n(Currently using %r)"
101 ) % (version, e.args[0])
102 sys.exit(2)
103 except pkg_resources.DistributionNotFound:
104 pass
105
106 del pkg_resources, sys.modules['pkg_resources'] # reload ok
107 return do_download()
108
109def download_setuptools(
110 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
111 delay = 15
112):
113 """Download setuptools from a specified location and return its filename
114
115 `version` should be a valid setuptools version number that is available
116 as an egg for download under the `download_base` URL (which should end
117 with a '/'). `to_dir` is the directory where the egg will be downloaded.
118 `delay` is the number of seconds to pause before an actual download attempt.
119 """
120 import urllib2, shutil
121 egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
122 url = download_base + egg_name
123 saveto = os.path.join(to_dir, egg_name)
124 src = dst = None
125 if not os.path.exists(saveto): # Avoid repeated downloads
126 try:
127 from distutils import log
128 if delay:
129 log.warn("""
130---------------------------------------------------------------------------
131This script requires setuptools version %s to run (even to display
132help). I will attempt to download it for you (from
133%s), but
134you may need to enable firewall access for this script first.
135I will start the download in %d seconds.
136
137(Note: if this machine does not have network access, please obtain the file
138
139 %s
140
141and place it in this directory before rerunning this script.)
142---------------------------------------------------------------------------""",
143 version, download_base, delay, url
144 ); from time import sleep; sleep(delay)
145 log.warn("Downloading %s", url)
146 src = urllib2.urlopen(url)
147 # Read/write all in one block, so we don't create a corrupt file
148 # if the download is interrupted.
149 data = _validate_md5(egg_name, src.read())
150 dst = open(saveto,"wb"); dst.write(data)
151 finally:
152 if src: src.close()
153 if dst: dst.close()
154 return os.path.realpath(saveto)
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191def main(argv, version=DEFAULT_VERSION):
192 """Install or upgrade setuptools and EasyInstall"""
193 try:
194 import setuptools
195 except ImportError:
196 egg = None
197 try:
198 egg = download_setuptools(version, delay=0)
199 sys.path.insert(0,egg)
200 from setuptools.command.easy_install import main
201 return main(list(argv)+[egg]) # we're done here
202 finally:
203 if egg and os.path.exists(egg):
204 os.unlink(egg)
205 else:
206 if setuptools.__version__ == '0.0.1':
207 print >>sys.stderr, (
208 "You have an obsolete version of setuptools installed. Please\n"
209 "remove it from your system entirely before rerunning this script."
210 )
211 sys.exit(2)
212
213 req = "setuptools>="+version
214 import pkg_resources
215 try:
216 pkg_resources.require(req)
217 except pkg_resources.VersionConflict:
218 try:
219 from setuptools.command.easy_install import main
220 except ImportError:
221 from easy_install import main
222 main(list(argv)+[download_setuptools(delay=0)])
223 sys.exit(0) # try to force an exit
224 else:
225 if argv:
226 from setuptools.command.easy_install import main
227 main(argv)
228 else:
229 print "Setuptools version",version,"or greater has been installed."
230 print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
231
232def update_md5(filenames):
233 """Update our built-in md5 registry"""
234
235 import re
236
237 for name in filenames:
238 base = os.path.basename(name)
239 f = open(name,'rb')
240 md5_data[base] = md5(f.read()).hexdigest()
241 f.close()
242
243 data = [" %r: %r,\n" % it for it in md5_data.items()]
244 data.sort()
245 repl = "".join(data)
246
247 import inspect
248 srcfile = inspect.getsourcefile(sys.modules[__name__])
249 f = open(srcfile, 'rb'); src = f.read(); f.close()
250
251 match = re.search("\nmd5_data = {\n([^}]+)}", src)
252 if not match:
253 print >>sys.stderr, "Internal error!"
254 sys.exit(2)
255
256 src = src[:match.start(1)] + repl + src[match.end(1):]
257 f = open(srcfile,'w')
258 f.write(src)
259 f.close()
260
261
262if __name__=='__main__':
263 if len(sys.argv)>2 and sys.argv[1]=='--md5update':
264 update_md5(sys.argv[2:])
265 else:
266 main(sys.argv[1:])