Statistics
| Branch: | Tag: | Revision:

root / distribute_setup.py @ master

History | View | Annotate | Download (16.9 kB)

1 52271184 Kostas Papadimitriou
# Copyright 2012 GRNET S.A. All rights reserved.
2 52271184 Kostas Papadimitriou
#
3 52271184 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 52271184 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 52271184 Kostas Papadimitriou
# conditions are met:
6 52271184 Kostas Papadimitriou
#
7 52271184 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 52271184 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 52271184 Kostas Papadimitriou
#      disclaimer.
10 52271184 Kostas Papadimitriou
#
11 52271184 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 52271184 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 52271184 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 52271184 Kostas Papadimitriou
#      provided with the distribution.
15 52271184 Kostas Papadimitriou
#
16 52271184 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 52271184 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 52271184 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 52271184 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 52271184 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 52271184 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 52271184 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 52271184 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 52271184 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 52271184 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 52271184 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 52271184 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 52271184 Kostas Papadimitriou
#
29 52271184 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 52271184 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 52271184 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 52271184 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 52271184 Kostas Papadimitriou
34 52271184 Kostas Papadimitriou
35 872ca586 Kostas Papadimitriou
#!python
36 872ca586 Kostas Papadimitriou
"""Bootstrap distribute installation
37 872ca586 Kostas Papadimitriou

38 872ca586 Kostas Papadimitriou
If you want to use setuptools in your package's setup.py, just include this
39 872ca586 Kostas Papadimitriou
file in the same directory with it, and add this to the top of your setup.py::
40 872ca586 Kostas Papadimitriou

41 872ca586 Kostas Papadimitriou
    from distribute_setup import use_setuptools
42 872ca586 Kostas Papadimitriou
    use_setuptools()
43 872ca586 Kostas Papadimitriou

44 872ca586 Kostas Papadimitriou
If you want to require a specific version of setuptools, set a download
45 872ca586 Kostas Papadimitriou
mirror, or use an alternate download directory, you can do so by supplying
46 872ca586 Kostas Papadimitriou
the appropriate options to ``use_setuptools()``.
47 872ca586 Kostas Papadimitriou

48 872ca586 Kostas Papadimitriou
This file can also be run as a script to install or upgrade setuptools.
49 872ca586 Kostas Papadimitriou
"""
50 872ca586 Kostas Papadimitriou
import os
51 872ca586 Kostas Papadimitriou
import sys
52 872ca586 Kostas Papadimitriou
import time
53 872ca586 Kostas Papadimitriou
import fnmatch
54 872ca586 Kostas Papadimitriou
import tempfile
55 872ca586 Kostas Papadimitriou
import tarfile
56 872ca586 Kostas Papadimitriou
from distutils import log
57 872ca586 Kostas Papadimitriou
58 872ca586 Kostas Papadimitriou
try:
59 872ca586 Kostas Papadimitriou
    from site import USER_SITE
60 872ca586 Kostas Papadimitriou
except ImportError:
61 872ca586 Kostas Papadimitriou
    USER_SITE = None
62 872ca586 Kostas Papadimitriou
63 872ca586 Kostas Papadimitriou
try:
64 872ca586 Kostas Papadimitriou
    import subprocess
65 872ca586 Kostas Papadimitriou
66 872ca586 Kostas Papadimitriou
    def _python_cmd(*args):
67 872ca586 Kostas Papadimitriou
        args = (sys.executable,) + args
68 872ca586 Kostas Papadimitriou
        return subprocess.call(args) == 0
69 872ca586 Kostas Papadimitriou
70 872ca586 Kostas Papadimitriou
except ImportError:
71 872ca586 Kostas Papadimitriou
    # will be used for python 2.3
72 872ca586 Kostas Papadimitriou
    def _python_cmd(*args):
73 872ca586 Kostas Papadimitriou
        args = (sys.executable,) + args
74 872ca586 Kostas Papadimitriou
        # quoting arguments if windows
75 872ca586 Kostas Papadimitriou
        if sys.platform == 'win32':
76 872ca586 Kostas Papadimitriou
            def quote(arg):
77 872ca586 Kostas Papadimitriou
                if ' ' in arg:
78 872ca586 Kostas Papadimitriou
                    return '"%s"' % arg
79 872ca586 Kostas Papadimitriou
                return arg
80 872ca586 Kostas Papadimitriou
            args = [quote(arg) for arg in args]
81 872ca586 Kostas Papadimitriou
        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
