Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / distribute_setup.py @ b22de10a

History | View | Annotate | Download (15.4 kB)

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

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

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

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

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

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