1#!/usr/bin/env python
2#
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
17"""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
94    except pkg_resources.VersionConflict as e:
95        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:])
267