82 872ca586 Kostas Papadimitriou
83 872ca586 Kostas Papadimitriou
DEFAULT_VERSION = "0.6.10"
84 872ca586 Kostas Papadimitriou
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
85 872ca586 Kostas Papadimitriou
SETUPTOOLS_FAKED_VERSION = "0.6c11"
86 872ca586 Kostas Papadimitriou
87 872ca586 Kostas Papadimitriou
SETUPTOOLS_PKG_INFO = """\
88 872ca586 Kostas Papadimitriou
Metadata-Version: 1.0
89 872ca586 Kostas Papadimitriou
Name: setuptools
90 872ca586 Kostas Papadimitriou
Version: %s
91 872ca586 Kostas Papadimitriou
Summary: xxxx
92 872ca586 Kostas Papadimitriou
Home-page: xxx
93 872ca586 Kostas Papadimitriou
Author: xxx
94 872ca586 Kostas Papadimitriou
Author-email: xxx
95 872ca586 Kostas Papadimitriou
License: xxx
96 872ca586 Kostas Papadimitriou
Description: xxx
97 872ca586 Kostas Papadimitriou
""" % SETUPTOOLS_FAKED_VERSION
98 872ca586 Kostas Papadimitriou
99 872ca586 Kostas Papadimitriou
100 872ca586 Kostas Papadimitriou
def _install(tarball):
101 872ca586 Kostas Papadimitriou
    # extracting the tarball
102 872ca586 Kostas Papadimitriou
    tmpdir = tempfile.mkdtemp()
103 872ca586 Kostas Papadimitriou
    log.warn('Extracting in %s', tmpdir)
104 872ca586 Kostas Papadimitriou
    old_wd = os.getcwd()
105 872ca586 Kostas Papadimitriou
    try:
106 872ca586 Kostas Papadimitriou
        os.chdir(tmpdir)
107 872ca586 Kostas Papadimitriou
        tar = tarfile.open(tarball)
108 872ca586 Kostas Papadimitriou
        _extractall(tar)
109 872ca586 Kostas Papadimitriou
        tar.close()
110 872ca586 Kostas Papadimitriou
111 872ca586 Kostas Papadimitriou
        # going in the directory
112 872ca586 Kostas Papadimitriou
        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
113 872ca586 Kostas Papadimitriou
        os.chdir(subdir)
114 872ca586 Kostas Papadimitriou
        log.warn('Now working in %s', subdir)
115 872ca586 Kostas Papadimitriou
116 872ca586 Kostas Papadimitriou
        # installing
117 872ca586 Kostas Papadimitriou
        log.warn('Installing Distribute')
118 872ca586 Kostas Papadimitriou
        if not _python_cmd('setup.py', 'install'):
119 872ca586 Kostas Papadimitriou
            log.warn('Something went wrong during the installation.')
120 872ca586 Kostas Papadimitriou
            log.warn('See the error message above.')
121 872ca586 Kostas Papadimitriou
    finally:
122 872ca586 Kostas Papadimitriou
        os.chdir(old_wd)
123 872ca586 Kostas Papadimitriou
124 872ca586 Kostas Papadimitriou
125 872ca586 Kostas Papadimitriou
def _build_egg(egg, tarball, to_dir):
126 872ca586 Kostas Papadimitriou
    # extracting the tarball
127 872ca586 Kostas Papadimitriou
    tmpdir = tempfile.mkdtemp()
128 872ca586 Kostas Papadimitriou
    log.warn('Extracting in %s', tmpdir)
129 872ca586 Kostas Papadimitriou
    old_wd = os.getcwd()
130 872ca586 Kostas Papadimitriou
    try:
131 872ca586 Kostas Papadimitriou
        os.chdir(tmpdir)
132 872ca586 Kostas Papadimitriou
        tar = tarfile.open(tarball)
133 872ca586 Kostas Papadimitriou
        _extractall(tar)
134 872ca586 Kostas Papadimitriou
        tar.close()
135 872ca586 Kostas Papadimitriou
136 872ca586 Kostas Papadimitriou
        # going in the directory
137 872ca586 Kostas Papadimitriou
        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
138 872ca586 Kostas Papadimitriou
        os.chdir(subdir)
139 872ca586 Kostas Papadimitriou
        log.warn('Now working in %s', subdir)
140 872ca586 Kostas Papadimitriou
141 872ca586 Kostas Papadimitriou
        # building an egg
142 872ca586 Kostas Papadimitriou
        log.warn('Building a Distribute egg in %s', to_dir)
143 872ca586 Kostas Papadimitriou
        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
144 872ca586 Kostas Papadimitriou
145 872ca586 Kostas Papadimitriou
    finally:
146 872ca586 Kostas Papadimitriou
        os.chdir(old_wd)
147 872ca586 Kostas Papadimitriou
    # returning the result
148 872ca586 Kostas Papadimitriou
    log.warn(egg)
149 872ca586 Kostas Papadimitriou
    if not os.path.exists(egg):
