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