Statistics
| Branch: | Tag: | Revision:

root / snf-common / distribute_setup.py @ 381a548c

History | View | Annotate | Download (15.4 kB)

1 7fb619a0 Kostas Papadimitriou
#!python
2 7fb619a0 Kostas Papadimitriou
"""Bootstrap distribute installation
3 7fb619a0 Kostas Papadimitriou

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

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

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

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

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