150 872ca586 Kostas Papadimitriou
        raise IOError('Could not build the egg.')
151 872ca586 Kostas Papadimitriou
152 872ca586 Kostas Papadimitriou
153 872ca586 Kostas Papadimitriou
def _do_download(version, download_base, to_dir, download_delay):
154 872ca586 Kostas Papadimitriou
    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
155 872ca586 Kostas Papadimitriou
                       % (version, sys.version_info[0], sys.version_info[1]))
156 872ca586 Kostas Papadimitriou
    if not os.path.exists(egg):
157 872ca586 Kostas Papadimitriou
        tarball = download_setuptools(version, download_base,
158 872ca586 Kostas Papadimitriou
                                      to_dir, download_delay)
159 872ca586 Kostas Papadimitriou
        _build_egg(egg, tarball, to_dir)
160 872ca586 Kostas Papadimitriou
    sys.path.insert(0, egg)
161 872ca586 Kostas Papadimitriou
    import setuptools
162 872ca586 Kostas Papadimitriou
    setuptools.bootstrap_install_from = egg
163 872ca586 Kostas Papadimitriou
164 872ca586 Kostas Papadimitriou
165 872ca586 Kostas Papadimitriou
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
166 872ca586 Kostas Papadimitriou
                   to_dir=os.curdir, download_delay=15, no_fake=True):
167 872ca586 Kostas Papadimitriou
    # making sure we use the absolute path
168 872ca586 Kostas Papadimitriou
    to_dir = os.path.abspath(to_dir)
169 872ca586 Kostas Papadimitriou
    was_imported = 'pkg_resources' in sys.modules or \
170 872ca586 Kostas Papadimitriou
        'setuptools' in sys.modules
171 872ca586 Kostas Papadimitriou
    try:
172 872ca586 Kostas Papadimitriou
        try:
173 872ca586 Kostas Papadimitriou
            import pkg_resources
174 872ca586 Kostas Papadimitriou
            if not hasattr(pkg_resources, '_distribute'):
175 872ca586 Kostas Papadimitriou
                if not no_fake:
176 872ca586 Kostas Papadimitriou
                    _fake_setuptools()
177 872ca586 Kostas Papadimitriou
                raise ImportError
178 872ca586 Kostas Papadimitriou
        except ImportError:
179 872ca586 Kostas Papadimitriou
            return _do_download(version, download_base, to_dir, download_delay)
180 872ca586 Kostas Papadimitriou
        try:
181 872ca586 Kostas Papadimitriou
            pkg_resources.require("distribute>="+version)
182 872ca586 Kostas Papadimitriou
            return
183 872ca586 Kostas Papadimitriou
        except pkg_resources.VersionConflict:
184 872ca586 Kostas Papadimitriou
            e = sys.exc_info()[1]
185 872ca586 Kostas Papadimitriou
            if was_imported:
186 872ca586 Kostas Papadimitriou
                sys.stderr.write(
187 872ca586 Kostas Papadimitriou
                "The required version of distribute (>=%s) is not available,\n"
188 872ca586 Kostas Papadimitriou
                "and can't be installed while this script is running. Please\n"
189 872ca586 Kostas Papadimitriou
                "install a more recent version first, using\n"
190 872ca586 Kostas Papadimitriou
                "'easy_install -U distribute'."
191 872ca586 Kostas Papadimitriou
                "\n\n(Currently using %r)\n" % (version, e.args[0]))
192 872ca586 Kostas Papadimitriou
                sys.exit(2)
193 872ca586 Kostas Papadimitriou
            else:
194 872ca586 Kostas Papadimitriou
                del pkg_resources, sys.modules['pkg_resources']    # reload ok
195 872ca586 Kostas Papadimitriou
                return _do_download(version, download_base, to_dir,
196 872ca586 Kostas Papadimitriou
                                    download_delay)
197 872ca586 Kostas Papadimitriou
        except pkg_resources.DistributionNotFound:
198 872ca586 Kostas Papadimitriou
            return _do_download(version, download_base, to_dir,
199 872ca586 Kostas Papadimitriou
                                download_delay)
200 872ca586 Kostas Papadimitriou
    finally:
201 872ca586 Kostas Papadimitriou
        if not no_fake:
202 872ca586 Kostas Papadimitriou
            _create_fake_setuptools_pkg_info(to_dir)
203 872ca586 Kostas Papadimitriou
204 872ca586 Kostas Papadimitriou
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
205 872ca586 Kostas Papadimitriou
                        to_dir=os.curdir, delay=15):
206 872ca586 Kostas Papadimitriou
    """Download distribute from a specified location and return its filename
207 872ca586 Kostas Papadimitriou

208 872ca586 Kostas Papadimitriou
    `version` should be a valid distribute version number that is available
209 872ca586 Kostas Papadimitriou
    as an egg for download under the `download_base` URL (which should end
210 872ca586 Kostas Papadimitriou
    with a '/'). `to_dir` is the directory where the egg will be downloaded.
211 872ca586 Kostas Papadimitriou
    `delay` is the number of seconds to pause before an actual download
212 872ca586 Kostas Papadimitriou
    attempt.
213 872ca586 Kostas Papadimitriou
    """
214 872ca586 Kostas Papadimitriou
    # making sure we use the absolute path
215 872ca586 Kostas Papadimitriou
    to_dir = os.path.abspath(to_dir)
216 872ca586 Kostas Papadimitriou
    try:
217 872ca586 Kostas Papadimitriou
        from urllib.request import urlopen
218 872ca586 Kostas Papadimitriou
    except ImportError:
219 872ca586 Kostas Papadimitriou
        from urllib2 import urlopen
220 872ca586 Kostas Papadimitriou
    tgz_name = "distribute-%s.tar.gz" % version
221 872ca586 Kostas Papadimitriou
    url = download_base + tgz_name
222 872ca586 Kostas Papadimitriou
    saveto = os.path.join(to_dir, tgz_name)
223 872ca586 Kostas Papadimitriou
    src = dst = None
224 872ca586 Kostas Papadimitriou
    if not os.path.exists(saveto):  # Avoid repeated downloads
225 872ca586 Kostas Papadimitriou
        try:
226 872ca586 Kostas Papadimitriou
            log.warn("Downloading %s", url)
227 872ca586 Kostas Papadimitriou
            src = urlopen(url)
228 872ca586 Kostas Papadimitriou
            # Read/write all in one block, so we don't create a corrupt file
229 872ca586 Kostas Papadimitriou
            # if the download is interrupted.
230 872ca586 Kostas Papadimitriou
            data = src.read()
231 872ca586 Kostas Papadimitriou
            dst = open(saveto, "wb")
232 872ca586 Kostas Papadimitriou
            dst.write(data)
233 872ca586 Kostas Papadimitriou
        finally:
234 872ca586 Kostas Papadimitriou
            if src:
235 872ca586 Kostas Papadimitriou
                src.close()
236 872ca586 Kostas Papadimitriou
            if dst:
237 872ca586 Kostas Papadimitriou
                dst.close()
238 872ca586 Kostas Papadimitriou
    return os.path.realpath(saveto)
239 872ca586 Kostas Papadimitriou
240 872ca586 Kostas Papadimitriou
def _no_sandbox(function):
241 872ca586 Kostas Papadimitriou
    def __no_sandbox(*args, **kw):
242 872ca586 Kostas Papadimitriou
        try:
243 872ca586 Kostas Papadimitriou
            from setuptools.sandbox import DirectorySandbox
244 872ca586 Kostas Papadimitriou
            if not hasattr(DirectorySandbox, '_old'):
245 872ca586 Kostas Papadimitriou
                def violation(*args):
246 872ca586 Kostas Papadimitriou
                    pass
247 872ca586 Kostas Papadimitriou
                DirectorySandbox._old = DirectorySandbox._violation
248 872ca586 Kostas Papadimitriou
                DirectorySandbox._violation = violation
249 872ca586 Kostas Papadimitriou
                patched = True
250 872ca586 Kostas Papadimitriou
            else:
251 872ca586 Kostas Papadimitriou
                patched = False
252 872ca586 Kostas Papadimitriou
        except ImportError:
253 872ca586 Kostas Papadimitriou
            patched = False
254 872ca586 Kostas Papadimitriou
255 872ca586 Kostas Papadimitriou
        try:
256 872ca586 Kostas Papadimitriou
            return function(*args, **kw)
257 872ca586 Kostas Papadimitriou
        finally:
258 872ca586 Kostas Papadimitriou
            if patched:
259 872ca586 Kostas Papadimitriou
                DirectorySandbox._violation = DirectorySandbox._old
260 872ca586 Kostas Papadimitriou
                del DirectorySandbox._old
261 872ca586 Kostas Papadimitriou
262 872ca586 Kostas Papadimitriou
    return __no_sandbox
263 872ca586 Kostas Papadimitriou
264 872ca586 Kostas Papadimitriou
def _patch_file(path, content):
265 872ca586 Kostas Papadimitriou
    """Will backup the file then patch it"""
266 872ca586 Kostas Papadimitriou
    existing_content = open(path).read()
267 872ca586 Kostas Papadimitriou
    if existing_content == content:
268 872ca586 Kostas Papadimitriou
        # already patched
