~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to distribute_setup.py

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!python
2
 
"""Bootstrap distribute installation
3
 
 
4
 
If you want to use setuptools in your package's setup.py, just include this
5
 
file in the same directory with it, and add this to the top of your setup.py::
6
 
 
7
 
    from distribute_setup import use_setuptools
8
 
    use_setuptools()
9
 
 
10
 
If you want to require a specific version of setuptools, set a download
11
 
mirror, or use an alternate download directory, you can do so by supplying
12
 
the appropriate options to ``use_setuptools()``.
13
 
 
14
 
This file can also be run as a script to install or upgrade setuptools.
15
 
"""
16
 
import os
17
 
import sys
18
 
import time
19
 
import fnmatch
20
 
import tempfile
21
 
import tarfile
22
 
from distutils import log
23
 
 
24
 
try:
25
 
    from site import USER_SITE
26
 
except ImportError:
27
 
    USER_SITE = None
28
 
 
29
 
try:
30
 
    import subprocess
31
 
 
32
 
    def _python_cmd(*args):
33
 
        args = (sys.executable,) + args
34
 
        return subprocess.call(args) == 0
35
 
 
36
 
except ImportError:
37
 
    # will be used for python 2.3
38
 
    def _python_cmd(*args):
39
 
        args = (sys.executable,) + args
40
 
        # quoting arguments if windows
41
 
        if sys.platform == 'win32':
42
 
            def quote(arg):
43
 
                if ' ' in arg:
44
 
                    return '"%s"' % arg
45
 
                return arg
46
 
            args = [quote(arg) for arg in args]
47
 
        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
48
 
 
49
 
DEFAULT_VERSION = "0.6.10"
50
 
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
51
 
SETUPTOOLS_FAKED_VERSION = "0.6c11"
52
 
 
53
 
SETUPTOOLS_PKG_INFO = """\
54
 
Metadata-Version: 1.0
55
 
Name: setuptools
56
 
Version: %s
57
 
Summary: xxxx
58
 
Home-page: xxx
59
 
Author: xxx
60
 
Author-email: xxx
61
 
License: xxx
62
 
Description: xxx
63
 
""" % SETUPTOOLS_FAKED_VERSION
64
 
 
65
 
 
66
 
def _install(tarball):
67
 
    # extracting the tarball
68
 
    tmpdir = tempfile.mkdtemp()
69
 
    log.warn('Extracting in %s', tmpdir)
70
 
    old_wd = os.getcwd()
71
 
    try:
72
 
        os.chdir(tmpdir)
73
 
        tar = tarfile.open(tarball)
74
 
        _extractall(tar)
75
 
        tar.close()
76
 
 
77
 
        # going in the directory
78
 
        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
79
 
        os.chdir(subdir)
80
 
        log.warn('Now working in %s', subdir)
81
 
 
82
 
        # installing
83
 
        log.warn('Installing Distribute')
84
 
        if not _python_cmd('setup.py', 'install'):
85
 
            log.warn('Something went wrong during the installation.')
86
 
            log.warn('See the error message above.')
87
 
    finally:
88
 
        os.chdir(old_wd)
89
 
 
90
 
 
91
 
def _build_egg(egg, tarball, to_dir):
92
 
    # extracting the tarball
93
 
    tmpdir = tempfile.mkdtemp()
94
 
    log.warn('Extracting in %s', tmpdir)
95
 
    old_wd = os.getcwd()
96
 
    try:
97
 
        os.chdir(tmpdir)
98
 
        tar = tarfile.open(tarball)
99
 
        _extractall(tar)
100
 
        tar.close()
101
 
 
102
 
        # going in the directory
103
 
        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
104
 
        os.chdir(subdir)
105
 
        log.warn('Now working in %s', subdir)
106
 
 
107
 
        # building an egg
108
 
        log.warn('Building a Distribute egg in %s', to_dir)
109
 
        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
110
 
 
111
 
    finally:
112
 
        os.chdir(old_wd)
113
 
    # returning the result
114
 
    log.warn(egg)
115
 
    if not os.path.exists(egg):
116
 
        raise IOError('Could not build the egg.')
117
 
 
118
 
 
119
 
def _do_download(version, download_base, to_dir, download_delay):
120
 
    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
121
 
                       % (version, sys.version_info[0], sys.version_info[1]))
122
 
    if not os.path.exists(egg):
123
 
        tarball = download_setuptools(version, download_base,
124
 
                                      to_dir, download_delay)
125
 
        _build_egg(egg, tarball, to_dir)
