Commit 50798288 authored by Gary Poster's avatar Gary Poster

By default, Buildout and the bootstrap script now prefer final versions of...

By default, Buildout and the bootstrap script now prefer final versions of Buildout, recipes, and extensions.
parent 1409c372
Change History
**************
1.5.0b1 (2010-04-29)
1.5.0b3 (unreleased)
====================
New Features:
New features:
- zc.buildout supports Python 2.7.
- By default, Buildout and the bootstrap script now prefer final versions of
Buildout, recipes, and extensions. This can be changed by setting
``prefer-final-build-system = false`` in your configuration's
[buildout] section, and by using the --accept-early-release flag when
calling bootstrap. This will hopefully allow beta releases to be more
easily and safely made in the future. Note that dependencies of your
software do not have this behavior: use the pre-existing switch
``prefer-final = true`` to get this behavior.
Bugs fixed:
- You can now again use virtualenv with zc.buildout. The new features to let
buildout be used with a system Python are disabled in this configuration,
and the previous script generation behavior (1.4.3) is used, even if
the new function ``zc.buildout.easy_install.sitepackage_safe_scripts``
is used.
1.5.0b2 (2010-04-29)
====================
This was a re-release of 1.4.3 in order to keep 1.5.0b1 release from hurting
workflows that combined virtualenv with zc.buildout.
1.5.0b1 (2010-04-29)
====================
New Features:
- Added buildout:socket-timout option so that socket timeout can be configured
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.
in site-packages), as long as you use (1) A fresh checkout, (2) the
new bootstrap.py, and (3) recipes that use the new
``zc.buildout.easy_install.sitepackage_safe_scripts`` function to generate
scripts and interpreters. Many recipes will need to be updated to use
this new function. The scripts and interpreters generated by
``zc.recipe.egg`` will continue to use the older function, not safe
with system Pythons. Use the ``z3c.recipe.scripts`` as a replacement.
zc.recipe.egg is still a fully supported, and simpler, way of
generating scripts and interpreters if you are using a "clean" Python,
......
......@@ -116,6 +116,17 @@ 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("--accept-early-release", dest='accept_early_release',
action="store_true", default=False,
help=("Normally, if you do not specify a --version, the "
"bootstrap script gets the newest *final* versions "
"of zc.buildout for you. If you use this flag, "
"bootstrap will get the newest releases even if they "
"are alphas or betas. Note that, if you do want to "
"use early buildout releases, you probably want "
"to also set ``prefer-final-build-system= false`` "
"in the [buildout] section of your configuration "
"file."))
parser.add_option("-c", None, action="store", dest="config_file",
help=("Specify the path to the buildout configuration "
"file to be used."))
......@@ -177,23 +188,56 @@ cmd = [quote(sys.executable),
if not has_broken_dash_S:
cmd.insert(1, '-S')
if options.download_base:
cmd.extend(['-f', quote(options.download_base)])
requirement = 'zc.buildout'
if options.version:
requirement = '=='.join((requirement, options.version))
cmd.append(requirement)
find_links = options.download_base
if not find_links:
find_links = os.environ.get('bootstrap-testing-find-links')
if find_links:
cmd.extend(['-f', quote(find_links)])
if options.use_distribute:
setup_requirement = 'distribute'
else:
setup_requirement = 'setuptools'
ws = pkg_resources.working_set
setup_requirement_path = ws.find(
pkg_resources.Requirement.parse(setup_requirement)).location
env = dict(
os.environ,
PYTHONPATH=ws.find(
pkg_resources.Requirement.parse(setup_requirement)).location)
PYTHONPATH=setup_requirement_path)
requirement = 'zc.buildout'
version = options.version
if version is None and not options.accept_early_release:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
_final_parts = '*final-', '*final'
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(
search_path=[setup_requirement_path])
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)
if is_jython:
import subprocess
......
......@@ -47,6 +47,87 @@ Make sure the bootstrap script actually works::
X...
d zc.buildout-...egg
The buildout script it has generated is a new-style script, using a
customized site.py.
>>> buildout_script = join(sample_buildout, 'bin', 'buildout')
>>> if sys.platform.startswith('win'):
... buildout_script += '-script.py'
>>> print open(buildout_script).read() # doctest: +ELLIPSIS
#...
<BLANKLINE>
import sys
sys.path[0:0] = [
'/sample/parts/buildout',
]
<BLANKLINE>
<BLANKLINE>
import os
path = sys.path[0]
if os.environ.get('PYTHONPATH'):
path = os.pathsep.join([path, os.environ['PYTHONPATH']])
os.environ['PYTHONPATH'] = path
import site # imports custom buildout-generated site.py
<BLANKLINE>
import zc.buildout.buildout
<BLANKLINE>
if __name__ == '__main__':
zc.buildout.buildout.main()
<BLANKLINE>
The bootstrap process prefers final versions of zc.buildout, so it has
selected the (generated-locally) 99.99 egg rather than the also-available
100.0b1 egg. We can see that in the buildout script's site.py.
>>> buildout_site_py = join(
... sample_buildout, 'parts', 'buildout', 'site.py')
>>> print open(buildout_site_py).read() # doctest: +ELLIPSIS
"...
buildout_paths = [
'/sample/eggs/setuptools-...egg',
'/sample/eggs/zc.buildout-99.99-pyN.N.egg'
]
...
If you want to accept early releases of zc.buildout, you either need to
specify an explicit version (using --version here and specifying the
version in the buildout configuration file using the
``buildout-version`` option or the ``versions`` option) or specify that you
accept early releases.
You accept early releases by using ``--accept-early-release`` on the
bootstrap script and specifying ``prefer-final-build-system = false`` in the
buildout configuration file. You must do both.
Here's an example.
>>> write('buildout.cfg',
... '''
... [buildout]
... parts =
... prefer-final-build-system = false
... ''')
>>> ignored = system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --accept-early-release')
>>> print open(buildout_site_py).read() # doctest: +ELLIPSIS
"...
buildout_paths = [
'/sample/eggs/setuptools-...egg',
'/sample/eggs/zc.buildout-100.0b1-pyN.N.egg'
]
...
Notice we are now using zc.buildout 100.0b1, a non-final release.
Now we'll go back to the default of preferring final versions.
>>> write('buildout.cfg',
... '''
... [buildout]
... parts =
... ''')
Now we will try the `--version` option, which lets you define a version for
`zc.buildout`. If not provided, bootstrap will look for the latest one.
......@@ -71,11 +152,9 @@ Now let's try with `1.1.2`, which happens to exist::
<BLANKLINE>
X
Let's make sure the generated `buildout` script uses it::
Versions older than 1.5.0 put their egg dependencies in the ``buildout`` script.
Let's make sure it was generated as we expect::
>>> buildout_script = join(sample_buildout, 'bin', 'buildout')
>>> if sys.platform.startswith('win'):
... buildout_script += '-script.py'
>>> print open(buildout_script).read() # doctest: +ELLIPSIS
#...
<BLANKLINE>
......@@ -102,7 +181,7 @@ Let's try with `1.2.1`::
<BLANKLINE>
X
Let's make sure the generated `buildout` script uses it::
Let's make sure the generated ``buildout`` script uses it::
>>> print open(buildout_script).read() # doctest: +ELLIPSIS
#...
......@@ -119,7 +198,7 @@ Let's make sure the generated `buildout` script uses it::
zc.buildout.buildout.main()
<BLANKLINE>
`zc.buildout` now can also run with `Distribute` with the `--distribute`
``zc.buildout`` now can also run with `Distribute` with the `--distribute`
option::
>>> print 'X'; print system(
......@@ -131,22 +210,14 @@ option::
Generated script '/sample/bin/buildout'...
X
Let's make sure the generated `buildout` script uses it::
>>> print open(buildout_script).read() # doctest: +ELLIPSIS
#...
<BLANKLINE>
import sys
sys.path[0:0] = [
Let's make sure the generated ``site.py`` uses it::
>>> print open(buildout_site_py).read() # doctest: +ELLIPSIS
"...
buildout_paths = [
'/sample/eggs/distribute-...egg',
'/sample/eggs/zc.buildout-...egg',
'/sample/eggs/zc.buildout-99.99-pyN.N.egg'
]
<BLANKLINE>
import zc.buildout.buildout
<BLANKLINE>
if __name__ == '__main__':
zc.buildout.buildout.main()
<BLANKLINE>
...
Make sure both options can be used together::
......@@ -160,8 +231,8 @@ Make sure both options can be used together::
Generated script '/sample/bin/buildout'...
X
Let's make sure the generated `buildout` script uses ``Distribute`` *and*
``zc.buildout-1.2.1``::
Let's make sure the old-style generated ``buildout`` script uses
``Distribute`` *and* ``zc.buildout-1.2.1``::
>>> print open(buildout_script).read() # doctest: +ELLIPSIS
#...
......@@ -258,5 +329,14 @@ Here's the entire help text.
--eggs=EGGS Specify a directory for storing eggs. Defaults to a
temporary directory that is deleted when the bootstrap
script completes.
--accept-early-release
Normally, if you do not specify a --version, the
bootstrap script gets the newest *final* versions of
zc.buildout for you. If you use this flag, bootstrap
will get the newest releases even if they are alphas
or betas. Note that, if you do want to use early
buildout releases, you probably want to also set
``prefer-final-build-system= false`` in the [buildout]
section of your configuration file.
-c CONFIG_FILE Specify the path to the buildout configuration file to
be used.
......@@ -131,6 +131,7 @@ _buildout_default_options = _annotate_section({
'offline': 'false',
'parts-directory': 'parts',
'prefer-final': 'false',
'prefer-final-build-system': 'true',
'python': 'buildout',
'relative-paths': 'false',
'socket-timeout': '',
......@@ -234,6 +235,8 @@ class Buildout(UserDict.DictMixin):
self._logger = logging.getLogger('zc.buildout')
self.offline = (buildout_section['offline'] == 'true')
self.newest = (buildout_section['newest'] == 'true')
self.prefer_final_build_system = (
buildout_section['prefer-final-build-system'] == 'true')
##################################################################
## WARNING!!!
......@@ -267,42 +270,26 @@ class Buildout(UserDict.DictMixin):
self._setup_logging()
offline = options['offline']
if offline not in ('true', 'false'):
self._error('Invalid value for offline option: %s', offline)
self.offline = (offline == 'true')
if self.offline:
newest = options['newest'] = 'false'
else:
newest = options['newest']
if newest not in ('true', 'false'):
self._error('Invalid value for newest option: %s', newest)
self.newest = (newest == 'true')
versions = options.get('versions')
if versions:
zc.buildout.easy_install.default_versions(dict(self[versions]))
prefer_final = options['prefer-final']
if prefer_final not in ('true', 'false'):
self._error('Invalid value for prefer-final option: %s',
prefer_final)
zc.buildout.easy_install.prefer_final(prefer_final=='true')
use_dependency_links = options['use-dependency-links']
if use_dependency_links not in ('true', 'false'):
self._error('Invalid value for use-dependency-links option: %s',
use_dependency_links)
self.offline = options.get_bool('offline')
if self.offline:
options['newest'] = 'false'
self.newest = options.get_bool('newest')
zc.buildout.easy_install.prefer_final(
options.get_bool('prefer-final'))
self.prefer_final_build_system = options.get_bool(
'prefer-final-build-system')
zc.buildout.easy_install.use_dependency_links(
use_dependency_links == 'true')
allow_picked_versions = options['allow-picked-versions']
if allow_picked_versions not in ('true', 'false'):
self._error('Invalid value for allow-picked-versions option: %s',
allow_picked_versions)
options.get_bool('use-dependency-links'))
zc.buildout.easy_install.allow_picked_versions(
allow_picked_versions == 'true')
options.get_bool('allow-picked-versions'))
zc.buildout.easy_install.install_from_cache(
options.get_bool('install-from-cache'))
zc.buildout.easy_install.always_unzip(options.get_bool('unzip'))
download_cache = options.get('download-cache')
if download_cache:
......@@ -319,19 +306,6 @@ class Buildout(UserDict.DictMixin):
zc.buildout.easy_install.download_cache(download_cache)
install_from_cache = options['install-from-cache']
if install_from_cache not in ('true', 'false'):
self._error('Invalid value for install-from-cache option: %s',
install_from_cache)
zc.buildout.easy_install.install_from_cache(
install_from_cache=='true')
always_unzip = options['unzip']
if always_unzip not in ('true', 'false'):
self._error('Invalid value for unzip option: %s',
always_unzip)
zc.buildout.easy_install.always_unzip(always_unzip=='true')
# "Use" each of the defaults so they aren't reported as unused options.
for name in _buildout_default_options:
options[name]
......@@ -364,6 +338,7 @@ class Buildout(UserDict.DictMixin):
[options['develop-eggs-directory'],
options['eggs-directory']],
include_site_packages=_sys_executable_has_broken_dash_S,
prefer_final = self.prefer_final_build_system,
)
else:
ws = zc.buildout.easy_install.install(
......@@ -375,6 +350,7 @@ class Buildout(UserDict.DictMixin):
newest=self.newest,
allow_hosts=self._allow_hosts,
include_site_packages=_sys_executable_has_broken_dash_S,
prefer_final = self.prefer_final_build_system,
)
# Now copy buildout and setuptools eggs, and record destination eggs:
......@@ -410,6 +386,8 @@ class Buildout(UserDict.DictMixin):
else:
assert relative_paths == 'false'
relative_paths = ''
# Ideally the (possibly) new version of buildout would get a
# chance to write the script. Not sure how to do that.
zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, options['executable'], partsdir,
reqs=['zc.buildout'], relative_paths=relative_paths,
......@@ -427,7 +405,7 @@ class Buildout(UserDict.DictMixin):
# for eggs:
sys.path.insert(0, self['buildout']['develop-eggs-directory'])
# Check for updates. This could cause the process to be rstarted
# Check for updates. This could cause the process to be restarted.
self._maybe_upgrade()
# load installed data
......@@ -480,7 +458,7 @@ class Buildout(UserDict.DictMixin):
# compute new part recipe signatures
self._compute_part_signatures(install_parts)
# uninstall parts that are no-longer used or who's configs
# uninstall parts that are no-longer used or whose configs
# have changed
for part in reversed(installed_parts):
if part in install_parts:
......@@ -626,11 +604,11 @@ class Buildout(UserDict.DictMixin):
f.close()
def _uninstall_part(self, part, installed_part_options):
# ununstall part
# uninstall part
__doing__ = 'Uninstalling %s.', part
self._logger.info(*__doing__)
# run uinstall recipe
# run uninstall recipe
recipe, entry = _recipe(installed_part_options[part])
try:
uninstaller = _install_and_load(
......@@ -859,7 +837,8 @@ class Buildout(UserDict.DictMixin):
index = options.get('index'),
path = [options['develop-eggs-directory']],
allow_hosts = self._allow_hosts,
include_site_packages=_sys_executable_has_broken_dash_S
include_site_packages=_sys_executable_has_broken_dash_S,
prefer_final=self.prefer_final_build_system,
)
upgraded = []
......@@ -913,6 +892,8 @@ class Buildout(UserDict.DictMixin):
# fast for Python to know to regenerate the .pyc/.pyo files.
shutil.rmtree(partsdir)
os.mkdir(partsdir)
# Ideally the new version of buildout would get a chance to write the
# script. Not sure how to do that.
zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, sys.executable, partsdir,
reqs=['zc.buildout'],
......@@ -957,7 +938,8 @@ class Buildout(UserDict.DictMixin):
links = self['buildout'].get('find-links', '').split(),
index = self['buildout'].get('index'),
newest=self.newest, allow_hosts=self._allow_hosts,
include_site_packages=_sys_executable_has_broken_dash_S)
include_site_packages=_sys_executable_has_broken_dash_S,
prefer_final=self.prefer_final_build_system)
# Clear cache because extensions might now let us read pages we
# couldn't read before.
......@@ -988,6 +970,7 @@ class Buildout(UserDict.DictMixin):
setup = os.path.abspath(setup)
fd, tsetup = tempfile.mkstemp()
exe = zc.buildout.easy_install._safe_arg(sys.executable)
try:
os.write(fd, zc.buildout.easy_install.runsetup_template % dict(
setuptools=pkg_resources_loc,
......@@ -1001,14 +984,10 @@ class Buildout(UserDict.DictMixin):
for a in args:
arg_list.append(zc.buildout.easy_install._safe_arg(a))
subprocess.Popen(
[zc.buildout.easy_install._safe_arg(sys.executable)]
+ list(tsetup)
+ arg_list
).wait()
subprocess.Popen([exe] + list(tsetup) + arg_list).wait()
else:
os.spawnl(os.P_WAIT, sys.executable, zc.buildout.easy_install._safe_arg (sys.executable), tsetup,
os.spawnl(os.P_WAIT, sys.executable, exe, tsetup,
*[zc.buildout.easy_install._safe_arg(a)
for a in args])
finally:
......@@ -1075,7 +1054,8 @@ def _install_and_load(spec, group, entry, buildout):
working_set=pkg_resources.working_set,
newest=buildout.newest,
allow_hosts=buildout._allow_hosts,
include_site_packages=_sys_executable_has_broken_dash_S)
include_site_packages=_sys_executable_has_broken_dash_S,
prefer_final=buildout.prefer_final_build_system)
__doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry
return pkg_resources.load_entry_point(
......@@ -1297,6 +1277,31 @@ class Options(UserDict.DictMixin):
self.name)
return self._created
def get_bool(self, name, default=None, on_error=None):
"""Given a name, return a boolean value for that name.
``default``, if given, should be 'true', 'false', or None. None
is the default, and means that there is no default for the
value: the call should raise a MissingOption error if the name
is not present.
``on_error``, if given, should be a callable that takes the name and
the found value.
"""
if default is None:
value = self[name]
else:
value = self.get(name, default=default)
if value not in ('true', 'false'):
if on_error is None:
raise zc.buildout.UserError(
'Invalid value for %s option: %s' % (name, value))
else:
on_error(name, value)
else:
return value == 'true'
_spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
'|'
'^[ \t\r\f\v]+'
......
......@@ -765,6 +765,8 @@ COMMAND_LINE_VALUE).
DEFAULT_VALUE
prefer-final= false
DEFAULT_VALUE
prefer-final-build-system= true
DEFAULT_VALUE
python= buildout
DEFAULT_VALUE
relative-paths= false
......@@ -2244,6 +2246,7 @@ database is shown.
parts =
parts-directory = /sample-buildout/parts
prefer-final = false
prefer-final-build-system = true
python = buildout
relative-paths = false
socket-timeout =
......@@ -2484,25 +2487,34 @@ the buildout -o option.
Preferring Final Releases
-------------------------
Currently, when searching for new releases, the newest available
release is used. This isn't usually ideal, as you may get a
development release or alpha releases not ready to be widely used.
You can request that final releases be preferred using the prefer
final option in the buildout section::
Currently, when searching for new releases of your project's
dependencies, the newest available release is used. This isn't usually
ideal, as you may get a development release or alpha releases not ready
to be widely used. You can request that final releases be preferred
using the ``prefer-final`` option in the buildout section::
[buildout]
...
prefer-final = true
When the prefer-final option is set to true, then when searching for
When the ``prefer-final`` option is set to true, then when searching for
new releases, final releases are preferred. If there are final
releases that satisfy distribution requirements, then those releases
are used even if newer non-final releases are available. The buildout
prefer-final option can be used to override this behavior.
are used even if newer non-final releases are available.
A separate option controls the behavior of the build system itself.
When buildout looks for recipes, extensions, and for updates to itself,
it does prefer final releases by default, as of the 1.5.0 release. The
``prefer-final-build-system`` option will let you override this behavior.
[buildout]
...
prefer-final-build-system = false
In buildout version 2, final releases will be preferred by default.
You will then need to use a false value for prefer-final to get the
newest releases.
In buildout version 2, all final releases will be preferred by
default--that is ``prefer-final`` will also default to 'true'. You will
then need to use a 'false' value for ``prefer-final`` to get the newest
releases, like with ``prefer-final-build-system``.
Finding distributions
---------------------
......
......@@ -322,7 +322,8 @@ class Installer:
use_dependency_links=None,
allow_hosts=('*',),
include_site_packages=None,
allowed_eggs_from_site_packages=None
allowed_eggs_from_site_packages=None,
prefer_final=None,
):
self._dest = dest
self._allow_hosts = allow_hosts
......@@ -336,6 +337,8 @@ class Installer:
if use_dependency_links is not None:
self._use_dependency_links = use_dependency_links
if prefer_final is not None:
self._prefer_final = prefer_final
self._links = links = list(_fix_file_links(links))
if self._download_cache and (self._download_cache not in links):
links.insert(0, self._download_cache)
......@@ -1060,13 +1063,14 @@ def install(specs, dest,
executable=sys.executable, always_unzip=None,
path=None, working_set=None, newest=True, versions=None,
use_dependency_links=None, allow_hosts=('*',),
include_site_packages=None, allowed_eggs_from_site_packages=None):
installer = Installer(dest, links, index, executable, always_unzip, path,
newest, versions, use_dependency_links,
allow_hosts=allow_hosts,
include_site_packages=None, allowed_eggs_from_site_packages=None,
prefer_final=None):
installer = Installer(
dest, links, index, executable, always_unzip, path, newest,
versions, use_dependency_links, allow_hosts=allow_hosts,
include_site_packages=include_site_packages,
allowed_eggs_from_site_packages=
allowed_eggs_from_site_packages)
allowed_eggs_from_site_packages=allowed_eggs_from_site_packages,
prefer_final=prefer_final)
return installer.install(specs, working_set)
......@@ -1075,11 +1079,11 @@ def build(spec, dest, build_ext,
executable=sys.executable,
path=None, newest=True, versions=None, allow_hosts=('*',),
include_site_packages=None, allowed_eggs_from_site_packages=None):
installer = Installer(dest, links, index, executable, True, path, newest,
versions, allow_hosts=allow_hosts,
installer = Installer(
dest, links, index, executable, True, path, newest, versions,
allow_hosts=allow_hosts,
include_site_packages=include_site_packages,
allowed_eggs_from_site_packages=
allowed_eggs_from_site_packages)
allowed_eggs_from_site_packages=allowed_eggs_from_site_packages)
return installer.build(spec, build_ext)
......@@ -1175,11 +1179,12 @@ def develop(setup, dest,
[f() for f in undo]
def working_set(specs, executable, path, include_site_packages=None,
allowed_eggs_from_site_packages=None):
allowed_eggs_from_site_packages=None, prefer_final=None):
return install(
specs, None, executable=executable, path=path,
include_site_packages=include_site_packages,
allowed_eggs_from_site_packages=allowed_eggs_from_site_packages)
allowed_eggs_from_site_packages=allowed_eggs_from_site_packages,
prefer_final=prefer_final)
############################################################################
# Script generation functions
......
......@@ -3126,6 +3126,105 @@ We get an error if we specify anything but true or false:
"""
def buildout_prefer_final_build_system_option():
"""
The prefer-final-build-system buildout option can be used for overriding
the default preference for final distributions for recipes, buildout
extensions, and buildout itself.
Set up. This creates sdists for demorecipe 1.0 and 1.1b1, and for
demoextension 1.0 and 1.1b1.
>>> create_sample_recipe_sdists(sample_eggs)
>>> create_sample_extension_sdists(sample_eggs)
The default is prefer-final-build-system = true:
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = demo
... find-links = %(link_server)s
... extensions = demoextension
...
... [demo]
... recipe = demorecipe
... ''' % globals())
>>> print system(buildout+' -v'), # doctest: +ELLIPSIS
Installing ...
Picked: demoextension = 1.0
...
Picked: demorecipe = 1.0
...
Here we see that the final versions of demorecipe and demoextension were used.
We get the same behavior if we explicitly state that
prefer-final-build-system = true.
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = demo
... find-links = %(link_server)s
... extensions = demoextension
... prefer-final-build-system = true
...
... [demo]
... recipe = demorecipe
... ''' % globals())
>>> print system(buildout+' -v'), # doctest: +ELLIPSIS
Installing ...
Picked: demoextension = 1.0
...
Picked: demorecipe = 1.0
...
If we specify prefer-final-build-system = false, we'll get the newest
distributions in the build system:
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = demo
... find-links = %(link_server)s
... extensions = demoextension
... prefer-final-build-system = false
...
... [demo]
... recipe = demorecipe
... ''' % globals())
>>> print system(buildout+' -v'), # doctest: +ELLIPSIS
Installing ...
Picked: demoextension = 1.1b1
...
Picked: demorecipe = 1.1b1
...
We get an error if we specify anything but true or false:
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = demo
... find-links = %(link_server)s
... extensions = demoextension
... prefer-final-build-system = no
...
... [demo]
... recipe = demorecipe
... ''' % globals())
>>> print system(buildout+' -v'), # doctest: +ELLIPSIS
While:
Initializing.
Error: Invalid value for prefer-final-build-system option: no
"""
def develop_with_modules():
"""
Distribution setup scripts can import modules in the distribution directory:
......@@ -3492,6 +3591,68 @@ def create_sample_namespace_eggs(dest, site_packages_path=None):
finally:
shutil.rmtree(tmp)
def create_sample_extension_sdists(dest):
from zc.buildout.testing import write, mkdir
name = 'demoextension'
for version in ('1.0', '1.1b1'):
tmp = tempfile.mkdtemp()
try:
write(tmp, 'README.txt', '')
write(tmp, name + '.py',
"def ext(buildout):\n"
" pass\n"
"def unload(buildout):\n"
" pass\n"
% locals())
write(tmp, 'setup.py',
"from setuptools import setup\n"
"setup(\n"
" name = %(name)r,\n"
" py_modules = [%(name)r],\n"
" entry_points = {\n"
" 'zc.buildout.extension': "
"['ext = %(name)s:ext'],\n"
" 'zc.buildout.unloadextension': "
"['ext = %(name)s:unload'],\n"
" },\n"
" zip_safe=True, version=%(version)r,\n"
" author='bob', url='bob', author_email='bob')\n"
% locals())
zc.buildout.testing.sdist(tmp, dest)
finally:
shutil.rmtree(tmp)
def create_sample_recipe_sdists(dest):
from zc.buildout.testing import write, mkdir
name = 'demorecipe'
for version in ('1.0', '1.1b1'):
tmp = tempfile.mkdtemp()
try:
write(tmp, 'README.txt', '')
write(tmp, name + '.py',
"import logging, os, zc.buildout\n"
"class Demorecipe:\n"
" def __init__(self, buildout, name, options):\n"
" self.name, self.options = name, options\n"
" def install(self):\n"
" return ()\n"
" def update(self):\n"
" pass\n"
% locals())
write(tmp, 'setup.py',
"from setuptools import setup\n"
"setup(\n"
" name = %(name)r,\n"
" py_modules = [%(name)r],\n"
" entry_points = {'zc.buildout': "
"['default = %(name)s:Demorecipe']},\n"
" zip_safe=True, version=%(version)r,\n"
" author='bob', url='bob', author_email='bob')\n"
% locals())
zc.buildout.testing.sdist(tmp, dest)
finally:
shutil.rmtree(tmp)
def _write_eggrecipedemoneeded(tmp, minor_version, suffix=''):
from zc.buildout.testing import write
write(tmp, 'README.txt', '')
......@@ -3639,37 +3800,33 @@ def easy_install_SetUp(test):
egg_parse = re.compile('([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d).egg$'
).match
def makeNewRelease(project, ws, dest):
def makeNewRelease(project, ws, dest, version='99.99'):
dist = ws.find(pkg_resources.Requirement.parse(project))
eggname, oldver, pyver = egg_parse(
os.path.basename(dist.location)
).groups()
dest = os.path.join(dest, "%s-99.99-py%s.egg" % (eggname, pyver))
dest = os.path.join(dest, "%s-%s-py%s.egg" % (eggname, version, pyver))
if os.path.isfile(dist.location):
shutil.copy(dist.location, dest)
zip = zipfile.ZipFile(dest, 'a')
zip.writestr(
'EGG-INFO/PKG-INFO',
zip.read('EGG-INFO/PKG-INFO').replace("Version: %s" % oldver,
"Version: 99.99")
"Version: %s" % version)
)
zip.close()
else:
shutil.copytree(dist.location, dest)
info_path = os.path.join(dest, 'EGG-INFO', 'PKG-INFO')
info = open(info_path).read().replace("Version: %s" % oldver,
"Version: 99.99")
"Version: %s" % version)
open(info_path, 'w').write(info)
def updateSetup(test):
zc.buildout.testing.buildoutSetUp(test)
new_releases = test.globs['tmpdir']('new_releases')
test.globs['new_releases'] = new_releases
def getWorkingSetWithBuildoutEgg(test):
sample_buildout = test.globs['sample_buildout']
eggs = os.path.join(sample_buildout, 'eggs')
# If the zc.buildout dist is a develo dist, convert it to a
# If the zc.buildout dist is a develop dist, convert it to a
# regular egg in the sample buildout
req = pkg_resources.Requirement.parse('zc.buildout')
dist = pkg_resources.working_set.find(req)
......@@ -3699,9 +3856,16 @@ def updateSetup(test):
os.path.join(sample_buildout, 'bin'))
else:
ws = pkg_resources.working_set
return ws
def updateSetup(test):
zc.buildout.testing.buildoutSetUp(test)
new_releases = test.globs['tmpdir']('new_releases')
test.globs['new_releases'] = new_releases
ws = getWorkingSetWithBuildoutEgg(test)
# now let's make the new releases
makeNewRelease('zc.buildout', ws, new_releases)
makeNewRelease('zc.buildout', ws, new_releases, '100.0b1')
os.mkdir(os.path.join(new_releases, 'zc.buildout'))
if zc.buildout.easy_install.is_distribute:
makeNewRelease('distribute', ws, new_releases)
......@@ -3710,6 +3874,13 @@ def updateSetup(test):
makeNewRelease('setuptools', ws, new_releases)
os.mkdir(os.path.join(new_releases, 'setuptools'))
def bootstrapSetup(test):
easy_install_SetUp(test)
sample_eggs = test.globs['sample_eggs']
ws = getWorkingSetWithBuildoutEgg(test)
makeNewRelease('zc.buildout', ws, sample_eggs)
makeNewRelease('zc.buildout', ws, sample_eggs, '100.0b1')
os.environ['bootstrap-testing-find-links'] = test.globs['link_server']
normalize_bang = (
re.compile(re.escape('#!'+
......@@ -3952,12 +4123,13 @@ def test_suite():
if os.path.exists(bootstrap_py):
test_suite.append(doctest.DocFileSuite(
'bootstrap.txt',
setUp=easy_install_SetUp,
setUp=bootstrapSetup,
tearDown=zc.buildout.testing.buildoutTearDown,
checker=renormalizing.RENormalizing([
zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings,
zc.buildout.testing.normalize_script,
zc.buildout.testing.normalize_egg_py,
normalize_bang,
(re.compile('Downloading.*setuptools.*egg\n'), ''),
(re.compile('options:'), 'Options:'),
......
......@@ -3,13 +3,14 @@ Automatic Buildout Updates
When a buildout is run, one of the first steps performed is to check
for updates to either zc.buildout or setuptools. To demonstrate this,
we've creates some "new releases" of buildout and setuptools in a
we've created some "new releases" of buildout and setuptools in a
new_releases folder:
>>> ls(new_releases)
d setuptools
- setuptools-99.99-py2.4.egg
d zc.buildout
- zc.buildout-100.0b1-pyN.N.egg
- zc.buildout-99.99-py2.4.egg
Let's update the sample buildout.cfg to look in this area:
......@@ -78,6 +79,11 @@ new versions found in new releases:
zc.buildout 99.99
setuptools 99.99
Notice that, even though we have a newer beta version of zc.buildout
available, the final "99.99" was selected. If you want to get non-final
versions, specify a specific version in your buildout's versions section,
or use the ``prefer-final-build-system = false`` discussed below.
Our buildout script's site.py has been updated to use the new eggs:
>>> cat(sample_buildout, 'parts', 'buildout', 'site.py')
......@@ -162,7 +168,7 @@ Or in non-newest mode:
setuptools 0.6
We also won't upgrade if the buildout script being run isn't in the
buildouts bin directory. To see this we'll create a new buildout
buildout's bin directory. To see this we'll create a new buildout
directory:
>>> sample_buildout2 = tmpdir('sample_buildout2')
......@@ -187,3 +193,33 @@ directory:
Not upgrading because not running a local buildout command.
>>> ls('bin')
Notice that, as mentioned above, the ``prefer-final-build-system =
false`` means that newer non-final versions of these dependencies are
preferred.
>>> cd(sample_buildout)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... find-links = %(new_releases)s
... index = %(new_releases)s
... parts = show-versions
... develop = showversions
... prefer-final-build-system = false
...
... [show-versions]
... recipe = showversions
... """ % dict(new_releases=new_releases))
>>> print system(buildout),
Getting distribution for 'zc.buildout'.
Got zc.buildout 100.0b1.
Upgraded:
zc.buildout version 100.0b1,
setuptools version 99.99;
restarting.
Develop: '/sample-buildout/showversions'
Updating show-versions.
zc.buildout 100.0b1
setuptools 99.99
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