aboutsummaryrefslogtreecommitdiffstats
path: root/bootstrap.py
blob: 1a78931122a3d578c556e307940399f5fdf1b8e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""
If setuptools is not already installed in the environment, it's not possible
to invoke setuptools' own commands. This routine will bootstrap this local
environment by creating a minimal egg-info directory and then invoking the
egg-info command to flesh out the egg-info directory.
"""

from __future__ import unicode_literals

import argparse
import os
import io
import re
import contextlib
import tempfile
import shutil
import sys
import textwrap
import subprocess


minimal_egg_info = textwrap.dedent("""
    [distutils.commands]
    egg_info = setuptools.command.egg_info:egg_info

    [distutils.setup_keywords]
    include_package_data = setuptools.dist:assert_bool
    install_requires = setuptools.dist:check_requirements
    extras_require = setuptools.dist:check_extras
    entry_points = setuptools.dist:check_entry_points

    [egg_info.writers]
    dependency_links.txt = setuptools.command.egg_info:overwrite_arg
    entry_points.txt = setuptools.command.egg_info:write_entries
    requires.txt = setuptools.command.egg_info:write_requirements
    """)


def ensure_egg_info():
    if os.path.exists('setuptools.egg-info'):
        return
    print("adding minimal entry_points")
    build_egg_info()


def build_egg_info():
    """
    Build a minimal egg-info, enough to invoke egg_info
    """

    os.mkdir('setuptools.egg-info')
    filename = 'setuptools.egg-info/entry_points.txt'
    with io.open(filename, 'w', encoding='utf-8') as ep:
        ep.write(minimal_egg_info)


def run_egg_info():
    cmd = [sys.executable, 'setup.py', 'egg_info']
    print("Regenerating egg_info")
    subprocess.check_call(cmd)
    print("...and again.")
    subprocess.check_call(cmd)


def gen_deps():
    with io.open('setup.py', encoding='utf-8') as strm:
        text = strm.read()
    pattern = r'install_requires=\[(.*?)\]'
    match = re.search(pattern, text, flags=re.M|re.DOTALL)
    reqs = eval(match.group(1).replace('\n', ''))
    with io.open('requirements.txt', 'w', encoding='utf-8') as reqs_file:
        reqs_file.write('\n'.join(reqs))


@contextlib.contextmanager
def install_deps():
    "Just in time make the deps available"
    import pip
    gen_deps()
    tmpdir = tempfile.mkdtemp()
    args = [
        'install',
        '-t', tmpdir,
        '-r', 'requirements.txt',
    ]
    pip.main(args)
    os.environ['PYTHONPATH'] = tmpdir
    try:
        yield tmpdir
    finally:
        shutil.rmtree(tmpdir)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='bootstrap setuptools')
    parser.add_argument(
        '--skip-dep-install', action='store_true',
        help=("Do not attempt to install setuptools dependencies. These "
              "should be provided in the environment in another manner."))
    args = parser.parse_args()
    ensure_egg_info()
    if args.skip_dep_install:
        run_egg_info()
    else:
        with install_deps():
            run_egg_info()