Statistics
| Branch: | Tag: | Revision:

root / snf-django-lib / distribute_setup.py @ 4911365b

History | View | Annotate | Download (15.4 kB)

1 a712571b Christos Stavrakakis
#!python
2 a712571b Christos Stavrakakis
"""Bootstrap distribute installation
3 a712571b Christos Stavrakakis

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

7 a712571b Christos Stavrakakis
    from distribute_setup import use_setuptools
8 a712571b Christos Stavrakakis
    use_setuptools()
9 a712571b Christos Stavrakakis

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

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

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