Commit a9519d25 authored by Gary Poster's avatar Gary Poster

merge buildout trunk with system python support branches.

parent 2bf8b65c
.installed.cfg
bin
build
develop-eggs
eggs
parts
src/zc.buildout.egg-info
z3c.recipe.scripts_/src/z3c.recipe.scripts.egg-info
zc.recipe.egg_/src/zc.recipe.egg.egg-info
Change History Change History
************** **************
1.4.4 (?)
=========
New feature: 1.?.? (201?-??-??)
==================
New Features:
- Added buildout:socket-timout option so that socket timeout can be configured - Added buildout:socket-timout option so that socket timeout can be configured
both from command line and from config files. (gotcha) both from command line and from config files. (gotcha)
- Buildout can be safely used with a system Python (or any Python with code
in site-packages), as long as you use the new z3c.recipe.scripts
recipe to generate scripts and interpreters, rather than zc.recipe.egg.
zc.recipe.egg is still a fully supported, and simpler, way of
generating scripts and interpreters if you are using a "clean" Python,
without code installed in site-packages. It keeps its previous behavior in
order to provide backwards compatibility.
The z3c.recipe.scripts recipe allows you to control how you use the
code in site-packages. You can exclude it entirely; allow eggs in it
to fulfill package dependencies declared in setup.py and buildout
configuration; allow it to be available but not used to fulfill
dependencies declared in setup.py or buildout configuration; or only
allow certain eggs in site-packages to fulfill dependencies.
- Added new function, ``zc.buildout.easy_install.sitepackage_safe_scripts``,
to generate scripts and interpreter. It produces a full-featured
interpreter (all command-line options supported) and the ability to
safely let scripts include site packages, such as with a system
Python. The ``z3c.recipe.scripts`` recipe uses this new function.
- 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).
Bugs fixed:
- The handling and documenting of default buildout options was normalized.
This means, among other things, that ``bin/buildout -vv`` and
``bin/buildout annotate`` correctly list more of the options.
- Installing a namespace package using a Python that already has a package
in the same namespace (e.g., in the Python's site-packages) failed in
some cases.
- Another variation of this error showed itself when at least two
dependencies were in a shared location like site-packages, and the
first one met the "versions" setting. The first dependency would be
added, but subsequent dependencies from the same location (e.g.,
site-packages) would use the version of the package found in the
shared location, ignoring the version setting.
1.4.3 (2009-12-10) 1.4.3 (2009-12-10)
================== ==================
......
...@@ -35,7 +35,15 @@ Existing recipes include: ...@@ -35,7 +35,15 @@ Existing recipes include:
`zc.recipe.egg <http://pypi.python.org/pypi/zc.recipe.egg>`_ `zc.recipe.egg <http://pypi.python.org/pypi/zc.recipe.egg>`_
The egg recipe installes one or more eggs, with their The egg recipe installes one or more eggs, with their
dependencies. It installs their console-script entry points with dependencies. It installs their console-script entry points with
the needed eggs included in their paths. the needed eggs included in their paths. It is suitable for use with
a "clean" Python: one without packages installed in site-packages.
`z3c.recipe.scripts <http://pypi.python.org/pypi/z3c.recipe.scripts>`_
Like zc.recipe.egg, this recipe builds interpreter scripts and entry
point scripts based on eggs. It can be used with a Python that has
packages installed in site-packages, such as a system Python. The
interpreter also has more features than the one offered by
zc.recipe.egg.
`zc.recipe.testrunner <http://pypi.python.org/pypi/zc.recipe.testrunner>`_ `zc.recipe.testrunner <http://pypi.python.org/pypi/zc.recipe.testrunner>`_
The testrunner egg creates a test runner script for one or The testrunner egg creates a test runner script for one or
......
...@@ -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 Distribute 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,47 @@ options, args = parser.parse_args() ...@@ -45,35 +86,47 @@ 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
try: try:
to_reload = False
import pkg_resources import pkg_resources
to_reload = True
if not hasattr(pkg_resources, '_distribute'): if not hasattr(pkg_resources, '_distribute'):
to_reload = True
raise ImportError raise ImportError
import setuptools # A flag. Sometimes pkg_resources is installed alone.
except ImportError: except ImportError:
ez_code = urllib2.urlopen(
options.setup_source).read().replace('\r\n', '\n')
ez = {} ez = {}
if USE_DISTRIBUTE: exec ez_code 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 +138,46 @@ else: ...@@ -85,37 +138,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)
[buildout] [buildout]
develop = zc.recipe.egg_ . develop = zc.recipe.egg_ z3c.recipe.scripts_ .
parts = test oltest py parts = test oltest py
[py] [py]
...@@ -13,6 +13,7 @@ recipe = zc.recipe.testrunner ...@@ -13,6 +13,7 @@ recipe = zc.recipe.testrunner
eggs = eggs =
zc.buildout zc.buildout
zc.recipe.egg zc.recipe.egg
z3c.recipe.scripts
# Tests that can be run wo a network # Tests that can be run wo a network
[oltest] [oltest]
...@@ -20,6 +21,7 @@ recipe = zc.recipe.testrunner ...@@ -20,6 +21,7 @@ recipe = zc.recipe.testrunner
eggs = eggs =
zc.buildout zc.buildout
zc.recipe.egg zc.recipe.egg
z3c.recipe.scripts
defaults = defaults =
[ [
'-t', '-t',
......
...@@ -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$
...@@ -31,7 +31,10 @@ if os.path.isdir('build'): ...@@ -31,7 +31,10 @@ if os.path.isdir('build'):
shutil.rmtree('build') shutil.rmtree('build')
try: try:
to_reload = False
import pkg_resources import pkg_resources
to_reload = True
import setuptools # A flag. Sometimes pkg_resources is installed alone.
except ImportError: except ImportError:
ez = {} ez = {}
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
...@@ -39,11 +42,15 @@ except ImportError: ...@@ -39,11 +42,15 @@ except ImportError:
ez['use_setuptools'](to_dir='eggs', download_delay=0) ez['use_setuptools'](to_dir='eggs', download_delay=0)
import pkg_resources import pkg_resources
if to_reload:
reload(pkg_resources)
env = os.environ.copy() # Windows needs yet-to-be-determined values from this.
env['PYTHONPATH'] = os.path.dirname(pkg_resources.__file__)
subprocess.Popen( subprocess.Popen(
[sys.executable] + [sys.executable] +
['setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs'], ['setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs'],
env = {'PYTHONPATH': os.path.dirname(pkg_resources.__file__)}).wait() env=env).wait()
pkg_resources.working_set.add_entry('src') pkg_resources.working_set.add_entry('src')
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# #
############################################################################## ##############################################################################
name = "zc.buildout" name = "zc.buildout"
version = "1.4.4dev" version = "1.5.0dev"
import os import os
from setuptools import setup from setuptools import setup
......
...@@ -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 +NORMALIZE_WHITESPACE
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.
This diff is collapsed.
...@@ -56,10 +56,9 @@ The bin directory contains scripts. ...@@ -56,10 +56,9 @@ The bin directory contains scripts.
- setuptools-0.6-py2.4.egg - setuptools-0.6-py2.4.egg
- zc.buildout-1.0-py2.4.egg - zc.buildout-1.0-py2.4.egg
The develop-eggs and parts directories are initially empty: The develop-eggs directory is initially empty:
>>> ls(sample_buildout, 'develop-eggs') >>> ls(sample_buildout, 'develop-eggs')
>>> ls(sample_buildout, 'parts')
The develop-eggs directory holds egg links for software being The develop-eggs directory holds egg links for software being
developed in the buildout. We separate develop-eggs and other eggs to developed in the buildout. We separate develop-eggs and other eggs to
...@@ -69,6 +68,12 @@ directory in their home that all non-develop eggs are stored in. This ...@@ -69,6 +68,12 @@ directory in their home that all non-develop eggs are stored in. This
allows larger buildouts to be set up much more quickly and saves disk allows larger buildouts to be set up much more quickly and saves disk
space. space.
The parts directory just contains some helpers for the buildout script
itself.
>>> ls(sample_buildout, 'parts')
d buildout
The parts directory provides an area where recipes can install The parts directory provides an area where recipes can install
part data. For example, if we built a custom Python, we would part data. For example, if we built a custom Python, we would
install it in the part directory. Part data is stored in a install it in the part directory. Part data is stored in a
...@@ -576,7 +581,7 @@ When we rerun the buildout: ...@@ -576,7 +581,7 @@ When we rerun the buildout:
.. Wait for the file to really disappear. My linux is weird. .. Wait for the file to really disappear. My linux is weird.
>>> wait_until("foo goes away", lambda : not os.path.exists('foo'), >>> wait_until("foo goes away", lambda : not os.path.exists('foo'),
... timeout=100) ... timeout=200)
we get the same error, but we don't get the directory left behind: we get the same error, but we don't get the directory left behind:
...@@ -724,6 +729,10 @@ COMMAND_LINE_VALUE). ...@@ -724,6 +729,10 @@ COMMAND_LINE_VALUE).
================== ==================
<BLANKLINE> <BLANKLINE>
[buildout] [buildout]
allow-hosts= *
DEFAULT_VALUE
allow-picked-versions= true
DEFAULT_VALUE
bin-directory= bin bin-directory= bin
DEFAULT_VALUE DEFAULT_VALUE
develop= recipes develop= recipes
...@@ -736,19 +745,33 @@ COMMAND_LINE_VALUE). ...@@ -736,19 +745,33 @@ COMMAND_LINE_VALUE).
DEFAULT_VALUE DEFAULT_VALUE
executable= ... executable= ...
DEFAULT_VALUE DEFAULT_VALUE
find-links=
DEFAULT_VALUE
install-from-cache= false
DEFAULT_VALUE
installed= .installed.cfg installed= .installed.cfg
DEFAULT_VALUE DEFAULT_VALUE
log-format= log-format=
DEFAULT_VALUE DEFAULT_VALUE
log-level= INFO log-level= INFO
DEFAULT_VALUE DEFAULT_VALUE
newest= true
DEFAULT_VALUE
offline= false
DEFAULT_VALUE
parts= data-dir parts= data-dir
/sample-buildout/buildout.cfg /sample-buildout/buildout.cfg
parts-directory= parts parts-directory= parts
DEFAULT_VALUE DEFAULT_VALUE
prefer-final= false
DEFAULT_VALUE
python= buildout python= buildout
DEFAULT_VALUE DEFAULT_VALUE
socket-timeout= socket-timeout=
DEFAULT_VALUE
unzip= false
DEFAULT_VALUE
use-dependency-links= true
DEFAULT_VALUE DEFAULT_VALUE
<BLANKLINE> <BLANKLINE>
[data-dir] [data-dir]
...@@ -2246,17 +2269,21 @@ database is shown. ...@@ -2246,17 +2269,21 @@ database is shown.
>>> print system(buildout+' -vv'), # doctest: +NORMALIZE_WHITESPACE >>> print system(buildout+' -vv'), # doctest: +NORMALIZE_WHITESPACE
Installing 'zc.buildout', 'setuptools'. Installing 'zc.buildout', 'setuptools'.
We have a develop egg: zc.buildout 1.0.0. We have a develop egg: zc.buildout X.X.
We have the best distribution that satisfies 'setuptools'. We have the best distribution that satisfies 'setuptools'.
Picked: setuptools = 0.6 Picked: setuptools = 0.6
<BLANKLINE> <BLANKLINE>
Configuration data: Configuration data:
[buildout] [buildout]
allow-hosts = *
allow-picked-versions = true
bin-directory = /sample-buildout/bin bin-directory = /sample-buildout/bin
develop-eggs-directory = /sample-buildout/develop-eggs develop-eggs-directory = /sample-buildout/develop-eggs
directory = /sample-buildout directory = /sample-buildout
eggs-directory = /sample-buildout/eggs eggs-directory = /sample-buildout/eggs
executable = /usr/local/bin/python2.3 executable = /usr/local/bin/python2.3
find-links =
install-from-cache = false
installed = /sample-buildout/.installed.cfg installed = /sample-buildout/.installed.cfg
log-format = log-format =
log-level = INFO log-level = INFO
...@@ -2264,8 +2291,11 @@ database is shown. ...@@ -2264,8 +2291,11 @@ database is shown.
offline = false offline = false
parts = parts =
parts-directory = /sample-buildout/parts parts-directory = /sample-buildout/parts
prefer-final = false
python = buildout python = buildout
socket-timeout = socket-timeout =
unzip = false
use-dependency-links = true
verbosity = 20 verbosity = 20
<BLANKLINE> <BLANKLINE>
......
This diff is collapsed.
This diff is collapsed.
...@@ -28,6 +28,7 @@ import socket ...@@ -28,6 +28,7 @@ import socket
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import textwrap
import threading import threading
import time import time
import urllib2 import urllib2
...@@ -109,6 +110,16 @@ def system(command, input=''): ...@@ -109,6 +110,16 @@ def system(command, input=''):
e.close() e.close()
return result return result
def call_py(interpreter, cmd, flags=None):
if sys.platform == 'win32':
args = ['"%s"' % arg for arg in (interpreter, flags, cmd) if arg]
args.insert(-1, '"-c"')
return system('"%s"' % ' '.join(args))
else:
cmd = repr(cmd)
return system(
' '.join(arg for arg in (interpreter, flags, '-c', cmd) if arg))
def get(url): def get(url):
return urllib2.urlopen(url).read() return urllib2.urlopen(url).read()
...@@ -120,7 +131,11 @@ def _runsetup(setup, executable, *args): ...@@ -120,7 +131,11 @@ def _runsetup(setup, executable, *args):
args = [zc.buildout.easy_install._safe_arg(arg) args = [zc.buildout.easy_install._safe_arg(arg)
for arg in args] for arg in args]
args.insert(0, '-q') args.insert(0, '-q')
args.append(dict(os.environ, PYTHONPATH=setuptools_location)) env = dict(os.environ)
if executable == sys.executable:
env['PYTHONPATH'] = setuptools_location
# else pass an executable that has setuptools! See testselectingpython.py.
args.append(env)
here = os.getcwd() here = os.getcwd()
try: try:
...@@ -139,6 +154,11 @@ def sdist(setup, dest): ...@@ -139,6 +154,11 @@ def sdist(setup, dest):
def bdist_egg(setup, executable, dest): def bdist_egg(setup, executable, dest):
_runsetup(setup, executable, 'bdist_egg', '-d', dest) _runsetup(setup, executable, 'bdist_egg', '-d', dest)
def sys_install(setup, dest):
_runsetup(setup, sys.executable, 'install', '--install-purelib', dest,
'--record', os.path.join(dest, '__added_files__'),
'--single-version-externally-managed')
def find_python(version): def find_python(version):
e = os.environ.get('PYTHON%s' % version) e = os.environ.get('PYTHON%s' % version)
if e is not None: if e is not None:
...@@ -206,14 +226,64 @@ def wait_until(label, func, *args, **kw): ...@@ -206,14 +226,64 @@ def wait_until(label, func, *args, **kw):
time.sleep(0.01) time.sleep(0.01)
raise ValueError('Timed out waiting for: '+label) raise ValueError('Timed out waiting for: '+label)
def get_installer_values():
"""Get the current values for the easy_install module.
This is necessary because instantiating a Buildout will force the
Buildout's values on the installer.
Returns a dict of names-values suitable for set_installer_values."""
names = ('default_versions', 'download_cache', 'install_from_cache',
'prefer_final', 'include_site_packages',
'allowed_eggs_from_site_packages', 'use_dependency_links',
'allow_picked_versions', 'always_unzip'
)
values = {}
for name in names:
values[name] = getattr(zc.buildout.easy_install, name)()
return values
def set_installer_values(values):
"""Set the given values on the installer."""
for name, value in values.items():
getattr(zc.buildout.easy_install, name)(value)
def make_buildout(executable=None):
"""Make a buildout that uses this version of zc.buildout."""
# Create a basic buildout.cfg to avoid a warning from buildout.
open('buildout.cfg', 'w').write(
"[buildout]\nparts =\n"
)
# Get state of installer defaults so we can reinstate them (instantiating
# a Buildout will force the Buildout's defaults on the installer).
installer_values = get_installer_values()
# Use the buildout bootstrap command to create a buildout
config = [
('buildout', 'log-level', 'WARNING'),
# trick bootstrap into putting the buildout develop egg
# in the eggs dir.
('buildout', 'develop-eggs-directory', 'eggs'),
]
if executable is not None:
config.append(('buildout', 'executable', executable))
zc.buildout.buildout.Buildout(
'buildout.cfg', config,
user_defaults=False,
).bootstrap([])
# Create the develop-eggs dir, which didn't get created the usual
# way due to the trick above:
os.mkdir('develop-eggs')
# Reinstate the default values of the installer.
set_installer_values(installer_values)
def buildoutSetUp(test): def buildoutSetUp(test):
test.globs['__tear_downs'] = __tear_downs = [] test.globs['__tear_downs'] = __tear_downs = []
test.globs['register_teardown'] = register_teardown = __tear_downs.append test.globs['register_teardown'] = register_teardown = __tear_downs.append
prefer_final = zc.buildout.easy_install.prefer_final() installer_values = get_installer_values()
register_teardown( register_teardown(
lambda: zc.buildout.easy_install.prefer_final(prefer_final) lambda: set_installer_values(installer_values)
) )
here = os.getcwd() here = os.getcwd()
...@@ -259,27 +329,7 @@ def buildoutSetUp(test): ...@@ -259,27 +329,7 @@ def buildoutSetUp(test):
sample = tmpdir('sample-buildout') sample = tmpdir('sample-buildout')
os.chdir(sample) os.chdir(sample)
make_buildout()
# Create a basic buildout.cfg to avoid a warning from buildout:
open('buildout.cfg', 'w').write(
"[buildout]\nparts =\n"
)
# Use the buildout bootstrap command to create a buildout
zc.buildout.buildout.Buildout(
'buildout.cfg',
[('buildout', 'log-level', 'WARNING'),
# trick bootstrap into putting the buildout develop egg
# in the eggs dir.
('buildout', 'develop-eggs-directory', 'eggs'),
]
).bootstrap([])
# Create the develop-eggs dir, which didn't get created the usual
# way due to the trick above:
os.mkdir('develop-eggs')
def start_server(path): def start_server(path):
port, thread = _start_server(path, name=path) port, thread = _start_server(path, name=path)
...@@ -287,6 +337,50 @@ def buildoutSetUp(test): ...@@ -287,6 +337,50 @@ def buildoutSetUp(test):
register_teardown(lambda: stop_server(url, thread)) register_teardown(lambda: stop_server(url, thread))
return url return url
def make_py(initialization=''):
"""Returns paths to new executable and to its site-packages.
"""
buildout = tmpdir('executable_buildout')
site_packages_dir = os.path.join(buildout, 'site-packages')
mkdir(site_packages_dir)
old_wd = os.getcwd()
os.chdir(buildout)
make_buildout()
# Normally we don't process .pth files in extra-paths. We want to
# in this case so that we can test with setuptools system installs
# (--single-version-externally-managed), which use .pth files.
initialization = (
('import sys\n'
'import site\n'
'known_paths = set(sys.path)\n'
'site_packages_dir = %r\n'
'site.addsitedir(site_packages_dir, known_paths)\n'
) % (site_packages_dir,)) + initialization
initialization = '\n'.join(
' ' + line for line in initialization.split('\n'))
install_develop(
'zc.recipe.egg', os.path.join(buildout, 'develop-eggs'))
install_develop(
'z3c.recipe.scripts', os.path.join(buildout, 'develop-eggs'))
write('buildout.cfg', textwrap.dedent('''\
[buildout]
parts = py
[py]
recipe = z3c.recipe.scripts
interpreter = py
initialization =
%(initialization)s
extra-paths = %(site-packages)s
eggs = setuptools
''') % {
'initialization': initialization,
'site-packages': site_packages_dir})
system(os.path.join(buildout, 'bin', 'buildout'))
os.chdir(old_wd)
return (
os.path.join(buildout, 'bin', 'py'), site_packages_dir)
test.globs.update(dict( test.globs.update(dict(
sample_buildout = sample, sample_buildout = sample,
ls = ls, ls = ls,
...@@ -297,6 +391,7 @@ def buildoutSetUp(test): ...@@ -297,6 +391,7 @@ def buildoutSetUp(test):
tmpdir = tmpdir, tmpdir = tmpdir,
write = write, write = write,
system = system, system = system,
call_py = call_py,
get = get, get = get,
cd = (lambda *path: os.chdir(os.path.join(*path))), cd = (lambda *path: os.chdir(os.path.join(*path))),
join = os.path.join, join = os.path.join,
...@@ -305,10 +400,9 @@ def buildoutSetUp(test): ...@@ -305,10 +400,9 @@ def buildoutSetUp(test):
start_server = start_server, start_server = start_server,
buildout = os.path.join(sample, 'bin', 'buildout'), buildout = os.path.join(sample, 'bin', 'buildout'),
wait_until = wait_until, wait_until = wait_until,
make_py = make_py
)) ))
zc.buildout.easy_install.prefer_final(prefer_final)
def buildoutTearDown(test): def buildoutTearDown(test):
for f in test.globs['__tear_downs']: for f in test.globs['__tear_downs']:
f() f()
......
This diff is collapsed.
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
import os, re, sys, unittest import os, re, subprocess, sys, textwrap, unittest
from zope.testing import doctest, renormalizing from zope.testing import doctest, renormalizing
import zc.buildout.tests import zc.buildout.tests
import zc.buildout.testing import zc.buildout.testing
...@@ -42,6 +42,33 @@ We can specify a specific Python executable. ...@@ -42,6 +42,33 @@ We can specify a specific Python executable.
def multi_python(test): def multi_python(test):
other_executable = zc.buildout.testing.find_python(other_version) other_executable = zc.buildout.testing.find_python(other_version)
command = textwrap.dedent('''\
try:
import setuptools
except ImportError:
import sys
sys.exit(1)
''')
if subprocess.call([other_executable, '-c', command],
env=os.environ):
# the other executable does not have setuptools. Get setuptools.
# We will do this using the same tools we are testing, for better or
# worse. Alternatively, we could try using bootstrap.
executable_dir = test.globs['tmpdir']('executable_dir')
executable_parts = os.path.join(executable_dir, 'parts')
test.globs['mkdir'](executable_parts)
ws = zc.buildout.easy_install.install(
['setuptools'], executable_dir,
index='http://www.python.org/pypi/',
always_unzip=True, executable=other_executable)
zc.buildout.easy_install.sitepackage_safe_scripts(
executable_dir, ws, other_executable, executable_parts,
reqs=['setuptools'], interpreter='py')
original_executable = other_executable
other_executable = os.path.join(executable_dir, 'py')
assert not subprocess.call(
[other_executable, '-c', command], env=os.environ), (
'test set up failed')
sample_eggs = test.globs['tmpdir']('sample_eggs') sample_eggs = test.globs['tmpdir']('sample_eggs')
os.mkdir(os.path.join(sample_eggs, 'index')) os.mkdir(os.path.join(sample_eggs, 'index'))
test.globs['sample_eggs'] = sample_eggs test.globs['sample_eggs'] = sample_eggs
......
...@@ -81,6 +81,7 @@ new versions found in new releases: ...@@ -81,6 +81,7 @@ new versions found in new releases:
Our buildout script has been updated to use the new eggs: Our buildout script has been updated to use the new eggs:
>>> cat(sample_buildout, 'bin', 'buildout') >>> cat(sample_buildout, 'bin', 'buildout')
... # doctest: +NORMALIZE_WHITESPACE
#!/usr/local/bin/python2.4 #!/usr/local/bin/python2.4
<BLANKLINE> <BLANKLINE>
import sys import sys
......
Change History
**************
1.0.0
=====
Initial public version.
********************************
Buildout Script Recipe
********************************
.. contents::
The script recipe installs eggs into a buildout eggs directory, exactly
like zc.recipe.egg, and then generates scripts in a buildout bin
directory with egg paths baked into them.
##############################################################################
#
# Copyright (c) 2007 Zope Corporation 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.
#
##############################################################################
"""Setup for z3c.recipe.scripts package
$Id: setup.py 106736 2009-12-18 02:33:08Z gary $
"""
version = '1.0.0dev'
import os
from setuptools import setup, find_packages
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
name = "z3c.recipe.scripts"
setup(
name = name,
version = version,
author = "Gary Poster",
author_email = "gary.poster@canonical.com",
description = "Recipe for installing Python scripts",
long_description = (
read('README.txt')
+ '\n' +
read('CHANGES.txt')
+ '\n' +
'Detailed Documentation\n'
'**********************\n'
+ '\n' +
read('src', 'z3c', 'recipe', 'scripts', 'README.txt')
+ '\n' +
'Download\n'
'*********\n'
),
keywords = "development build",
classifiers = [
'Development Status :: 5 - Production/Stable',
'Framework :: Buildout',
'Intended Audience :: Developers',
'License :: OSI Approved :: Zope Public License',
'Topic :: Software Development :: Build Tools',
'Topic :: Software Development :: Libraries :: Python Modules',
],
url='http://cheeseshop.python.org/pypi/z3c.recipe.scripts',
license = "ZPL 2.1",
packages = find_packages('src'),
package_dir = {'':'src'},
namespace_packages = ['z3c', 'z3c.recipe'],
install_requires = [
'zc.buildout >=1.5.0dev',
'zc.recipe.egg >=1.2.3dev',
'setuptools'],
tests_require = ['zope.testing'],
test_suite = name+'.tests.test_suite',
entry_points = {'zc.buildout': ['default = %s:Scripts' % name,
'script = %s:Scripts' % name,
'scripts = %s:Scripts' % name,
'interpreter = %s:Interpreter' % name,
]
},
include_package_data = True,
zip_safe=False,
)
__import__('pkg_resources').declare_namespace(__name__)
__import__('pkg_resources').declare_namespace(__name__)
This diff is collapsed.
from z3c.recipe.scripts.scripts import Scripts, Interpreter
##############################################################################
#
# Copyright (c) 2009-2010 Zope Corporation 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.
#
##############################################################################
"""Install scripts from eggs.
"""
import os
import zc.buildout
import zc.buildout.easy_install
from zc.recipe.egg.egg import ScriptBase
class Base(ScriptBase):
def __init__(self, buildout, name, options):
if 'extends' in options:
options.update(buildout[options['extends']])
super(Base, self).__init__(buildout, name, options)
self.default_eggs = '' # Disables feature from zc.recipe.egg.
b_options = buildout['buildout']
options['parts-directory'] = os.path.join(
b_options['parts-directory'], self.name)
value = options.setdefault(
'allowed-eggs-from-site-packages',
'*')
self.allowed_eggs = tuple(name.strip() for name in value.split('\n'))
value = options.setdefault(
'include-site-packages',
b_options.get('include-site-packages', 'false'))
if value not in ('true', 'false'):
raise zc.buildout.UserError(
"Invalid value for include-site-packages option: %s" %
(value,))
self.include_site_packages = (value == 'true')
value = options.setdefault(
'exec-sitecustomize',
b_options.get('exec-sitecustomize', 'false'))
if value not in ('true', 'false'):
raise zc.buildout.UserError(
"Invalid value for exec-sitecustomize option: %s" %
(value,))
self.exec_sitecustomize = (value == 'true')
class Interpreter(Base):
def __init__(self, buildout, name, options):
super(Interpreter, self).__init__(buildout, name, options)
options.setdefault('name', name)
def install(self):
reqs, ws = self.working_set()
options = self.options
generated = []
if not os.path.exists(options['parts-directory']):
os.mkdir(options['parts-directory'])
generated.append(options['parts-directory'])
generated.extend(zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, options['executable'],
options['parts-directory'],
interpreter=options['name'],
extra_paths=self.extra_paths,
initialization=options.get('initialization', ''),
include_site_packages=self.include_site_packages,
exec_sitecustomize=self.exec_sitecustomize,
relative_paths=self._relative_paths,
))
return generated
update = install
class Scripts(Base):
def _install(self, reqs, ws, scripts):
options = self.options
generated = []
if not os.path.exists(options['parts-directory']):
os.mkdir(options['parts-directory'])
generated.append(options['parts-directory'])
generated.extend(zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, options['executable'],
options['parts-directory'], reqs=reqs, scripts=scripts,
interpreter=options.get('interpreter'),
extra_paths=self.extra_paths,
initialization=options.get('initialization', ''),
include_site_packages=self.include_site_packages,
exec_sitecustomize=self.exec_sitecustomize,
relative_paths=self._relative_paths,
script_arguments=options.get('arguments', ''),
script_initialization=options.get('script-initialization', '')
))
return generated
This diff is collapsed.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
$Id$ $Id$
""" """
version = '0' version = '1.2.3dev'
import os import os
from setuptools import setup, find_packages from setuptools import setup, find_packages
...@@ -66,7 +66,7 @@ setup( ...@@ -66,7 +66,7 @@ setup(
package_dir = {'':'src'}, package_dir = {'':'src'},
namespace_packages = ['zc', 'zc.recipe'], namespace_packages = ['zc', 'zc.recipe'],
install_requires = [ install_requires = [
'zc.buildout >=1.2.0', 'zc.buildout >=1.5.0dev',
'setuptools'], 'setuptools'],
tests_require = ['zope.testing'], tests_require = ['zope.testing'],
test_suite = name+'.tests.test_suite', test_suite = name+'.tests.test_suite',
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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