~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/python/virtualenv/virtualenv_embedded/distribute_setup.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

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