269 872ca586 Kostas Papadimitriou
        log.warn('Already patched.')
270 872ca586 Kostas Papadimitriou
        return False
271 872ca586 Kostas Papadimitriou
    log.warn('Patching...')
272 872ca586 Kostas Papadimitriou
    _rename_path(path)
273 872ca586 Kostas Papadimitriou
    f = open(path, 'w')
274 872ca586 Kostas Papadimitriou
    try:
275 872ca586 Kostas Papadimitriou
        f.write(content)
276 872ca586 Kostas Papadimitriou
    finally:
277 872ca586 Kostas Papadimitriou
        f.close()
278 872ca586 Kostas Papadimitriou
    return True
279 872ca586 Kostas Papadimitriou
280 872ca586 Kostas Papadimitriou
_patch_file = _no_sandbox(_patch_file)
281 872ca586 Kostas Papadimitriou
282 872ca586 Kostas Papadimitriou
def _same_content(path, content):
283 872ca586 Kostas Papadimitriou
    return open(path).read() == content
284 872ca586 Kostas Papadimitriou
285 872ca586 Kostas Papadimitriou
def _rename_path(path):
286 872ca586 Kostas Papadimitriou
    new_name = path + '.OLD.%s' % time.time()
287 872ca586 Kostas Papadimitriou
    log.warn('Renaming %s into %s', path, new_name)
288 872ca586 Kostas Papadimitriou
    os.rename(path, new_name)
289 872ca586 Kostas Papadimitriou
    return new_name
290 872ca586 Kostas Papadimitriou
291 872ca586 Kostas Papadimitriou
def _remove_flat_installation(placeholder):
292 872ca586 Kostas Papadimitriou
    if not os.path.isdir(placeholder):
293 872ca586 Kostas Papadimitriou
        log.warn('Unkown installation at %s', placeholder)
294 872ca586 Kostas Papadimitriou
        return False
295 872ca586 Kostas Papadimitriou
    found = False
296 872ca586 Kostas Papadimitriou
    for file in os.listdir(placeholder):
297 872ca586 Kostas Papadimitriou
        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
298 872ca586 Kostas Papadimitriou
            found = True
299 872ca586 Kostas Papadimitriou
            break
300 872ca586 Kostas Papadimitriou
    if not found:
301 872ca586 Kostas Papadimitriou
        log.warn('Could not locate setuptools*.egg-info')
302 872ca586 Kostas Papadimitriou
        return
303 872ca586 Kostas Papadimitriou
304 872ca586 Kostas Papadimitriou
    log.warn('Removing elements out of the way...')
305 872ca586 Kostas Papadimitriou
    pkg_info = os.path.join(placeholder, file)
306 872ca586 Kostas Papadimitriou
    if os.path.isdir(pkg_info):
307 872ca586 Kostas Papadimitriou
        patched = _patch_egg_dir(pkg_info)
308 872ca586 Kostas Papadimitriou
    else:
309 872ca586 Kostas Papadimitriou
        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
310 872ca586 Kostas Papadimitriou
311 872ca586 Kostas Papadimitriou
    if not patched:
312 872ca586 Kostas Papadimitriou
        log.warn('%s already patched.', pkg_info)
313 872ca586 Kostas Papadimitriou
        return False
314 872ca586 Kostas Papadimitriou
    # now let's move the files out of the way
315 872ca586 Kostas Papadimitriou
    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
316 872ca586 Kostas Papadimitriou
        element = os.path.join(placeholder, element)
317 872ca586 Kostas Papadimitriou
        if os.path.exists(element):
318 872ca586 Kostas Papadimitriou
            _rename_path(element)
319 872ca586 Kostas Papadimitriou
        else:
320 872ca586 Kostas Papadimitriou
            log.warn('Could not find the %s element of the '
321 872ca586 Kostas Papadimitriou
                     'Setuptools distribution', element)
322 872ca586 Kostas Papadimitriou
    return True
323 872ca586 Kostas Papadimitriou
324 872ca586 Kostas Papadimitriou
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
325 872ca586 Kostas Papadimitriou
326 872ca586 Kostas Papadimitriou
def _after_install(dist):
327 872ca586 Kostas Papadimitriou
    log.warn('After install bootstrap.')
328 872ca586 Kostas Papadimitriou
    placeholder = dist.get_command_obj('install').install_purelib
329 872ca586 Kostas Papadimitriou
    _create_fake_setuptools_pkg_info(placeholder)
330 872ca586 Kostas Papadimitriou
331 872ca586 Kostas Papadimitriou
def _create_fake_setuptools_pkg_info(placeholder):
332 872ca586 Kostas Papadimitriou
    if not placeholder or not os.path.exists(placeholder):