126
 
    sys.path.insert(0, egg)
127
 
    import setuptools
128
 
    setuptools.bootstrap_install_from = egg
129
 
 
130
 
 
131
 
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
132
 
                   to_dir=os.curdir, download_delay=15, no_fake=True):
133
 
    # making sure we use the absolute path
134
 
    to_dir = os.path.abspath(to_dir)
135
 
    was_imported = 'pkg_resources' in sys.modules or \
136
 
        'setuptools' in sys.modules
137
 
    try:
138
 
        try:
139
 
            import pkg_resources
140
 
            if not hasattr(pkg_resources, '_distribute'):
141
 
                if not no_fake:
142
 
                    _fake_setuptools()
143
 
                raise ImportError
144
 
        except ImportError:
145
 
            return _do_download(version, download_base, to_dir, download_delay)
146
 
        try:
147
 
            pkg_resources.require("distribute>="+version)
148
 
            return
149
 
        except pkg_resources.VersionConflict:
150
 
            e = sys.exc_info()[1]
151
 
            if was_imported:
152
 
                sys.stderr.write(
153
 
                "The required version of distribute (>=%s) is not available,\n"
154
 
                "and can't be installed while this script is running. Please\n"
155
 
                "install a more recent version first, using\n"
156
 
                "'easy_install -U distribute'."
157
 
                "\n\n(Currently using %r)\n" % (version, e.args[0]))
158
 
                sys.exit(2)
159
 
            else:
160
 
                del pkg_resources, sys.modules['pkg_resources']    # reload ok
161
 
                return _do_download(version, download_base, to_dir,
162
 
                                    download_delay)
163
 
        except pkg_resources.DistributionNotFound:
164
 
            return _do_download(version, download_base, to_dir,
165
 
                                download_delay)
166
 
    finally:
167
 
        if not no_fake:
168
 
            _create_fake_setuptools_pkg_info(to_dir)
169
 
 
170
 
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
171
 
                        to_dir=os.curdir, delay=15):
172
 
    """Download distribute from a specified location and return its filename
173
 
 
174
 
    `version` should be a valid distribute version number that is available
175
 
    as an egg for download under the `download_base` URL (which should end
176
 
    with a '/'). `to_dir` is the directory where the egg will be downloaded.
177
 
    `delay` is the number of seconds to pause before an actual download
178
 
    attempt.
179
 
    """
180
 
    # making sure we use the absolute path
181
 
    to_dir = os.path.abspath(to_dir)
182
 
    try:
183
 
        from urllib.request import urlopen
184
 
    except ImportError:
185
 
        from urllib2 import urlopen
186
 
    tgz_name = "distribute-%s.tar.gz" % version
187
 
    url = download_base + tgz_name
188
 
    saveto = os.path.join(to_dir, tgz_name)
189
 
    src = dst = None
190
 
    if not os.path.exists(saveto):  # Avoid repeated downloads
191
 
        try:
192
 
            log.warn("Downloading %s", url)
193
 
            src = urlopen(url)
194
 
            # Read/write all in one block, so we don't create a corrupt file
195
 
            # if the download is interrupted.
196
 
            data = src.read()
197
 
            dst = open(saveto, "wb")
198
 
            dst.write(data)
199
 
        finally:
200
 
            if src:
201
 
                src.close()
202
 
            if dst:
203
 
                dst.close()
204
 
    return os.path.realpath(saveto)
205
 
 
206
 
 
207
 
def _patch_file(path, content):
208
 
    """Will backup the file then patch it"""
209
 
    existing_content = open(path).read()
210
 
    if existing_content == content:
211
 
        # already patched
212
 
        log.warn('Already patched.')
213
 
        return False
214
 
    log.warn('Patching...')
215
 
    _rename_path(path)
216
 
    f = open(path, 'w')
217
 
    try:
218
 
        f.write(content)
219
 
    finally:
220
 
        f.close()
221
 
    return True
222
 
 
223
 
 
224
 
def _same_content(path, content):
225
 
    return open(path).read() == content
226
 
 
227
 
def _no_sandbox(function):
228
 
    def __no_sandbox(*args, **kw):
229
 
        try:
230
 
            from setuptools.sandbox import DirectorySandbox
231
 
            def violation(*args):
232
 
                pass
233
 
            DirectorySandbox._old = DirectorySandbox._violation
234
 
            DirectorySandbox._violation = violation
235
 
            patched = True
236
 
        except ImportError:
237
 
            patched = False
238
 
 
239
 
        try:
240
 
            return function(*args, **kw)
241
 
        finally:
242
 
            if patched:
243
 
                DirectorySandbox._violation = DirectorySandbox._old
244
 
                del DirectorySandbox._old
245
 
 
246
 
    return __no_sandbox
247
 
 
248
 
@_no_sandbox
249
 
def _rename_path(path):
250
 
    new_name = path + '.OLD.%s' % time.time()
251
 
    log.warn('Renaming %s into %s', path, new_name)
252
 
    os.rename(path, new_name)
253
 
    return new_name
254
 
 
255
 
def _remove_flat_installation(placeholder):
256
 
    if not os.path.isdir(placeholder):
257
 
        log.warn('Unkown installation at %s', placeholder)
258
 
        return False
259
 
    found = False
260
 
    for file in os.listdir(placeholder):
261
 
        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
262
 
            found = True
263
 
            break
264
 
    if not found:
265
 
        log.warn('Could not locate setuptools*.egg-info')
266
 
        return
267
 
 
268
 
    log.warn('Removing elements out of the way...')
269
 
    pkg_info = os.path.join(placeholder, file)
270
 
    if os.path.isdir(pkg_info):
271
 
        patched = _patch_egg_dir(pkg_info)
272
 
    else:
273
 
        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
274
 
 
275
 
    if not patched:
276
 
        log.warn('%s already patched.', pkg_info)
277
 
        return False
278
 
    # now let's move the files out of the way
279
 
    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
280
 
        element = os.path.join(placeholder, element)
281
 
        if os.path.exists(element):
282
 
            _rename_path(element)
283
 
        else:
284
 
            log.warn('Could not find the %s element of the '
285
 
                     'Setuptools distribution', element)
286
 
    return True
287
 
 
288
 
 
289
 
def _after_install(dist):
290
 
    log.warn('After install bootstrap.')
291
 
    placeholder = dist.get_command_obj('install').install_purelib
292
 
    _create_fake_setuptools_pkg_info(placeholder)
293
 
 
294
 
@_no_sandbox
295
 
def _create_fake_setuptools_pkg_info(placeholder):
296
 
    if not placeholder or not os.path.exists(placeholder):
297
 
        log.warn('Could not find the install location')
298
 
        return
299
 
    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
300
 
    setuptools_file = 'setuptools-%s-py%s.egg-info' % \
301
 
            (SETUPTOOLS_FAKED_VERSION, pyver)
302
 
    pkg_info = os.path.join(placeholder, setuptools_file)
303
 
    if os.path.exists(pkg_info):
304
 
        log.warn('%s already exists', pkg_info)
305
 
        return
306
 
 
307
 
    log.warn('Creating %s', pkg_info)
308
 
    f = open(pkg_info, 'w')
309
 
    try:
310
 
        f.write(SETUPTOOLS_PKG_INFO)
311
 
    finally:
312
 
        f.close()
313
 
 
314
 
    pth_file = os.path.join(placeholder, 'setuptools.pth')
315
 
    log.warn('Creating %s', pth_file)
316
 
    f = open(pth_file, 'w')
317
 
    try:
318
 
        f.write(os.path.join(os.curdir, setuptools_file))
319
 
    finally:
320
 
        f.close()
321
 
 
322
 
def _patch_egg_dir(path):
323
 
    # let's check if it's already patched
324
 
    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
325
 
    if os.path.exists(pkg_info):
326
 
        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
327
 
            log.warn('%s already patched.', pkg_info)
328
 
            return False
329
 
    _rename_path(path)
330
 
    os.mkdir(path)
331
 
    os.mkdir(os.path.join(path, 'EGG-INFO'))
332
 
    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
333
 
    f = open(pkg_info, 'w')
334
 
    try:
335
 
        f.write(SETUPTOOLS_PKG_INFO)
336
 
    finally:
337
 
        f.close()
338
 
    return True
339
 
 
340
 
 
341
 
def _before_install():
342
 
    log.warn('Before install bootstrap.')
343
 
    _fake_setuptools()
344
 
 
345
 
 
346
 
def _under_prefix(location):
347
 
    if 'install' not in sys.argv:
348
 
        return True
349
 
    args = sys.argv[sys.argv.index('install')+1:]
350
 
    for index, arg in enumerate(args):
351
 
        for option in ('--root', '--prefix'):
352
 
            if arg.startswith('%s=' % option):
353
 
                top_dir = arg.split('root=')[-1]
354
 
                return location.startswith(top_dir)
355
 
            elif arg == option:
356
 
                if len(args) > index:
357
 
                    top_dir = args[index+1]
358
 
                    return location.startswith(top_dir)
