fc70661 by Jon Rosebaugh at 2009-01-28 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
}
55
56
import sys, os
57
try: from hashlib import md5
58
except ImportError: from md5 import md5
59
60
def _validate_md5(egg_name, data):
61
    if egg_name in md5_data:
62
        digest = md5(data).hexdigest()
63
        if digest != md5_data[egg_name]:
64
            print >>sys.stderr, (
65
                "md5 validation of %s failed!  (Possible download problem?)"
66
                % egg_name
67
            )
68
            sys.exit(2)
69
    return data
70
71
def use_setuptools(
72
    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
73
    download_delay=15
74
):
75
    """Automatically find/download setuptools and make it available on sys.path
76
77
    `version` should be a valid setuptools version number that is available
78
    as an egg for download under the `download_base` URL (which should end with
79
    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
80
    it is not already available.  If `download_delay` is specified, it should
81
    be the number of seconds that will be paused before initiating a download,
82
    should one be required.  If an older version of setuptools is installed,
83
    this routine will print a message to ``sys.stderr`` and raise SystemExit in
84
    an attempt to abort the calling script.
85
    """
86
    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
87
    def do_download():
88
        egg = download_setuptools(version, download_base, to_dir, download_delay)
89
        sys.path.insert(0, egg)
90
        import setuptools; setuptools.bootstrap_install_from = egg
91
    try:
92
        import pkg_resources
93
    except ImportError:
94
        return do_download()       
95
    try:
96
        pkg_resources.require("setuptools>="+version); return
97
    except pkg_resources.VersionConflict, e:
98
        if was_imported:
99
            print >>sys.stderr, (
100
            "The required version of setuptools (>=%s) is not available, and\n"
101
            "can't be installed while this script is running. Please install\n"
102
            " a more recent version first, using 'easy_install -U setuptools'."
103
            "\n\n(Currently using %r)"
104
            ) % (version, e.args[0])
105
            sys.exit(2)
106
        else:
107
            del pkg_resources, sys.modules['pkg_resources']    # reload ok
108
            return do_download()
109
    except pkg_resources.DistributionNotFound:
110
        return do_download()
111
112
def download_setuptools(
113
    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
114
    delay = 15
115
):
116
    """Download setuptools from a specified location and return its filename
117
118
    `version` should be a valid setuptools version number that is available
119
    as an egg for download under the `download_base` URL (which should end
120
    with a '/'). `to_dir` is the directory where the egg will be downloaded.
121
    `delay` is the number of seconds to pause before an actual download attempt.
122
    """
123
    import urllib2, shutil
124
    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
125
    url = download_base + egg_name
126
    saveto = os.path.join(to_dir, egg_name)
127
    src = dst = None
128
    if not os.path.exists(saveto):  # Avoid repeated downloads
129
        try:
130
            from distutils import log
131
            if delay:
132
                log.warn("""
133
---------------------------------------------------------------------------
134
This script requires setuptools version %s to run (even to display
135
help).  I will attempt to download it for you (from
136
%s), but
137
you may need to enable firewall access for this script first.
138
I will start the download in %d seconds.
139
140
(Note: if this machine does not have network access, please obtain the file
141
142
   %s
143
144
and place it in this directory before rerunning this script.)
145
---------------------------------------------------------------------------""",
146
                    version, download_base, delay, url
147
                ); from time import sleep; sleep(delay)
148
            log.warn("Downloading %s", url)
149
            src = urllib2.urlopen(url)
150
            # Read/write all in one block, so we don't create a corrupt file
151
            # if the download is interrupted.
152
            data = _validate_md5(egg_name, src.read())
153
            dst = open(saveto,"wb"); dst.write(data)
154
        finally:
155
            if src: src.close()
156
            if dst: dst.close()
157
    return os.path.realpath(saveto)
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
191
192
193
194
def main(argv, version=DEFAULT_VERSION):
195
    """Install or upgrade setuptools and EasyInstall"""
196
    try:
197
        import setuptools
198
    except ImportError:
199
        egg = None
200
        try:
201
            egg = download_setuptools(version, delay=0)
202
            sys.path.insert(0,egg)
203
            from setuptools.command.easy_install import main
204
            return main(list(argv)+[egg])   # we're done here
205
        finally:
206
            if egg and os.path.exists(egg):
207
                os.unlink(egg)
208
    else:
209
        if setuptools.__version__ == '0.0.1':
210
            print >>sys.stderr, (
211
            "You have an obsolete version of setuptools installed.  Please\n"
212
            "remove it from your system entirely before rerunning this script."
213
            )
214
            sys.exit(2)
215
216
    req = "setuptools>="+version
217
    import pkg_resources
218
    try:
219
        pkg_resources.require(req)
220
    except pkg_resources.VersionConflict:
221
        try:
222
            from setuptools.command.easy_install import main
223
        except ImportError:
224
            from easy_install import main
225
        main(list(argv)+[download_setuptools(delay=0)])
226
        sys.exit(0) # try to force an exit
227
    else:
228
        if argv:
229
            from setuptools.command.easy_install import main
230
            main(argv)
231
        else:
232
            print "Setuptools version",version,"or greater has been installed."
233
            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
234
235
def update_md5(filenames):
236
    """Update our built-in md5 registry"""
237
238
    import re
239
240
    for name in filenames:
241
        base = os.path.basename(name)
242
        f = open(name,'rb')
243
        md5_data[base] = md5(f.read()).hexdigest()
244
        f.close()
245
246
    data = ["    %r: %r,\n" % it for it in md5_data.items()]
247
    data.sort()
248
    repl = "".join(data)
249
250
    import inspect
251
    srcfile = inspect.getsourcefile(sys.modules[__name__])
252
    f = open(srcfile, 'rb'); src = f.read(); f.close()
253
254
    match = re.search("\nmd5_data = {\n([^}]+)}", src)
255
    if not match:
256
        print >>sys.stderr, "Internal error!"
257
        sys.exit(2)
258
259
    src = src[:match.start(1)] + repl + src[match.end(1):]
260
    f = open(srcfile,'w')
261
    f.write(src)
262
    f.close()
263
264
265
if __name__=='__main__':
266
    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
267
        update_md5(sys.argv[2:])
268
    else:
269
        main(sys.argv[1:])
270
271
272
273
274
275