333 872ca586 Kostas Papadimitriou
        log.warn('Could not find the install location')
334 872ca586 Kostas Papadimitriou
        return
335 872ca586 Kostas Papadimitriou
    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
336 872ca586 Kostas Papadimitriou
    setuptools_file = 'setuptools-%s-py%s.egg-info' % \
337 872ca586 Kostas Papadimitriou
            (SETUPTOOLS_FAKED_VERSION, pyver)
338 872ca586 Kostas Papadimitriou
    pkg_info = os.path.join(placeholder, setuptools_file)
339 872ca586 Kostas Papadimitriou
    if os.path.exists(pkg_info):
340 872ca586 Kostas Papadimitriou
        log.warn('%s already exists', pkg_info)
341 872ca586 Kostas Papadimitriou
        return
342 872ca586 Kostas Papadimitriou
343 872ca586 Kostas Papadimitriou
    log.warn('Creating %s', pkg_info)
344 872ca586 Kostas Papadimitriou
    f = open(pkg_info, 'w')
345 872ca586 Kostas Papadimitriou
    try:
346 872ca586 Kostas Papadimitriou
        f.write(SETUPTOOLS_PKG_INFO)
347 872ca586 Kostas Papadimitriou
    finally:
348 872ca586 Kostas Papadimitriou
        f.close()
349 872ca586 Kostas Papadimitriou
350 872ca586 Kostas Papadimitriou
    pth_file = os.path.join(placeholder, 'setuptools.pth')
351 872ca586 Kostas Papadimitriou
    log.warn('Creating %s', pth_file)
352 872ca586 Kostas Papadimitriou
    f = open(pth_file, 'w')
353 872ca586 Kostas Papadimitriou
    try:
354 872ca586 Kostas Papadimitriou
        f.write(os.path.join(os.curdir, setuptools_file))
355 872ca586 Kostas Papadimitriou
    finally:
356 872ca586 Kostas Papadimitriou
        f.close()
357 872ca586 Kostas Papadimitriou
358 872ca586 Kostas Papadimitriou
_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
359 872ca586 Kostas Papadimitriou
360 872ca586 Kostas Papadimitriou
def _patch_egg_dir(path):
361 872ca586 Kostas Papadimitriou
    # let's check if it's already patched
362 872ca586 Kostas Papadimitriou
    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
363 872ca586 Kostas Papadimitriou
    if os.path.exists(pkg_info):
364 872ca586 Kostas Papadimitriou
        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
365 872ca586 Kostas Papadimitriou
            log.warn('%s already patched.', pkg_info)
366 872ca586 Kostas Papadimitriou
            return False
367 872ca586 Kostas Papadimitriou
    _rename_path(path)
368 872ca586 Kostas Papadimitriou
    os.mkdir(path)
369 872ca586 Kostas Papadimitriou
    os.mkdir(os.path.join(path, 'EGG-INFO'))
370 872ca586 Kostas Papadimitriou
    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
371 872ca586 Kostas Papadimitriou
    f = open(pkg_info, 'w')
372 872ca586 Kostas Papadimitriou
    try:
373 872ca586 Kostas Papadimitriou
        f.write(SETUPTOOLS_PKG_INFO)
374 872ca586 Kostas Papadimitriou
    finally:
375 872ca586 Kostas Papadimitriou
        f.close()
376 872ca586 Kostas Papadimitriou
    return True
377 872ca586 Kostas Papadimitriou
378 872ca586 Kostas Papadimitriou
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
379 872ca586 Kostas Papadimitriou
380 872ca586 Kostas Papadimitriou
def _before_install():
381 872ca586 Kostas Papadimitriou
    log.warn('Before install bootstrap.')
382 872ca586 Kostas Papadimitriou
    _fake_setuptools()
383 872ca586 Kostas Papadimitriou
384 872ca586 Kostas Papadimitriou
385 872ca586 Kostas Papadimitriou
def _under_prefix(location):
386 872ca586 Kostas Papadimitriou
    if 'install' not in sys.argv:
387 872ca586 Kostas Papadimitriou
        return True
388 872ca586 Kostas Papadimitriou
    args = sys.argv[sys.argv.index('install')+1:]
389 872ca586 Kostas Papadimitriou
    for index, arg in enumerate(args):
390 872ca586 Kostas Papadimitriou
        for option in ('--root', '--prefix'):
391 872ca586 Kostas Papadimitriou
            if arg.startswith('%s=' % option):
392 872ca586 Kostas Papadimitriou
                top_dir = arg.split('root=')[-1]
393 872ca586 Kostas Papadimitriou
                return location.startswith(top_dir)
394 872ca586 Kostas Papadimitriou
            elif arg == option:
