~abompard/mailman/import21

« back to all changes in this revision

Viewing changes to bootstrap.py

  • Committer: Barry Warsaw
  • Date: 2013-07-21 14:43:28 UTC
  • Revision ID: barry@list.org-20130721144328-qu7hrnlcptnkaazf
Update bootstrap.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
use the -c option to specify an alternate configuration file.
19
19
"""
20
20
 
21
 
import os, shutil, sys, tempfile
 
21
import os, shutil, sys, tempfile, urllib, urllib2, subprocess
22
22
from optparse import OptionParser
23
23
 
24
 
tmpeggs = tempfile.mkdtemp()
 
24
if sys.platform == 'win32':
 
25
    def quote(c):
 
26
        if ' ' in c:
 
27
            return '"%s"' % c  # work around spawn lamosity on windows
 
28
        else:
 
29
            return c
 
30
else:
 
31
    quote = str
 
32
 
 
33
# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
 
34
stdout, stderr = subprocess.Popen(
 
35
    [sys.executable, '-Sc',
 
36
     'try:\n'
 
37
     '    import ConfigParser\n'
 
38
     'except ImportError:\n'
 
39
     '    print 1\n'
 
40
     'else:\n'
 
41
     '    print 0\n'],
 
42
    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
 
43
has_broken_dash_S = bool(int(stdout.strip()))
 
44
 
 
45
# In order to be more robust in the face of system Pythons, we want to
 
46
# run without site-packages loaded.  This is somewhat tricky, in
 
47
# particular because Python 2.6's distutils imports site, so starting
 
48
# with the -S flag is not sufficient.  However, we'll start with that:
 
49
if not has_broken_dash_S and 'site' in sys.modules:
 
50
    # We will restart with python -S.
 
51
    args = sys.argv[:]
 
52
    args[0:0] = [sys.executable, '-S']
 
53
    args = map(quote, args)
 
54
    os.execv(sys.executable, args)
 
55
# Now we are running with -S.  We'll get the clean sys.path, import site
 
56
# because distutils will do it later, and then reset the path and clean
 
57
# out any namespace packages from site-packages that might have been
 
58
# loaded by .pth files.
 
59
clean_path = sys.path[:]
 
60
import site  # imported because of its side effects
 
61
sys.path[:] = clean_path
 
62
for k, v in sys.modules.items():
 
63
    if k in ('setuptools', 'pkg_resources') or (
 
64
        hasattr(v, '__path__') and
 
65
        len(v.__path__) == 1 and
 
66
        not os.path.exists(os.path.join(v.__path__[0], '__init__.py'))):
 
67
        # This is a namespace package.  Remove it.
 
68
        sys.modules.pop(k)
 
69
 
 
70
is_jython = sys.platform.startswith('java')
 
71
 
 
72
setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
 
73
distribute_source = 'http://python-distribute.org/distribute_setup.py'
 
74
 
 
75
 
 
76
# parsing arguments
 
77
def normalize_to_url(option, opt_str, value, parser):
 
78
    if value:
 
79
        if '://' not in value:  # It doesn't smell like a URL.
 
80
            value = 'file://%s' % (
 
81
                urllib.pathname2url(
 
82
                    os.path.abspath(os.path.expanduser(value))),)
 
83
        if opt_str == '--download-base' and not value.endswith('/'):
 
84
            # Download base needs a trailing slash to make the world happy.
 
85
            value += '/'
 
86
    else:
 
87
        value = None
 
88
    name = opt_str[2:].replace('-', '_')
 
89
    setattr(parser.values, name, value)
25
90
 
26
91
usage = '''\
27
92
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
36
101
'''
37
102
 
38
103
parser = OptionParser(usage=usage)
39
 
parser.add_option("-v", "--version", help="use a specific zc.buildout version")
40
 
 
 
104
parser.add_option("-v", "--version", dest="version",
 
105
                          help="use a specific zc.buildout version")
 
106
parser.add_option("-d", "--distribute",
 
107
                   action="store_true", dest="use_distribute", default=False,
 
108
                   help="Use Distribute rather than Setuptools.")
 
109
parser.add_option("--setup-source", action="callback", dest="setup_source",
 
110
                  callback=normalize_to_url, nargs=1, type="string",
 
111
                  help=("Specify a URL or file location for the setup file. "
 
112
                        "If you use Setuptools, this will default to " +
 
113
                        setuptools_source + "; if you use Distribute, this "
 
114
                        "will default to " + distribute_source + "."))
 
115
parser.add_option("--download-base", action="callback", dest="download_base",
 
116
                  callback=normalize_to_url, nargs=1, type="string",
 
117
                  help=("Specify a URL or directory for downloading "
 
118
                        "zc.buildout and either Setuptools or Distribute. "
 
119
                        "Defaults to PyPI."))
 
120
parser.add_option("--eggs",
 
121
                  help=("Specify a directory for storing eggs.  Defaults to "
 
122
                        "a temporary directory that is deleted when the "
 
123
                        "bootstrap script completes."))
41
124
parser.add_option("-t", "--accept-buildout-test-releases",
42
125
                  dest='accept_buildout_test_releases',
43
126
                  action="store_true", default=False,
47
130
                        "extensions for you.  If you use this flag, "
48
131
                        "bootstrap and buildout will get the newest releases "
49
132
                        "even if they are alphas or betas."))
50
 
parser.add_option("-c", "--config-file",
 
133
parser.add_option("-c", None, action="store", dest="config_file",
51
134
                   help=("Specify the path to the buildout configuration "
52
135
                         "file to be used."))
53
 
parser.add_option("-f", "--find-links",
54
 
                   help=("Specify a URL to search for buildout releases"))
55
 
 
56
136
 
57
137
options, args = parser.parse_args()
58
138
 
59
 
######################################################################
60
 
# load/install distribute
61
 
 
62
 
to_reload = False
 
139
if options.eggs:
 
140
    eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
 
141
else:
 
142
    eggs_dir = tempfile.mkdtemp()
 
143
 
 
144
if options.setup_source is None:
 
145
    if options.use_distribute:
 
146
        options.setup_source = distribute_source
 
147
    else:
 
148
        options.setup_source = setuptools_source
 
149
 
 
150
if options.accept_buildout_test_releases:
 
151
    args.insert(0, 'buildout:accept-buildout-test-releases=true')
 
152
 
63
153
try:
64
 
    import pkg_resources, setuptools
 
154
    import pkg_resources
 
155
    import setuptools  # A flag.  Sometimes pkg_resources is installed alone.
65
156
    if not hasattr(pkg_resources, '_distribute'):
66
 
        to_reload = True
67
157
        raise ImportError
68
158
except ImportError:
 
159
    ez_code = urllib2.urlopen(
 
160
        options.setup_source).read().replace('\r\n', '\n')
69
161
    ez = {}
70
 
 
71
 
    try:
72
 
        from urllib.request import urlopen
73
 
    except ImportError:
74
 
        from urllib2 import urlopen
75
 
 
76
 
    exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
77
 
    setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
 
162
    exec ez_code in ez
 
163
    setup_args = dict(to_dir=eggs_dir, download_delay=0)
 
164
    if options.download_base:
 
165
        setup_args['download_base'] = options.download_base
 
166
    if options.use_distribute:
 
167
        setup_args['no_fake'] = True
 
168
        if sys.version_info[:2] == (2, 4):
 
169
            setup_args['version'] = '0.6.32'
78
170
    ez['use_setuptools'](**setup_args)
79
 
 
80
 
    if to_reload:
81
 
        reload(pkg_resources)
 
171
    if 'pkg_resources' in sys.modules:
 
172
        reload(sys.modules['pkg_resources'])
82
173
    import pkg_resources
83
174
    # This does not (always?) update the default working set.  We will
84
175
    # do it.
86
177
        if path not in pkg_resources.working_set.entries:
87
178
            pkg_resources.working_set.add_entry(path)
88
179
 
89
 
######################################################################
90
 
# Install buildout
91
 
 
92
 
ws  = pkg_resources.working_set
93
 
 
94
 
cmd = [sys.executable, '-c',
95
 
       'from setuptools.command.easy_install import main; main()',
96
 
       '-mZqNxd', tmpeggs]
97
 
 
98
 
find_links = os.environ.get(
99
 
    'bootstrap-testing-find-links',
100
 
    options.find_links or
101
 
    ('http://downloads.buildout.org/'
102
 
     if options.accept_buildout_test_releases else None)
103
 
    )
 
180
cmd = [quote(sys.executable),
 
181
       '-c',
 
182
       quote('from setuptools.command.easy_install import main; main()'),
 
183
       '-mqNxd',
 
184
       quote(eggs_dir)]
 
185
 
 
186
if not has_broken_dash_S:
 
187
    cmd.insert(1, '-S')
 
188
 
 
189
find_links = options.download_base
 
190
if not find_links:
 
191
    find_links = os.environ.get('bootstrap-testing-find-links')
 
192
if not find_links and options.accept_buildout_test_releases:
 
193
    find_links = 'http://downloads.buildout.org/'
104
194
if find_links:
105
 
    cmd.extend(['-f', find_links])
 
195
    cmd.extend(['-f', quote(find_links)])
106
196
 
107
 
distribute_path = ws.find(
108
 
    pkg_resources.Requirement.parse('distribute')).location
 
197
if options.use_distribute:
 
198
    setup_requirement = 'distribute'
 
199
else:
 
200
    setup_requirement = 'setuptools'
 
201
ws = pkg_resources.working_set
 
202
setup_requirement_path = ws.find(
 
203
    pkg_resources.Requirement.parse(setup_requirement)).location
 
204
env = dict(
 
205
    os.environ,
 
206
    PYTHONPATH=setup_requirement_path)
109
207
 
110
208
requirement = 'zc.buildout'
111
209
version = options.version
113
211
    # Figure out the most recent final version of zc.buildout.
114
212
    import setuptools.package_index
115
213
    _final_parts = '*final-', '*final'
 
214
 
116
215
    def _final_version(parsed_version):
117
216
        for part in parsed_version:
118
217
            if (part[:1] == '*') and (part not in _final_parts):
119
218
                return False
120
219
        return True
121
220
    index = setuptools.package_index.PackageIndex(
122
 
        search_path=[distribute_path])
 
221
        search_path=[setup_requirement_path])
123
222
    if find_links:
124
223
        index.add_find_links((find_links,))
125
224
    req = pkg_resources.Requirement.parse(requirement)
128
227
        bestv = None
129
228
        for dist in index[req.project_name]:
130
229
            distv = dist.parsed_version
 
230
            if distv >= pkg_resources.parse_version('2dev'):
 
231
                continue
131
232
            if _final_version(distv):
132
233
                if bestv is None or distv > bestv:
133
234
                    best = [dist]
137
238
        if best:
138
239
            best.sort()
139
240
            version = best[-1].version
 
241
 
140
242
if version:
141
 
    requirement = '=='.join((requirement, version))
 
243
    requirement += '=='+version
 
244
else:
 
245
    requirement += '<2dev'
 
246
 
142
247
cmd.append(requirement)
143
248
 
144
 
import subprocess
145
 
if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
146
 
    raise Exception(
147
 
        "Failed to execute command:\n%s",
148
 
        repr(cmd)[1:-1])
149
 
 
150
 
######################################################################
151
 
# Import and run buildout
152
 
 
153
 
ws.add_entry(tmpeggs)
 
249
if is_jython:
 
250
    import subprocess
 
251
    exitcode = subprocess.Popen(cmd, env=env).wait()
 
252
else:  # Windows prefers this, apparently; otherwise we would prefer subprocess
 
253
    exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
 
254
if exitcode != 0:
 
255
    sys.stdout.flush()
 
256
    sys.stderr.flush()
 
257
    print ("An error occurred when trying to install zc.buildout. "
 
258
           "Look above this message for any errors that "
 
259
           "were output by easy_install.")
 
260
    sys.exit(exitcode)
 
261
 
 
262
ws.add_entry(eggs_dir)
154
263
ws.require(requirement)
155
264
import zc.buildout.buildout
156
265
 
 
266
# If there isn't already a command in the args, add bootstrap
157
267
if not [a for a in args if '=' not in a]:
158
268
    args.append('bootstrap')
159
269
 
160
 
# if -c was provided, we push it back into args for buildout' main function
 
270
 
 
271
# if -c was provided, we push it back into args for buildout's main function
161
272
if options.config_file is not None:
162
273
    args[0:0] = ['-c', options.config_file]
163
274
 
164
275
zc.buildout.buildout.main(args)
165
 
shutil.rmtree(tmpeggs)
 
276
if not options.eggs:  # clean up temporary egg directory
 
277
    shutil.rmtree(eggs_dir)