~launchpad-pqm/launchpad/devel

8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
1
##############################################################################
2
#
3
# Copyright (c) 2006 Zope Corporation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""Bootstrap a buildout-based project
15
16
Simply run this script in a directory containing a buildout.cfg.
17
The script accepts buildout command-line options, so you can
18
use the -c option to specify an alternate configuration file.
19
10303.1.10 by Gary Poster
update to newer version of buildout branch
20
$Id$
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
21
"""
22
10303.1.10 by Gary Poster
update to newer version of buildout branch
23
import os, shutil, sys, tempfile, textwrap, urllib, urllib2
24
from optparse import OptionParser
25
26
if sys.platform == 'win32':
27
    def quote(c):
28
        if ' ' in c:
29
            return '"%s"' % c # work around spawn lamosity on windows
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
30
        else:
10303.1.10 by Gary Poster
update to newer version of buildout branch
31
            return c
32
else:
33
    quote = str
34
35
# In order to be more robust in the face of system Pythons, we want to
36
# run without site-packages loaded.  This is somewhat tricky, in
37
# particular because Python 2.6's distutils imports site, so starting
38
# with the -S flag is not sufficient.  However, we'll start with that:
39
if 'site' in sys.modules:
40
    # We will restart with python -S.
41
    args = sys.argv[:]
42
    args[0:0] = [sys.executable, '-S']
43
    args = map(quote, args)
44
    os.execv(sys.executable, args)
45
# Now we are running with -S.  We'll get the clean sys.path, import site
46
# because distutils will do it later, and then reset the path and clean
47
# out any namespace packages from site-packages that might have been
48
# loaded by .pth files.
49
clean_path = sys.path[:]
50
import site
51
sys.path[:] = clean_path
52
for k, v in sys.modules.items():
53
    if (hasattr(v, '__path__') and
54
        len(v.__path__)==1 and
55
        not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
56
        # This is a namespace package.  Remove it.
57
        sys.modules.pop(k)
58
59
is_jython = sys.platform.startswith('java')
60
61
setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
62
distribute_source = 'http://python-distribute.org/distribute_setup.py'
63
64
# parsing arguments
65
def normalize_to_url(option, opt_str, value, parser):
66
    if value:
67
        if '://' not in value: # It doesn't smell like a URL.
68
            value = 'file://%s' % (
69
                urllib.pathname2url(
70
                    os.path.abspath(os.path.expanduser(value))),)
71
        if opt_str == '--download-base' and not value.endswith('/'):
72
            # Download base needs a trailing slash to make the world happy.
73
            value += '/'
74
    else:
75
        value = None
76
    name = opt_str[2:].replace('-', '_')
77
    setattr(parser.values, name, value)
78
79
usage = '''\
80
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
81
82
Bootstraps a buildout-based project.
83
84
Simply run this script in a directory containing a buildout.cfg, using the
85
Python that you want bin/buildout to use.
86
87
Note that by using --setup-source and --download-base to point to
88
local resources, you can keep this script from going over the network.
89
'''
90
91
parser = OptionParser(usage=usage)
92
parser.add_option("-v", "--version", dest="version",
93
                          help="use a specific zc.buildout version")
94
parser.add_option("-d", "--distribute",
95
                   action="store_true", dest="use_distribute", default=False,
96
                   help="Use Distribute rather than Setuptools.")
97
parser.add_option("--setup-source", action="callback", dest="setup_source",
98
                  callback=normalize_to_url, nargs=1, type="string",
99
                  help=("Specify a URL or file location for the setup file. "
100
                        "If you use Setuptools, this will default to " +
101
                        setuptools_source + "; if you use Distribute, this "
102
                        "will default to " + distribute_source +"."))
103
parser.add_option("--download-base", action="callback", dest="download_base",
104
                  callback=normalize_to_url, nargs=1, type="string",
105
                  help=("Specify a URL or directory for downloading "
106
                        "zc.buildout and either Setuptools or Distribute. "
107
                        "Defaults to PyPI."))
108
parser.add_option("--eggs",
109
                  help=("Specify a directory for storing eggs.  Defaults to "
110
                        "a temporary directory that is deleted when the "
111
                        "bootstrap script completes."))
112
parser.add_option("-c", None, action="store", dest="config_file",
113
                   help=("Specify the path to the buildout configuration "
114
                         "file to be used."))
115
116
options, args = parser.parse_args()
117
118
# if -c was provided, we push it back into args for buildout' main function
119
if options.config_file is not None:
120
    args += ['-c', options.config_file]
121
122
if options.eggs:
123
    eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
124
else:
125
    eggs_dir = tempfile.mkdtemp()
126
127
if options.setup_source is None:
128
    if options.use_distribute:
129
        options.setup_source = distribute_source
130
    else:
131
        options.setup_source = setuptools_source
132
133
args = args + ['bootstrap']
134
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
135
136
try:
10303.1.10 by Gary Poster
update to newer version of buildout branch
137
    to_reload = False
138
    import pkg_resources
139
    to_reload = True
140
    if not hasattr(pkg_resources, '_distribute'):
141
        raise ImportError
8926.1.1 by Gary Poster
handle a couple more site-packages issues; one if pkg_resources is around but setuptools is not; and the other to make developing an egg have the same sys.path as bin/buildout
142
    import setuptools # A flag.  Sometimes pkg_resources is installed alone.
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
143
except ImportError:
10303.1.10 by Gary Poster
update to newer version of buildout branch
144
    ez_code = urllib2.urlopen(
145
        options.setup_source).read().replace('\r\n', '\n')
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
146
    ez = {}
10303.1.10 by Gary Poster
update to newer version of buildout branch
147
    exec ez_code in ez
148
    setup_args = dict(to_dir=eggs_dir, download_delay=0)
149
    if options.download_base:
150
        setup_args['download_base'] = options.download_base
151
    if options.use_distribute:
152
        setup_args['no_fake'] = True
153
    ez['use_setuptools'](**setup_args)
154
    if to_reload:
155
        reload(pkg_resources)
156
    else:
157
        import pkg_resources
8926.1.1 by Gary Poster
handle a couple more site-packages issues; one if pkg_resources is around but setuptools is not; and the other to make developing an egg have the same sys.path as bin/buildout
158
    # This does not (always?) update the default working set.  We will
159
    # do it.
160
    for path in sys.path:
161
        if path not in pkg_resources.working_set.entries:
162
            pkg_resources.working_set.add_entry(path)
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
163
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
164
cmd = [quote(sys.executable),
165
       '-c',
166
       quote('from setuptools.command.easy_install import main; main()'),
167
       '-mqNxd',
10303.1.10 by Gary Poster
update to newer version of buildout branch
168
       quote(eggs_dir)]
169
170
if options.download_base:
171
    cmd.extend(['-f', quote(options.download_base)])
172
173
requirement = 'zc.buildout'
174
if options.version:
175
    requirement = '=='.join((requirement, options.version))
8827.2.3 by Gary Poster
put in new zc.buildout eggs
176
cmd.append(requirement)
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
177
10303.1.10 by Gary Poster
update to newer version of buildout branch
178
if options.use_distribute:
179
    setup_requirement = 'distribute'
180
else:
181
    setup_requirement = 'setuptools'
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
182
ws = pkg_resources.working_set
183
env = dict(
184
    os.environ,
10303.1.10 by Gary Poster
update to newer version of buildout branch
185
    PYTHONPATH=ws.find(
186
        pkg_resources.Requirement.parse(setup_requirement)).location)
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
187
8827.2.2 by Gary Poster
use temporary, local eggs for buildout work.
188
if is_jython:
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
189
    import subprocess
8827.2.2 by Gary Poster
use temporary, local eggs for buildout work.
190
    exitcode = subprocess.Popen(cmd, env=env).wait()
10303.1.10 by Gary Poster
update to newer version of buildout branch
191
else: # Windows prefers this, apparently; otherwise we would prefer subprocess
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
192
    exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
193
if exitcode != 0:
8827.2.4 by Gary Poster
try to make ec2test happy, and fix up a bootstrap bug.
194
    sys.stdout.flush()
10303.1.10 by Gary Poster
update to newer version of buildout branch
195
    sys.stderr.flush()
8827.2.2 by Gary Poster
use temporary, local eggs for buildout work.
196
    print ("An error occured when trying to install zc.buildout. "
197
           "Look above this message for any errors that "
198
           "were output by easy_install.")
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
199
    sys.exit(exitcode)
8697.27.1 by Gary Poster
bugfixes for problems revealed in ec2test
200
10303.1.10 by Gary Poster
update to newer version of buildout branch
201
ws.add_entry(eggs_dir)
8827.2.3 by Gary Poster
put in new zc.buildout eggs
202
ws.require(requirement)
8234.1.2 by Gary Poster
checkpoint: this initial buildout variant has several parts working, including run, start, stop, and harness.
203
import zc.buildout.buildout
8827.2.1 by Gary Poster
use experimental eggs for buildout and friends
204
zc.buildout.buildout.main(args)
10303.1.10 by Gary Poster
update to newer version of buildout branch
205
if not options.eggs: # clean up temporary egg directory
206
    shutil.rmtree(eggs_dir)