395 872ca586 Kostas Papadimitriou
                if len(args) > index:
396 872ca586 Kostas Papadimitriou
                    top_dir = args[index+1]
397 872ca586 Kostas Papadimitriou
                    return location.startswith(top_dir)
398 872ca586 Kostas Papadimitriou
        if arg == '--user' and USER_SITE is not None:
399 872ca586 Kostas Papadimitriou
            return location.startswith(USER_SITE)
400 872ca586 Kostas Papadimitriou
    return True
401 872ca586 Kostas Papadimitriou
402 872ca586 Kostas Papadimitriou
403 872ca586 Kostas Papadimitriou
def _fake_setuptools():
404 872ca586 Kostas Papadimitriou
    log.warn('Scanning installed packages')
405 872ca586 Kostas Papadimitriou
    try:
406 872ca586 Kostas Papadimitriou
        import pkg_resources
407 872ca586 Kostas Papadimitriou
    except ImportError:
408 872ca586 Kostas Papadimitriou
        # we're cool
409 872ca586 Kostas Papadimitriou
        log.warn('Setuptools or Distribute does not seem to be installed.')
410 872ca586 Kostas Papadimitriou
        return
411 872ca586 Kostas Papadimitriou
    ws = pkg_resources.working_set
412 872ca586 Kostas Papadimitriou
    try:
413 872ca586 Kostas Papadimitriou
        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
414 872ca586 Kostas Papadimitriou
                                  replacement=False))
415 872ca586 Kostas Papadimitriou
    except TypeError:
416 872ca586 Kostas Papadimitriou
        # old distribute API
417 872ca586 Kostas Papadimitriou
        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
418 872ca586 Kostas Papadimitriou
419 872ca586 Kostas Papadimitriou
    if setuptools_dist is None:
420 872ca586 Kostas Papadimitriou
        log.warn('No setuptools distribution found')
421 872ca586 Kostas Papadimitriou
        return
422 872ca586 Kostas Papadimitriou
    # detecting if it was already faked
423 872ca586 Kostas Papadimitriou
    setuptools_location = setuptools_dist.location
424 872ca586 Kostas Papadimitriou
    log.warn('Setuptools installation detected at %s', setuptools_location)
425 872ca586 Kostas Papadimitriou
426 872ca586 Kostas Papadimitriou
    # if --root or --preix was provided, and if
427 872ca586 Kostas Papadimitriou
    # setuptools is not located in them, we don't patch it
428 872ca586 Kostas Papadimitriou
    if not _under_prefix(setuptools_location):
429 872ca586 Kostas Papadimitriou
        log.warn('Not patching, --root or --prefix is installing Distribute'
430 872ca586 Kostas Papadimitriou
                 ' in another location')
431 872ca586 Kostas Papadimitriou
        return
432 872ca586 Kostas Papadimitriou
433 872ca586 Kostas Papadimitriou
    # let's see if its an egg
434 872ca586 Kostas Papadimitriou
    if not setuptools_location.endswith('.egg'):
435 872ca586 Kostas Papadimitriou
        log.warn('Non-egg installation')
436 872ca586 Kostas Papadimitriou
        res = _remove_flat_installation(setuptools_location)
437 872ca586 Kostas Papadimitriou
        if not res:
438 872ca586 Kostas Papadimitriou
            return
439 872ca586 Kostas Papadimitriou
    else:
440 872ca586 Kostas Papadimitriou
        log.warn('Egg installation')
441 872ca586 Kostas Papadimitriou
        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
