Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / distribute_setup.py @ dfb1fafa

History | View | Annotate | Download (15.4 kB)

1 8c306eab Kostas Papadimitriou
#!python
2 8c306eab Kostas Papadimitriou
"""Bootstrap distribute installation
3 8c306eab Kostas Papadimitriou

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

7 8c306eab Kostas Papadimitriou
    from distribute_setup import use_setuptools
8 8c306eab Kostas Papadimitriou
    use_setuptools()
9 8c306eab Kostas Papadimitriou

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

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

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