]> git.rkrishnan.org Git - tahoe-lafs/zfec.git/blob - zfec/ez_setup.py
f09fd0fcb407bc6bd1f122cb2ebc318ba2b767de
[tahoe-lafs/zfec.git] / zfec / ez_setup.py
1 #!/usr/bin/env 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 os, sys
17 DEFAULT_VERSION = "0.6c12dev"
18 DEFAULT_DIR     = "misc/dependencies/"
19 DEFAULT_URL     = "file:"+DEFAULT_DIR
20
21 md5_data = {
22     'setuptools-0.6c12dev.egg': '770da1c9e5446cf04273f0f1cdb8c09a',
23 }
24
25 import sys, os
26
27 def _validate_md5(egg_name, data):
28     if egg_name in md5_data:
29         from md5 import md5
30         digest = md5(data).hexdigest()
31         if digest != md5_data[egg_name]:
32             print >>sys.stderr, (
33                 "md5 validation of %s failed!  (Possible download problem?)"
34                 % egg_name
35             )
36             sys.exit(2)
37     return data
38
39
40 def use_setuptools(
41     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
42     min_version="0.6c12dev", download_delay=15
43 ):
44     """Automatically find/download setuptools and make it available on sys.path
45
46     `version` should be a valid setuptools version number that is available as
47     an egg for download under the `download_base` URL (which should end with a
48     '/').  `to_dir` is the directory where setuptools will be downloaded, if it
49     is not already available.  If `download_delay` is specified, it is the
50     number of seconds that will be paused before initiating a download, should
51     one be required.  If an older version of setuptools is installed but hasn't
52     been imported yet, this routine will go ahead and install the required
53     version and then use it.  If an older version of setuptools has already been
54     imported then we can't upgrade to the new one, so this routine will print a
55     message to ``sys.stderr`` and raise SystemExit in an attempt to abort the
56     calling script.
57     """
58     if min_version is None:
59         min_version = version
60
61     was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
62     def do_download():
63         egg = download_setuptools(version, download_base, to_dir, download_delay)
64         sys.path.insert(0, egg)
65         import setuptools; setuptools.bootstrap_install_from = egg
66     try:
67         import pkg_resources
68     except ImportError:
69         return do_download()       
70     try:
71         pkg_resources.require("setuptools>="+min_version); return
72     except pkg_resources.VersionConflict, e:
73         if was_imported:
74             print >>sys.stderr, (
75             "The required version of setuptools (>=%s) is not available, and\n"
76             "can't be installed while this script is running. Please install\n"
77             " a more recent version first, using 'easy_install -U setuptools'."
78             "\n\n(Currently using %r)"
79             ) % (min_version, e.args[0])
80             sys.exit(2)
81         else:
82             del pkg_resources, sys.modules['pkg_resources']    # reload ok
83             return do_download()
84     except pkg_resources.DistributionNotFound:
85         return do_download()
86
87 def download_setuptools(
88     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
89     delay = 15
90 ):
91     """Download setuptools from a specified location and return its filename
92
93     `version` should be a valid setuptools version number that is available
94     as an egg for download under the `download_base` URL (which should end
95     with a '/'). `to_dir` is the directory where the egg will be downloaded.
96     `delay` is the number of seconds to pause before an actual download attempt.
97     """
98     import urllib2, shutil
99     egg_name = "setuptools-%s.egg" % (version,)
100     url = download_base + egg_name
101     saveto = os.path.join(to_dir, egg_name)
102     src = dst = None
103     if not os.path.exists(saveto):  # Avoid repeated downloads
104         try:
105             from distutils import log
106             if delay:
107                 log.warn("""
108 ---------------------------------------------------------------------------
109 This script requires setuptools version %s to run (even to display
110 help).  I will attempt to download it for you (from
111 %s), but
112 you may need to enable firewall access for this script first.
113 I will start the download in %d seconds.
114
115 (Note: if this machine does not have network access, please obtain the file
116
117    %s
118
119 and place it in this directory before rerunning this script.)
120 ---------------------------------------------------------------------------""",
121                     version, download_base, delay, url
122                 ); from time import sleep; sleep(delay)
123             log.warn("Downloading %s", url)
124             src = urllib2.urlopen(url)
125             # Read/write all in one block, so we don't create a corrupt file
126             # if the download is interrupted.
127             data = _validate_md5(egg_name, src.read())
128             dst = open(saveto,"wb"); dst.write(data)
129         finally:
130             if src: src.close()
131             if dst: dst.close()
132     return os.path.realpath(saveto)
133
134
135
136
137
138
139
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 def main(argv, version=DEFAULT_VERSION):
170     """Install or upgrade setuptools and EasyInstall"""
171     try:
172         import setuptools
173     except ImportError:
174         egg = None
175         try:
176             egg = download_setuptools(version, delay=0)
177             sys.path.insert(0,egg)
178             from setuptools.command.easy_install import main
179             return main(list(argv)+[egg])   # we're done here
180         finally:
181             if egg and os.path.exists(egg):
182                 os.unlink(egg)
183     else:
184         if setuptools.__version__ == '0.0.1':
185             print >>sys.stderr, (
186             "You have an obsolete version of setuptools installed.  Please\n"
187             "remove it from your system entirely before rerunning this script."
188             )
189             sys.exit(2)
190
191     req = "setuptools>="+version
192     import pkg_resources
193     try:
194         pkg_resources.require(req)
195     except pkg_resources.VersionConflict:
196         try:
197             from setuptools.command.easy_install import main
198         except ImportError:
199             from easy_install import main
200         main(list(argv)+[download_setuptools(delay=0)])
201         sys.exit(0) # try to force an exit
202     else:
203         if argv:
204             from setuptools.command.easy_install import main
205             main(argv)
206         else:
207             print "Setuptools version",version,"or greater has been installed."
208             print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
209
210 def update_md5(filenames):
211     """Update our built-in md5 registry"""
212
213     import re
214     from md5 import md5
215
216     for name in filenames:
217         base = os.path.basename(name)
218         f = open(name,'rb')
219         md5_data[base] = md5(f.read()).hexdigest()
220         f.close()
221
222     data = ["    %r: %r,\n" % it for it in md5_data.items()]
223     data.sort()
224     repl = "".join(data)
225
226     import inspect
227     srcfile = inspect.getsourcefile(sys.modules[__name__])
228     f = open(srcfile, 'rb'); src = f.read(); f.close()
229
230     match = re.search("\nmd5_data = {\n([^}]+)}", src)
231     if not match:
232         print >>sys.stderr, "Internal error!"
233         sys.exit(2)
234
235     src = src[:match.start(1)] + repl + src[match.end(1):]
236     f = open(srcfile,'w')
237     f.write(src)
238     f.close()
239
240
241 if __name__=='__main__':
242     if len(sys.argv)>2 and sys.argv[1]=='--md5update':
243         update_md5(sys.argv[2:])
244     else:
245         main(sys.argv[1:])
246
247
248
249
250