442 872ca586 Kostas Papadimitriou
        if (os.path.exists(pkg_info) and
443 872ca586 Kostas Papadimitriou
            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
444 872ca586 Kostas Papadimitriou
            log.warn('Already patched.')
445 872ca586 Kostas Papadimitriou
            return
446 872ca586 Kostas Papadimitriou
        log.warn('Patching...')
447 872ca586 Kostas Papadimitriou
        # let's create a fake egg replacing setuptools one
448 872ca586 Kostas Papadimitriou
        res = _patch_egg_dir(setuptools_location)
449 872ca586 Kostas Papadimitriou
        if not res:
450 872ca586 Kostas Papadimitriou
            return
451 872ca586 Kostas Papadimitriou
    log.warn('Patched done.')
452 872ca586 Kostas Papadimitriou
    _relaunch()
453 872ca586 Kostas Papadimitriou
454 872ca586 Kostas Papadimitriou
455 872ca586 Kostas Papadimitriou
def _relaunch():
456 872ca586 Kostas Papadimitriou
    log.warn('Relaunching...')
457 872ca586 Kostas Papadimitriou
    # we have to relaunch the process
458 872ca586 Kostas Papadimitriou
    # pip marker to avoid a relaunch bug
459 872ca586 Kostas Papadimitriou
    if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
460 872ca586 Kostas Papadimitriou
        sys.argv[0] = 'setup.py'
461 872ca586 Kostas Papadimitriou
    args = [sys.executable] + sys.argv
462 872ca586 Kostas Papadimitriou
    sys.exit(subprocess.call(args))
463 872ca586 Kostas Papadimitriou
464 872ca586 Kostas Papadimitriou
465 872ca586 Kostas Papadimitriou
def _extractall(self, path=".", members=None):
466 872ca586 Kostas Papadimitriou
    """Extract all members from the archive to the current working
467 872ca586 Kostas Papadimitriou
       directory and set owner, modification time and permissions on
468 872ca586 Kostas Papadimitriou
       directories afterwards. `path' specifies a different directory
469 872ca586 Kostas Papadimitriou
       to extract to. `members' is optional and must be a subset of the
470 872ca586 Kostas Papadimitriou
       list returned by getmembers().
471 872ca586 Kostas Papadimitriou
    """
472 872ca586 Kostas Papadimitriou
    import copy
473 872ca586 Kostas Papadimitriou
    import operator
474 872ca586 Kostas Papadimitriou
    from tarfile import ExtractError
475 872ca586 Kostas Papadimitriou
    directories = []
476 872ca586 Kostas Papadimitriou
477 872ca586 Kostas Papadimitriou
    if members is None:
478 872ca586 Kostas Papadimitriou
        members = self
479 872ca586 Kostas Papadimitriou
480 872ca586 Kostas Papadimitriou
    for tarinfo in members:
481 872ca586 Kostas Papadimitriou
        if tarinfo.isdir():
482 872ca586 Kostas Papadimitriou
            # Extract directories with a safe mode.
483 872ca586 Kostas Papadimitriou
            directories.append(tarinfo)
484 872ca586 Kostas Papadimitriou
            tarinfo = copy.copy(tarinfo)
485 872ca586 Kostas Papadimitriou
            tarinfo.mode = 448 # decimal for oct 0700
486 872ca586 Kostas Papadimitriou
        self.extract(tarinfo, path)
487 872ca586 Kostas Papadimitriou
488 872ca586 Kostas Papadimitriou
    # Reverse sort directories.
489 872ca586 Kostas Papadimitriou
    if sys.version_info < (2, 4):
490 872ca586 Kostas Papadimitriou
        def sorter(dir1, dir2):
491 872ca586 Kostas Papadimitriou
            return cmp(dir1.name, dir2.name)
492 872ca586 Kostas Papadimitriou
        directories.sort(sorter)
493 872ca586 Kostas Papadimitriou
        directories.reverse()
494 872ca586 Kostas Papadimitriou
    else:
495 872ca586 Kostas Papadimitriou
        directories.sort(key=operator.attrgetter('name'), reverse=True)
496 872ca586 Kostas Papadimitriou
497 872ca586 Kostas Papadimitriou
    # Set correct owner, mtime and filemode on directories.
498 872ca586 Kostas Papadimitriou
    for tarinfo in directories:
499 872ca586 Kostas Papadimitriou
        dirpath = os.path.join(path, tarinfo.name)
500 872ca586 Kostas Papadimitriou
        try:
501 872ca586 Kostas Papadimitriou
            self.chown(tarinfo, dirpath)
502 872ca586 Kostas Papadimitriou
            self.utime(tarinfo, dirpath)
503 872ca586 Kostas Papadimitriou
            self.chmod(tarinfo, dirpath)
504 872ca586 Kostas Papadimitriou
        except ExtractError:
505 872ca586 Kostas Papadimitriou
            e = sys.exc_info()[1]
506 872ca586 Kostas Papadimitriou
            if self.errorlevel > 1:
507 872ca586 Kostas Papadimitriou
                raise
508 872ca586 Kostas Papadimitriou
            else:
509 872ca586 Kostas Papadimitriou
                self._dbg(1, "tarfile: %s" % e)
510 872ca586 Kostas Papadimitriou
511 872ca586 Kostas Papadimitriou
512 872ca586 Kostas Papadimitriou
def main(argv, version=DEFAULT_VERSION):
513 872ca586 Kostas Papadimitriou
    """Install or upgrade setuptools and EasyInstall"""
514 872ca586 Kostas Papadimitriou
    tarball = download_setuptools()
515 872ca586 Kostas Papadimitriou
    _install(tarball)
516 872ca586 Kostas Papadimitriou
517 872ca586 Kostas Papadimitriou
518 872ca586 Kostas Papadimitriou
if __name__ == '__main__':
519 872ca586 Kostas Papadimitriou
    main(sys.argv[1:])