Statistics
| Branch: | Tag: | Revision:

root / distribute_setup.py @ 18a2af6d

History | View | Annotate | Download (15.4 kB)

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

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

7 1c3c6417 Christos Stavrakakis
    from distribute_setup import use_setuptools
8 1c3c6417 Christos Stavrakakis
    use_setuptools()
9 1c3c6417 Christos Stavrakakis

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

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

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