Statistics
| Branch: | Tag: | Revision:

root / snf-tools / distribute_setup.py @ adc46059

History | View | Annotate | Download (15.4 kB)

1 1b5d6e95 John Giannelos
#!python
2 1b5d6e95 John Giannelos
"""Bootstrap distribute installation
3 1b5d6e95 John Giannelos

4 1b5d6e95 John Giannelos
If you want to use setuptools in your package's setup.py, just include this
5 1b5d6e95 John Giannelos
file in the same directory with it, and add this to the top of your setup.py::
6 1b5d6e95 John Giannelos

7 1b5d6e95 John Giannelos
    from distribute_setup import use_setuptools
8 1b5d6e95 John Giannelos
    use_setuptools()
9 1b5d6e95 John Giannelos

10 1b5d6e95 John Giannelos
If you want to require a specific version of setuptools, set a download
11 1b5d6e95 John Giannelos
mirror, or use an alternate download directory, you can do so by supplying
12 1b5d6e95 John Giannelos
the appropriate options to ``use_setuptools()``.
13 1b5d6e95 John Giannelos

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

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