359
 
            elif option == '--user' and USER_SITE is not None:
360
 
                return location.startswith(USER_SITE)
361
 
    return True
362
 
 
363
 
 
364
 
def _fake_setuptools():
365
 
    log.warn('Scanning installed packages')
366
 
    try:
367
 
        import pkg_resources
368
 
    except ImportError:
369
 
        # we're cool
370
 
        log.warn('Setuptools or Distribute does not seem to be installed.')
371
 
        return
372
 
    ws = pkg_resources.working_set
373
 
    try:
374
 
        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
375
 
                                  replacement=False))
376
 
    except TypeError:
377
 
        # old distribute API
378
 
        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
379
 
 
380
 
    if setuptools_dist is None:
381
 
        log.warn('No setuptools distribution found')
382
 
        return
383
 
    # detecting if it was already faked
384
 
    setuptools_location = setuptools_dist.location
385
 
    log.warn('Setuptools installation detected at %s', setuptools_location)
386
 
 
387
 
    # if --root or --preix was provided, and if
388
 
    # setuptools is not located in them, we don't patch it
389
 
    if not _under_prefix(setuptools_location):
390
 
        log.warn('Not patching, --root or --prefix is installing Distribute'
391
 
                 ' in another location')
392
 
        return
393
 
 
394
 
    # let's see if its an egg
395
 
    if not setuptools_location.endswith('.egg'):
396
 
        log.warn('Non-egg installation')
397
 
        res = _remove_flat_installation(setuptools_location)
398
 
        if not res:
399
 
            return
400
 
    else:
401
 
        log.warn('Egg installation')
402
 
        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
403
 
        if (os.path.exists(pkg_info) and
404
 
            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
405
 
            log.warn('Already patched.')
406
 
            return
407
 
        log.warn('Patching...')
408
 
        # let's create a fake egg replacing setuptools one
409
 
        res = _patch_egg_dir(setuptools_location)
410
 
        if not res:
411
 
            return
412
 
    log.warn('Patched done.')
413
 
    _relaunch()
414
 
 
415
 
 
416
 
def _relaunch():
417
 
    log.warn('Relaunching...')
418
 
    # we have to relaunch the process
419
 
    args = [sys.executable] + sys.argv
420
 
    sys.exit(subprocess.call(args))
421
 
 
422
 
 
423
 
def _extractall(self, path=".", members=None):
424
 
    """Extract all members from the archive to the current working
425
 
       directory and set owner, modification time and permissions on
426
 
       directories afterwards. `path' specifies a different directory
427
 
       to extract to. `members' is optional and must be a subset of the
428
 
       list returned by getmembers().
429
 
    """
430
 
    import copy
431
 
    import operator
432
 
    from tarfile import ExtractError
433
 
    directories = []
434
 
 
435
 
    if members is None:
436
 
        members = self
437
 
 
438
 
    for tarinfo in members:
439
 
        if tarinfo.isdir():
440
 
            # Extract directories with a safe mode.
441
 
            directories.append(tarinfo)
442
 
            tarinfo = copy.copy(tarinfo)
443
 
            tarinfo.mode = 448 # decimal for oct 0700
444
 
        self.extract(tarinfo, path)
445
 
 
446
 
    # Reverse sort directories.
447
 
    if sys.version_info < (2, 4):
448
 
        def sorter(dir1, dir2):
449
 
            return cmp(dir1.name, dir2.name)
450
 
        directories.sort(sorter)
451
 
        directories.reverse()
452
 
    else:
453
 
        directories.sort(key=operator.attrgetter('name'), reverse=True)
454
 
 
455
 
    # Set correct owner, mtime and filemode on directories.
456
 
    for tarinfo in directories:
457
 
        dirpath = os.path.join(path, tarinfo.name)
458
 
        try:
459
 
            self.chown(tarinfo, dirpath)
460
 
            self.utime(tarinfo, dirpath)
461
 
            self.chmod(tarinfo, dirpath)
462
 
        except ExtractError:
463
 
            e = sys.exc_info()[1]
464
 
            if self.errorlevel > 1:
465
 
                raise
466
 
            else:
467
 
                self._dbg(1, "tarfile: %s" % e)
468
 
 
469
 
 
470
 
def main(argv, version=DEFAULT_VERSION):
471
 
    """Install or upgrade setuptools and EasyInstall"""
472
 
    tarball = download_setuptools()
473
 
    _install(tarball)
474
 
 
475
 
 
476
 
if __name__ == '__main__':
477
 
    main(sys.argv[1:])