Version 1.3.1dev.
[librarian.git] / ez_setup.py
1 #!python
2 """Bootstrap setuptools installation
3
4 If you want to use setuptools in your package's setup.py, just include this
5 file 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
10 If you want to require a specific version of setuptools, set a download
11 mirror, or use an alternate download directory, you can do so by supplying
12 the appropriate options to ``use_setuptools()``.
13
14 This file can also be run as a script to install or upgrade setuptools.
15 """
16 import sys
17 DEFAULT_VERSION = "0.6c9"
18 DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
19
20 md5_data = {
21     'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
22     'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
23     'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
24     'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
25     'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
26     'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
27     'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
28     'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
29     'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
30     'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
31     'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
32     'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
33     'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
34     'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
35     'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
36     'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
37     'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
38     'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
39     'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
40     'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
41     'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
42     'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
43     'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
44     'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
45     'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
46     'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
47     'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
48     'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
49     'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
50     'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
51     'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
52     'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
53     'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
54     'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
55 }
56
57 import sys, os
58 try: from hashlib import md5
59 except ImportError: from md5 import md5
60
61 def _validate_md5(egg_name, data):
62     if egg_name in md5_data:
63         digest = md5(data).hexdigest()
64         if digest != md5_data[egg_name]:
65             print >>sys.stderr, (
66                 "md5 validation of %s failed!  (Possible download problem?)"
67                 % egg_name
68             )
69             sys.exit(2)
70     return data
71
72 def use_setuptools(
73     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
74     download_delay=15
75 ):
76     """Automatically find/download setuptools and make it available on sys.path
77
78     `version` should be a valid setuptools version number that is available
79     as an egg for download under the `download_base` URL (which should end with
80     a '/').  `to_dir` is the directory where setuptools will be downloaded, if
81     it is not already available.  If `download_delay` is specified, it should
82     be the number of seconds that will be paused before initiating a download,
83     should one be required.  If an older version of setuptools is installed,
84     this routine will print a message to ``sys.stderr`` and raise SystemExit in
85     an attempt to abort the calling script.
86     """
87     was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
88     def do_download():
89         egg = download_setuptools(version, download_base, to_dir, download_delay)
90         sys.path.insert(0, egg)
91         import setuptools; setuptools.bootstrap_install_from = egg
92     try:
93         import pkg_resources
94     except ImportError:
95         return do_download()       
96     try:
97         pkg_resources.require("setuptools>="+version); return
98     except pkg_resources.VersionConflict, e:
99         if was_imported:
100             print >>sys.stderr, (
101             "The required version of setuptools (>=%s) is not available, and\n"
102             "can't be installed while this script is running. Please install\n"
103             " a more recent version first, using 'easy_install -U setuptools'."
104             "\n\n(Currently using %r)"
105             ) % (version, e.args[0])
106             sys.exit(2)
107         else:
108             del pkg_resources, sys.modules['pkg_resources']    # reload ok
109             return do_download()
110     except pkg_resources.DistributionNotFound:
111         return do_download()
112
113 def download_setuptools(
114     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
115     delay = 15
116 ):
117     """Download setuptools from a specified location and return its filename
118
119     `version` should be a valid setuptools version number that is available
120     as an egg for download under the `download_base` URL (which should end
121     with a '/'). `to_dir` is the directory where the egg will be downloaded.
122     `delay` is the number of seconds to pause before an actual download attempt.
123     """
124     import urllib2, shutil
125     egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
126     url = download_base + egg_name
127     saveto = os.path.join(to_dir, egg_name)
128     src = dst = None
129     if not os.path.exists(saveto):  # Avoid repeated downloads
130         try:
131             from distutils import log
132             if delay:
133                 log.warn("""
134 ---------------------------------------------------------------------------
135 This script requires setuptools version %s to run (even to display
136 help).  I will attempt to download it for you (from
137 %s), but
138 you may need to enable firewall access for this script first.
139 I will start the download in %d seconds.
140
141 (Note: if this machine does not have network access, please obtain the file
142
143    %s
144
145 and place it in this directory before rerunning this script.)
146 ---------------------------------------------------------------------------""",
147                     version, download_base, delay, url
148                 ); from time import sleep; sleep(delay)
149             log.warn("Downloading %s", url)
150             src = urllib2.urlopen(url)
151             # Read/write all in one block, so we don't create a corrupt file
152             # if the download is interrupted.
153             data = _validate_md5(egg_name, src.read())
154             dst = open(saveto,"wb"); dst.write(data)
155         finally:
156             if src: src.close()
157             if dst: dst.close()
158     return os.path.realpath(saveto)
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
191
192
193
194
195 def main(argv, version=DEFAULT_VERSION):
196     """Install or upgrade setuptools and EasyInstall"""
197     try:
198         import setuptools
199     except ImportError:
200         egg = None
201         try:
202             egg = download_setuptools(version, delay=0)
203             sys.path.insert(0,egg)
204             from setuptools.command.easy_install import main
205             return main(list(argv)+[egg])   # we're done here
206         finally:
207             if egg and os.path.exists(egg):
208                 os.unlink(egg)
209     else:
210         if setuptools.__version__ == '0.0.1':
211             print >>sys.stderr, (
212             "You have an obsolete version of setuptools installed.  Please\n"
213             "remove it from your system entirely before rerunning this script."
214             )
215             sys.exit(2)
216
217     req = "setuptools>="+version
218     import pkg_resources
219     try:
220         pkg_resources.require(req)
221     except pkg_resources.VersionConflict:
222         try:
223             from setuptools.command.easy_install import main
224         except ImportError:
225             from easy_install import main
226         main(list(argv)+[download_setuptools(delay=0)])
227         sys.exit(0) # try to force an exit
228     else:
229         if argv:
230             from setuptools.command.easy_install import main
231             main(argv)
232         else:
233             print "Setuptools version",version,"or greater has been installed."
234             print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
235
236 def update_md5(filenames):
237     """Update our built-in md5 registry"""
238
239     import re
240
241     for name in filenames:
242         base = os.path.basename(name)
243         f = open(name,'rb')
244         md5_data[base] = md5(f.read()).hexdigest()
245         f.close()
246
247     data = ["    %r: %r,\n" % it for it in md5_data.items()]
248     data.sort()
249     repl = "".join(data)
250
251     import inspect
252     srcfile = inspect.getsourcefile(sys.modules[__name__])
253     f = open(srcfile, 'rb'); src = f.read(); f.close()
254
255     match = re.search("\nmd5_data = {\n([^}]+)}", src)
256     if not match:
257         print >>sys.stderr, "Internal error!"
258         sys.exit(2)
259
260     src = src[:match.start(1)] + repl + src[match.end(1):]
261     f = open(srcfile,'w')
262     f.write(src)
263     f.close()
264
265
266 if __name__=='__main__':
267     if len(sys.argv)>2 and sys.argv[1]=='--md5update':
268         update_md5(sys.argv[2:])
269     else:
270         main(sys.argv[1:])
271
272
273
274
275