Commit d7c5f3fb authored by Gary Poster's avatar Gary Poster

merge of gary-2-bootstrap-changes into trunk, resolving lots of conflicts with...

merge of gary-2-bootstrap-changes into trunk, resolving lots of conflicts with the distribute changes.
parent 3b233592
Change History Change History
************** **************
1.4.4 (?) 1.?.? (201?-??-??)
========= ==================
New Features:
- Improve bootstrap.
* New options let you specify where to find ez_setup.py and where to find
a download cache. These options can keep bootstrap from going over the
network.
* Another new option lets you specify where to put generated eggs.
* The buildout script generated by bootstrap honors more of the settings
in the designated configuration file (e.g., buildout.cfg).
1.4.3 (2009-12-10) 1.4.3 (2009-12-10)
================== ==================
......
...@@ -20,21 +20,62 @@ use the -c option to specify an alternate configuration file. ...@@ -20,21 +20,62 @@ use the -c option to specify an alternate configuration file.
$Id$ $Id$
""" """
import os, shutil, sys, tempfile, urllib2 import os, shutil, sys, tempfile, textwrap, urllib, urllib2
from optparse import OptionParser from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
is_jython = sys.platform.startswith('java') is_jython = sys.platform.startswith('java')
setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
distribute_source = 'http://python-distribute.org/distribute_setup.py'
# parsing arguments # parsing arguments
parser = OptionParser() def normalize_to_url(option, opt_str, value, parser):
if value:
if '://' not in value: # It doesn't smell like a URL.
value = 'file://%s' % (
urllib.pathname2url(
os.path.abspath(os.path.expanduser(value))),)
if opt_str == '--download-base' and not value.endswith('/'):
# Download base needs a trailing slash to make the world happy.
value += '/'
else:
value = None
name = opt_str[2:].replace('-', '_')
setattr(parser.values, name, value)
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.
Note that by using --setup-source and --download-base to point to
local resources, you can keep this script from going over the network.
'''
parser = OptionParser(usage=usage)
parser.add_option("-v", "--version", dest="version", parser.add_option("-v", "--version", dest="version",
help="use a specific zc.buildout version") help="use a specific zc.buildout version")
parser.add_option("-d", "--distribute", parser.add_option("-d", "--distribute",
action="store_true", dest="distribute", default=False, action="store_true", dest="use_distribute", default=False,
help="Use Disribute rather than Setuptools.") help="Use Distribute rather than Setuptools.")
parser.add_option("--setup-source", action="callback", dest="setup_source",
callback=normalize_to_url, nargs=1, type="string",
help=("Specify a URL or file location for the setup file. "
"If you use Setuptools, this will default to " +
setuptools_source + "; if you use Distribute, this "
"will default to " + distribute_source +"."))
parser.add_option("--download-base", action="callback", dest="download_base",
callback=normalize_to_url, nargs=1, type="string",
help=("Specify a URL or directory for downloading "
"zc.buildout and either Setuptools or Distribute. "
"Defaults to PyPI."))
parser.add_option("--eggs",
help=("Specify a directory for storing eggs. Defaults to "
"a temporary directory that is deleted when the "
"bootstrap script completes."))
parser.add_option("-c", None, action="store", dest="config_file", parser.add_option("-c", None, action="store", dest="config_file",
help=("Specify the path to the buildout configuration " help=("Specify the path to the buildout configuration "
"file to be used.")) "file to be used."))
...@@ -45,35 +86,46 @@ options, args = parser.parse_args() ...@@ -45,35 +86,46 @@ options, args = parser.parse_args()
if options.config_file is not None: if options.config_file is not None:
args += ['-c', options.config_file] args += ['-c', options.config_file]
if options.version is not None: if options.eggs:
VERSION = '==%s' % options.version eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
else: else:
VERSION = '' eggs_dir = tempfile.mkdtemp()
if options.setup_source is None:
if options.use_distribute:
options.setup_source = distribute_source
else:
options.setup_source = setuptools_source
USE_DISTRIBUTE = options.distribute
args = args + ['bootstrap'] args = args + ['bootstrap']
to_reload = False to_reload = False
try: try:
import setuptools # A flag. Sometimes pkg_resources is installed alone.
import pkg_resources import pkg_resources
if not hasattr(pkg_resources, '_distribute'): if not hasattr(pkg_resources, '_distribute'):
to_reload = True to_reload = True
raise ImportError raise ImportError
except ImportError: except ImportError:
ez = {} ez = {}
if USE_DISTRIBUTE: exec urllib2.urlopen(options.setup_source).read() in ez
exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' setup_args = dict(to_dir=eggs_dir, download_delay=0)
).read() in ez if options.download_base:
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) setup_args['download_base'] = options.download_base
else: if options.use_distribute:
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' setup_args['no_fake'] = True
).read() in ez ez['use_setuptools'](**setup_args)
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
if to_reload: if to_reload:
reload(pkg_resources) reload(pkg_resources)
else: else:
import pkg_resources 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)
if sys.platform == 'win32': if sys.platform == 'win32':
def quote(c): def quote(c):
...@@ -85,37 +137,46 @@ else: ...@@ -85,37 +137,46 @@ else:
def quote (c): def quote (c):
return c return c
cmd = 'from setuptools.command.easy_install import main; main()' cmd = [quote(sys.executable),
ws = pkg_resources.working_set '-c',
quote('from setuptools.command.easy_install import main; main()'),
'-mqNxd',
quote(eggs_dir)]
if options.download_base:
cmd.extend(['-f', quote(options.download_base)])
if USE_DISTRIBUTE: requirement = 'zc.buildout'
requirement = 'distribute' if options.version:
requirement = '=='.join((requirement, options.version))
cmd.append(requirement)
if options.use_distribute:
setup_requirement = 'distribute'
else: else:
requirement = 'setuptools' setup_requirement = 'setuptools'
ws = pkg_resources.working_set
env = dict(
os.environ,
PYTHONPATH=ws.find(
pkg_resources.Requirement.parse(setup_requirement)).location)
if is_jython: if is_jython:
import subprocess import subprocess
exitcode = subprocess.Popen(cmd, env=env).wait()
assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', else: # Windows prefers this, apparently; otherwise we would prefer subprocess
quote(tmpeggs), 'zc.buildout' + VERSION], exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
env=dict(os.environ, if exitcode != 0:
PYTHONPATH= sys.stdout.flush()
ws.find(pkg_resources.Requirement.parse(requirement)).location sys.stderr.flush()
), print ("An error occured when trying to install zc.buildout. "
).wait() == 0 "Look above this message for any errors that "
"were output by easy_install.")
else: sys.exit(exitcode)
assert os.spawnle(
os.P_WAIT, sys.executable, quote (sys.executable), ws.add_entry(eggs_dir)
'-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION, ws.require(requirement)
dict(os.environ,
PYTHONPATH=
ws.find(pkg_resources.Requirement.parse(requirement)).location
),
) == 0
ws.add_entry(tmpeggs)
ws.require('zc.buildout' + VERSION)
import zc.buildout.buildout import zc.buildout.buildout
zc.buildout.buildout.main(args) zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs) if not options.eggs: # clean up temporary egg directory
shutil.rmtree(eggs_dir)
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
############################################################################## ##############################################################################
"""Bootstrap the buildout project itself. """Bootstrap the buildout project itself.
This is different from a normal boostrapping process because the This is different from a normal bootstrapping process because the
buildout egg itself is installed as a develop egg. buildout egg itself is installed as a develop egg.
$Id$ $Id$
......
...@@ -57,7 +57,7 @@ Let's try with an unknown version:: ...@@ -57,7 +57,7 @@ Let's try with an unknown version::
... 'bootstrap.py --version UNKNOWN'); print 'X' # doctest: +ELLIPSIS ... 'bootstrap.py --version UNKNOWN'); print 'X' # doctest: +ELLIPSIS
... ...
X X
No local packages or download links found for zc.buildout==UNKNOWN No local packages or download links found for zc.buildout==UNKNOWN...
... ...
Now let's try with `1.1.2`, which happens to exist:: Now let's try with `1.1.2`, which happens to exist::
...@@ -119,8 +119,8 @@ Let's make sure the generated `buildout` script uses it:: ...@@ -119,8 +119,8 @@ Let's make sure the generated `buildout` script uses it::
zc.buildout.buildout.main() zc.buildout.buildout.main()
<BLANKLINE> <BLANKLINE>
`zc.buildout` now can also run with `Distribute` with the `--distribute` option:: `zc.buildout` now can also run with `Distribute` with the `--distribute`
option::
>>> print 'X'; print system( >>> print 'X'; print system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
...@@ -153,7 +153,8 @@ Make sure both options can be used together:: ...@@ -153,7 +153,8 @@ Make sure both options can be used together::
>>> print 'X'; print system( >>> print 'X'; print system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --distribute --version 1.2.1'); print 'X' # doctest: +ELLIPSIS ... 'bootstrap.py --distribute --version 1.2.1'); print 'X'
... # doctest: +ELLIPSIS
... ...
X X
... ...
...@@ -161,7 +162,8 @@ Make sure both options can be used together:: ...@@ -161,7 +162,8 @@ Make sure both options can be used together::
<BLANKLINE> <BLANKLINE>
X X
Let's make sure the generated `buildout` script uses ``Distribute`` *and* ``zc.buildout-1.2.1``:: Let's make sure the generated `buildout` script uses ``Distribute`` *and*
``zc.buildout-1.2.1``::
>>> print open(buildout_script).read() # doctest: +ELLIPSIS >>> print open(buildout_script).read() # doctest: +ELLIPSIS
#... #...
...@@ -194,4 +196,70 @@ Last, the -c option needs to work on bootstrap.py:: ...@@ -194,4 +196,70 @@ Last, the -c option needs to work on bootstrap.py::
<BLANKLINE> <BLANKLINE>
X X
You can specify a location of ez_setup.py or distribute_setup, so you
can rely on a local or remote location. We'll write our own ez_setup.py
that we will also use to test some other bootstrap options.
>>> write('ez_setup.py', '''\
... def use_setuptools(**kwargs):
... import sys, pprint
... pprint.pprint(kwargs, width=40)
... sys.exit()
... ''')
>>> print system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --setup-source=./ez_setup.py')
... # doctest: +ELLIPSIS
{'download_delay': 0,
'to_dir': '...'}
<BLANKLINE>
You can also pass a download-cache, and a place in which eggs should be stored
(they are normally stored in a temporary directory).
>>> print system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --setup-source=./ez_setup.py '+
... '--download-base=./download-cache --eggs=eggs')
... # doctest: +ELLIPSIS
{'download_base': '/sample/download-cache/',
'download_delay': 0,
'to_dir': '/sample/eggs'}
<BLANKLINE>
Here's the entire help text.
>>> print system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --help'),
... # doctest: +ELLIPSIS
usage: [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
<BLANKLINE>
Bootstraps a buildout-based project.
<BLANKLINE>
Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.
<BLANKLINE>
Note that by using --setup-source and --download-base to point to
local resources, you can keep this script from going over the network.
<BLANKLINE>
<BLANKLINE>
options:
-h, --help show this help message and exit
-v VERSION, --version=VERSION
use a specific zc.buildout version
-d, --distribute Use Distribute rather than Setuptools.
--setup-source=SETUP_SOURCE
Specify a URL or file location for the setup file. If
you use Setuptools, this will default to
http://peak.telecommunity.com/dist/ez_setup.py; if you
use Distribute, this will default to http://python-
distribute.org/distribute_setup.py.
--download-base=DOWNLOAD_BASE
Specify a URL or directory for downloading zc.buildout
and either Setuptools or Distribute. Defaults to PyPI.
--eggs=EGGS Specify a directory for storing eggs. Defaults to a
temporary directory that is deleted when the bootstrap
script completes.
-c CONFIG_FILE Specify the path to the buildout configuration file to
be used.
...@@ -338,11 +338,32 @@ class Buildout(UserDict.DictMixin): ...@@ -338,11 +338,32 @@ class Buildout(UserDict.DictMixin):
self._setup_directories() self._setup_directories()
options = self['buildout']
# Get a base working set for our distributions that corresponds to the
# stated desires in the configuration.
distributions = ['setuptools', 'zc.buildout']
if options.get('offline') == 'true':
ws = zc.buildout.easy_install.working_set(
distributions, options['executable'],
[options['develop-eggs-directory'], options['eggs-directory']]
)
else:
ws = zc.buildout.easy_install.install(
distributions, options['eggs-directory'],
links=self._links,
index=options.get('index'),
executable=options['executable'],
path=[options['develop-eggs-directory']],
newest=self.newest,
allow_hosts=self._allow_hosts
)
# Now copy buildout and setuptools eggs, and record destination eggs: # Now copy buildout and setuptools eggs, and record destination eggs:
entries = [] entries = []
for name in 'setuptools', 'zc.buildout': for name in 'setuptools', 'zc.buildout':
r = pkg_resources.Requirement.parse(name) r = pkg_resources.Requirement.parse(name)
dist = pkg_resources.working_set.find(r) dist = ws.find(r)
if dist.precedence == pkg_resources.DEVELOP_DIST: if dist.precedence == pkg_resources.DEVELOP_DIST:
dest = os.path.join(self['buildout']['develop-eggs-directory'], dest = os.path.join(self['buildout']['develop-eggs-directory'],
name+'.egg-link') name+'.egg-link')
...@@ -362,8 +383,8 @@ class Buildout(UserDict.DictMixin): ...@@ -362,8 +383,8 @@ class Buildout(UserDict.DictMixin):
ws = pkg_resources.WorkingSet(entries) ws = pkg_resources.WorkingSet(entries)
ws.require('zc.buildout') ws.require('zc.buildout')
zc.buildout.easy_install.scripts( zc.buildout.easy_install.scripts(
['zc.buildout'], ws, sys.executable, ['zc.buildout'], ws, options['executable'],
self['buildout']['bin-directory']) options['bin-directory'])
init = bootstrap init = bootstrap
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment