bootstrap.py 5.93 KB
Newer Older
André Anjos's avatar
André Anjos committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Bootstrap a buildout-based project

Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""

21
22
23
24
25
import os
import shutil
import sys
import tempfile

André Anjos's avatar
André Anjos committed
26
27
from optparse import OptionParser

28
tmpeggs = tempfile.mkdtemp()
André Anjos's avatar
André Anjos committed
29
30
31
32
33
34
35
36
37

usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]

Bootstraps a buildout-based project.

Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.

38
39
Note that by using --find-links to point to local resources, you can keep
this script from going over the network.
André Anjos's avatar
André Anjos committed
40
41
42
'''

parser = OptionParser(usage=usage)
43
44
parser.add_option("-v", "--version", help="use a specific zc.buildout version")

André Anjos's avatar
André Anjos committed
45
46
47
48
49
50
51
52
53
parser.add_option("-t", "--accept-buildout-test-releases",
                  dest='accept_buildout_test_releases',
                  action="store_true", default=False,
                  help=("Normally, if you do not specify a --version, the "
                        "bootstrap script and buildout gets the newest "
                        "*final* versions of zc.buildout and its recipes and "
                        "extensions for you.  If you use this flag, "
                        "bootstrap and buildout will get the newest releases "
                        "even if they are alphas or betas."))
54
parser.add_option("-c", "--config-file",
55
56
                  help=("Specify the path to the buildout configuration "
                        "file to be used."))
57
parser.add_option("-f", "--find-links",
58
                  help=("Specify a URL to search for buildout releases"))
André Anjos's avatar
André Anjos committed
59
60


61
options, args = parser.parse_args()
André Anjos's avatar
André Anjos committed
62

63
######################################################################
64
# load/install setuptools
André Anjos's avatar
André Anjos committed
65

66
to_reload = False
André Anjos's avatar
André Anjos committed
67
try:
68
69
    import pkg_resources
    import setuptools
André Anjos's avatar
André Anjos committed
70
71
except ImportError:
    ez = {}
72
73
74
75
76
77

    try:
        from urllib.request import urlopen
    except ImportError:
        from urllib2 import urlopen

78
79
80
81
    # XXX use a more permanent ez_setup.py URL when available.
    exec(urlopen('https://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py'
                ).read(), ez)
    setup_args = dict(to_dir=tmpeggs, download_delay=0)
André Anjos's avatar
André Anjos committed
82
    ez['use_setuptools'](**setup_args)
83
84
85

    if to_reload:
        reload(pkg_resources)
André Anjos's avatar
André Anjos committed
86
87
88
89
90
91
92
    import pkg_resources
    # This does not (always?) update the default working set.  We will
    # do it.
    for path in sys.path:
        if path not in pkg_resources.working_set.entries:
            pkg_resources.working_set.add_entry(path)

93
94
95
96
97
98
99
100
101
102
103
104
105
######################################################################
# Try to best guess the version of buildout given setuptools
if options.version is None:

  try:
    from distutils.version import LooseVersion
    package = pkg_resources.require('setuptools')[0]
    v = LooseVersion(package.version)
    if v < LooseVersion('0.7'):
      options.version = '2.1.1'
  except:
    pass

106
107
108
######################################################################
# Install buildout

109
ws = pkg_resources.working_set
André Anjos's avatar
André Anjos committed
110

111
112
113
cmd = [sys.executable, '-c',
       'from setuptools.command.easy_install import main; main()',
       '-mZqNxd', tmpeggs]
André Anjos's avatar
André Anjos committed
114

115
116
117
118
119
120
find_links = os.environ.get(
    'bootstrap-testing-find-links',
    options.find_links or
    ('http://downloads.buildout.org/'
     if options.accept_buildout_test_releases else None)
    )
André Anjos's avatar
André Anjos committed
121
if find_links:
122
    cmd.extend(['-f', find_links])
André Anjos's avatar
André Anjos committed
123

124
125
setuptools_path = ws.find(
    pkg_resources.Requirement.parse('setuptools')).location
André Anjos's avatar
André Anjos committed
126
127
128
129
130
131
132

requirement = 'zc.buildout'
version = options.version
if version is None and not options.accept_buildout_test_releases:
    # Figure out the most recent final version of zc.buildout.
    import setuptools.package_index
    _final_parts = '*final-', '*final'
133

André Anjos's avatar
André Anjos committed
134
135
136
137
138
139
    def _final_version(parsed_version):
        for part in parsed_version:
            if (part[:1] == '*') and (part not in _final_parts):
                return False
        return True
    index = setuptools.package_index.PackageIndex(
140
        search_path=[setuptools_path])
André Anjos's avatar
André Anjos committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    if find_links:
        index.add_find_links((find_links,))
    req = pkg_resources.Requirement.parse(requirement)
    if index.obtain(req) is not None:
        best = []
        bestv = None
        for dist in index[req.project_name]:
            distv = dist.parsed_version
            if _final_version(distv):
                if bestv is None or distv > bestv:
                    best = [dist]
                    bestv = distv
                elif distv == bestv:
                    best.append(dist)
        if best:
            best.sort()
            version = best[-1].version
if version:
    requirement = '=='.join((requirement, version))
cmd.append(requirement)

162
import subprocess
163
if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
164
165
166
    raise Exception(
        "Failed to execute command:\n%s",
        repr(cmd)[1:-1])
André Anjos's avatar
André Anjos committed
167

168
169
170
171
######################################################################
# Import and run buildout

ws.add_entry(tmpeggs)
André Anjos's avatar
André Anjos committed
172
173
ws.require(requirement)
import zc.buildout.buildout
174
175
176
177
178
179
180
181

if not [a for a in args if '=' not in a]:
    args.append('bootstrap')

# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
    args[0:0] = ['-c', options.config_file]

André Anjos's avatar
André Anjos committed
182
zc.buildout.buildout.main(args)
183
shutil.rmtree(tmpeggs)