Commit 5da42b95 authored by Jim Fulton's avatar Jim Fulton

Feature Changes

```------------
- Added a buildout newest option, to control whether the newest
  distributions should be sought to meet requirements.  This might
  also provide a hint to recipes that don't deal with
  distributions. For example, a recipe that manages subversion
  checkouts might not update a checkout if newest is set to "false".

- The recipe-testing support setUp function now adds the name
  *buildout* to the test namespace with a value that is the path to
  the buildout script in the sample buildout.  This allows tests to
  use

>>> print system(buildout),

rather than:

>>> print system(join('bin', 'buildout')),

Bugs Fixed
```

-------

- Paths returned from update methods replaced lists of installed files
  rather than augmenting them.
parent b3cbe68c
...@@ -20,6 +20,44 @@ priorities include: ...@@ -20,6 +20,44 @@ priorities include:
Change History Change History
************** **************
1.0.0b20 (2007-02-??)
=====================
Feature Changes
---------------
- Added a buildout newest option, to control whether the newest
distributions should be sought to meet requirements. This might
also provide a hint to recipes that don't deal with
distributions. For example, a recipe that manages subversion
checkouts might not update a checkout if newest is set to "false".
- Added a *newest* keyword parameter to the
zc.buildout.easy_install.install and zc.buildout.easy_install.build
functions to control whether the newest distributions that meed
given requirements should be sought. If a false value is provided
for this parameter and already installed eggs meet the given
requirements, then no attempt will be made to search for newer
distributions.
- The recipe-testing support setUp function now adds the name
*buildout* to the test namespace with a value that is the path to
the buildout script in the sample buildout. This allows tests to
use
>>> print system(buildout),
rather than:
>>> print system(join('bin', 'buildout')),
Bugs Fixed
----------
- Paths returned from update methods replaced lists of installed files
rather than augmenting them.
1.0.0b19 (2007-01-24) 1.0.0b19 (2007-01-24)
===================== =====================
......
...@@ -7,7 +7,7 @@ def read(*rnames): ...@@ -7,7 +7,7 @@ def read(*rnames):
name = "zc.buildout" name = "zc.buildout"
setup( setup(
name = name, name = name,
version = "1.0.0b19", version = "1.0.0b20",
author = "Jim Fulton", author = "Jim Fulton",
author_email = "jim@zope.com", author_email = "jim@zope.com",
description = "System for managing development buildouts", description = "System for managing development buildouts",
......
...@@ -131,7 +131,16 @@ class Buildout(UserDict.DictMixin): ...@@ -131,7 +131,16 @@ class Buildout(UserDict.DictMixin):
if offline not in ('true', 'false'): if offline not in ('true', 'false'):
self._error('Invalid value for offline option: %s', offline) self._error('Invalid value for offline option: %s', offline)
options['offline'] = offline options['offline'] = offline
self.offline = offline == 'true'
if self.offline:
newest = options['newest'] = 'false'
else:
newest = options.get('newest', 'true')
if newest not in ('true', 'false'):
self._error('Invalid value for newest option: %s', newest)
options['newest'] = newest
self.newest = newest == 'true'
def _buildout_path(self, *names): def _buildout_path(self, *names):
return os.path.join(self._buildout_dir, *names) return os.path.join(self._buildout_dir, *names)
...@@ -303,6 +312,16 @@ class Buildout(UserDict.DictMixin): ...@@ -303,6 +312,16 @@ class Buildout(UserDict.DictMixin):
if installed_files is None: if installed_files is None:
installed_files = old_installed_files.split('\n') installed_files = old_installed_files.split('\n')
else:
if isinstance(installed_files, str):
installed_files = [installed_files]
else:
installed_files = list(installed_files)
installed_files += [
p for p in old_installed_files.split('\n')
if p and p not in installed_files]
else: else:
self._logger.info('Installing %s', part) self._logger.info('Installing %s', part)
...@@ -491,8 +510,8 @@ class Buildout(UserDict.DictMixin): ...@@ -491,8 +510,8 @@ class Buildout(UserDict.DictMixin):
# See if buildout or setuptools need to be upgraded. # See if buildout or setuptools need to be upgraded.
# If they do, do the upgrade and restart the buildout process. # If they do, do the upgrade and restart the buildout process.
if self['buildout'].get('offline') == 'true': if not self.newest:
return # skip upgrade in offline mode: return
ws = zc.buildout.easy_install.install( ws = zc.buildout.easy_install.install(
[ [
...@@ -563,7 +582,7 @@ class Buildout(UserDict.DictMixin): ...@@ -563,7 +582,7 @@ class Buildout(UserDict.DictMixin):
specs = self['buildout'].get('extensions', '').split() specs = self['buildout'].get('extensions', '').split()
if specs: if specs:
path = [self['buildout']['develop-eggs-directory']] path = [self['buildout']['develop-eggs-directory']]
if self['buildout'].get('offline') == 'true': if self.offline:
dest = None dest = None
path.append(self['buildout']['eggs-directory']) path.append(self['buildout']['eggs-directory'])
else: else:
...@@ -575,7 +594,7 @@ class Buildout(UserDict.DictMixin): ...@@ -575,7 +594,7 @@ class Buildout(UserDict.DictMixin):
zc.buildout.easy_install.install( zc.buildout.easy_install.install(
specs, dest, path=path, specs, dest, path=path,
working_set=pkg_resources.working_set, working_set=pkg_resources.working_set,
) newest=self.newest)
for ep in pkg_resources.iter_entry_points('zc.buildout.extension'): for ep in pkg_resources.iter_entry_points('zc.buildout.extension'):
ep.load()(self) ep.load()(self)
...@@ -640,7 +659,7 @@ def _install_and_load(spec, group, entry, buildout): ...@@ -640,7 +659,7 @@ def _install_and_load(spec, group, entry, buildout):
buildout_options = buildout['buildout'] buildout_options = buildout['buildout']
if pkg_resources.working_set.find(req) is None: if pkg_resources.working_set.find(req) is None:
if buildout_options['offline'] == 'true': if buildout.offline:
dest = None dest = None
path = [buildout_options['develop-eggs-directory'], path = [buildout_options['develop-eggs-directory'],
buildout_options['eggs-directory'], buildout_options['eggs-directory'],
...@@ -655,6 +674,7 @@ def _install_and_load(spec, group, entry, buildout): ...@@ -655,6 +674,7 @@ def _install_and_load(spec, group, entry, buildout):
index=buildout_options.get('index'), index=buildout_options.get('index'),
path=path, path=path,
working_set=pkg_resources.working_set, working_set=pkg_resources.working_set,
newest=buildout.newest,
) )
return pkg_resources.load_entry_point( return pkg_resources.load_entry_point(
...@@ -961,6 +981,32 @@ Options: ...@@ -961,6 +981,32 @@ Options:
Don't read user defaults. Don't read user defaults.
-o
Run in off-line mode. This is equivalent to the assignment
buildout:offline=true.
-O
Run in non-off-line mode. This is equivalent to the assignment
buildout:offline=false. This is the default buildout mode. The
-O option would normally be used to override a true offline
setting in a configuration file.
-n
Run in newest mode. This is equivalent to the assignment
buildout:newest=true. With this setting, which is the default,
buildout will try to find the newest versions of distributions
available that satisfy its requirements.
-N
Run in non-newest mode. This is equivalent to the assignment
buildout:newest=false. With this setting, buildout will not seek
new distributions if installed distributions satisfy it's
requirements.
Assignments are of the form: section:option=value and are used to Assignments are of the form: section:option=value and are used to
provide configuration options that override those given in the provide configuration options that override those given in the
configuration file. For example, to run the buildout in offline mode, configuration file. For example, to run the buildout in offline mode,
...@@ -1000,7 +1046,7 @@ def main(args=None): ...@@ -1000,7 +1046,7 @@ def main(args=None):
if args[0][0] == '-': if args[0][0] == '-':
op = orig_op = args.pop(0) op = orig_op = args.pop(0)
op = op[1:] op = op[1:]
while op and op[0] in 'vqhWUo': while op and op[0] in 'vqhWUoOnN':
if op[0] == 'v': if op[0] == 'v':
verbosity += 10 verbosity += 10
elif op[0] == 'q': elif op[0] == 'q':
...@@ -1011,6 +1057,12 @@ def main(args=None): ...@@ -1011,6 +1057,12 @@ def main(args=None):
user_defaults = False user_defaults = False
elif op[0] == 'o': elif op[0] == 'o':
options.append(('buildout', 'offline', 'true')) options.append(('buildout', 'offline', 'true'))
elif op[0] == 'O':
options.append(('buildout', 'offline', 'false'))
elif op[0] == 'n':
options.append(('buildout', 'newest', 'true'))
elif op[0] == 'N':
options.append(('buildout', 'newest', 'false'))
else: else:
_help() _help()
op = op[1:] op = op[1:]
......
...@@ -205,7 +205,7 @@ part. An empty method is often provided, as in this example, if parts ...@@ -205,7 +205,7 @@ part. An empty method is often provided, as in this example, if parts
can't be updated. An update method can return None, a string, or an can't be updated. An update method can return None, a string, or an
iterable of strings. If a string or iterable of strings is returned, iterable of strings. If a string or iterable of strings is returned,
then the saved list of paths to be uninstalled is updated with the new then the saved list of paths to be uninstalled is updated with the new
information. information by adding any new files returned by the update method.
We need to provide packaging information so that our recipe can be We need to provide packaging information so that our recipe can be
installed as a develop egg. The minimum information we need to specify installed as a develop egg. The minimum information we need to specify
...@@ -1186,6 +1186,24 @@ The following options are supported: ...@@ -1186,6 +1186,24 @@ The following options are supported:
Run in off-line mode. This is equivalent to the assignment Run in off-line mode. This is equivalent to the assignment
buildout:offline=true. buildout:offline=true.
-O
Run in non-off-line mode. This is equivalent to the assignment
buildout:offline=false. This is the default buildout mode. The
-O option would normally be used to override a true offline
setting in a configuration file.
-n
Run in newest mode. This is equivalent to the assignment
buildout:newest=true. With this setting, which is the default,
buildout will try to find the newest versions of distributions
available that satisfy its requirements.
-N
Run in non-newest mode. This is equivalent to the assignment
buildout:newest=false. With this setting, buildout will not seek
new distributions if installed distributions satisfy it's
requirements.
Assignments are of the form:: Assignments are of the form::
section_name:option_name=value section_name:option_name=value
...@@ -1593,6 +1611,7 @@ database is shown. ...@@ -1593,6 +1611,7 @@ database is shown.
installed = /sample-buildout/.installed.cfg installed = /sample-buildout/.installed.cfg
log-format = %(name)s: %(message)s log-format = %(name)s: %(message)s
log-level = INFO log-level = INFO
newest = true
offline = false offline = false
parts = parts =
parts-directory = /sample-buildout/parts parts-directory = /sample-buildout/parts
...@@ -1705,15 +1724,24 @@ buildout or setuptools.) ...@@ -1705,15 +1724,24 @@ buildout or setuptools.)
Note that the buildout script was installed but not run. To run Note that the buildout script was installed but not run. To run
the buildout, we'd have to run the installed buildout script. the buildout, we'd have to run the installed buildout script.
Offline mode Newest and Offline Modes
------------ ------------------------
If the buildout offline option is given a value of "true", the By default buildout and recipes will try to find the newest versions
buildout and recipes that are aware of the option will avoid doing of distributions needed to satisfy requirements. This can be very
network access. This is handy when running the buildout when not time consuming, especially when incrementally working on setting up a
connected to the internet. It also makes buildouts run much buildout or working on a recipe. The buildout newest option can be
faster. This option is typically given as a command-line option used to to suppress this. If the newest option is set to false, then
``buildout:offline=true``. new distributions won't be sought if an installed distribution meets
requirements. The newest option can be set to false using the -N
command-line option.
The offline option goes a bit further. If the buildout offline option
is given a value of "true", the buildout and recipes that are aware of
the option will avoid doing network access. This is handy when
running the buildout when not connected to the internet. It also
makes buildouts run much faster. This option is typically set using
the buildout -o option.
Controlling the installation database Controlling the installation database
------------------------------------- -------------------------------------
......
...@@ -204,6 +204,7 @@ def buildoutSetUp(test): ...@@ -204,6 +204,7 @@ def buildoutSetUp(test):
sdist = sdist, sdist = sdist,
bdist_egg = bdist_egg, bdist_egg = bdist_egg,
start_server = start_server, start_server = start_server,
buildout = os.path.join(sample, 'bin', 'buildout'),
)) ))
def buildoutTearDown(test): def buildoutTearDown(test):
......
...@@ -451,6 +451,32 @@ Options: ...@@ -451,6 +451,32 @@ Options:
-U -U
<BLANKLINE> <BLANKLINE>
Don't read user defaults. Don't read user defaults.
<BLANKLINE>
-o
<BLANKLINE>
Run in off-line mode. This is equivalent to the assignment
buildout:offline=true.
<BLANKLINE>
-O
<BLANKLINE>
Run in non-off-line mode. This is equivalent to the assignment
buildout:offline=false. This is the default buildout mode. The
-O option would normally be used to override a true offline
setting in a configuration file.
<BLANKLINE>
-n
<BLANKLINE>
Run in newest mode. This is equivalent to the assignment
buildout:newest=true. With this setting, which is the default,
buildout will try to find the newest versions of distributions
available that satisfy its requirements.
<BLANKLINE>
-N
<BLANKLINE>
Run in non-newest mode. This is equivalent to the assignment
buildout:newest=false. With this setting, buildout will not seek
new distributions if installed distributions satisfy it's
requirements.
<BLANKLINE> <BLANKLINE>
Assignments are of the form: section:option=value and are used to Assignments are of the form: section:option=value and are used to
provide configuration options that override those given in the provide configuration options that override those given in the
...@@ -502,6 +528,32 @@ Options: ...@@ -502,6 +528,32 @@ Options:
-U -U
<BLANKLINE> <BLANKLINE>
Don't read user defaults. Don't read user defaults.
<BLANKLINE>
-o
<BLANKLINE>
Run in off-line mode. This is equivalent to the assignment
buildout:offline=true.
<BLANKLINE>
-O
<BLANKLINE>
Run in non-off-line mode. This is equivalent to the assignment
buildout:offline=false. This is the default buildout mode. The
-O option would normally be used to override a true offline
setting in a configuration file.
<BLANKLINE>
-n
<BLANKLINE>
Run in newest mode. This is equivalent to the assignment
buildout:newest=true. With this setting, which is the default,
buildout will try to find the newest versions of distributions
available that satisfy its requirements.
<BLANKLINE>
-N
<BLANKLINE>
Run in non-newest mode. This is equivalent to the assignment
buildout:newest=false. With this setting, buildout will not seek
new distributions if installed distributions satisfy it's
requirements.
<BLANKLINE> <BLANKLINE>
Assignments are of the form: section:option=value and are used to Assignments are of the form: section:option=value and are used to
provide configuration options that override those given in the provide configuration options that override those given in the
...@@ -974,6 +1026,185 @@ def o_option_sets_offline(): ...@@ -974,6 +1026,185 @@ def o_option_sets_offline():
... ...
""" """
def recipe_upgrade():
"""
The buildout will upgrade recipes in newest (and non-offline) mode.
Let's create a recipe egg
>>> mkdir('recipe')
>>> write('recipe', 'recipe.py',
... '''
... class Recipe:
... def __init__(*a): pass
... def install(self):
... print 'recipe v1'
... return ()
... update = install
... ''')
>>> write('recipe', 'setup.py',
... '''
... from setuptools import setup
... setup(name='recipe', version='1', py_modules=['recipe'],
... entry_points={'zc.buildout': ['default = recipe:Recipe']},
... )
... ''')
>>> write('recipe', 'README', '')
>>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS
buildout: Running setup script recipe/setup.py
...
And update our buildout to use it.
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = foo
... find-links = %s
...
... [foo]
... recipe = recipe
... ''' % join('recipe', 'dist'))
>>> print system(buildout),
zc.buildout.easy_install: Getting new distribution for recipe
zc.buildout.easy_install: Got recipe 1
buildout: Installing foo
recipe v1
Now, if we update the recipe egg:
>>> write('recipe', 'recipe.py',
... '''
... class Recipe:
... def __init__(*a): pass
... def install(self):
... print 'recipe v2'
... return ()
... update = install
... ''')
>>> write('recipe', 'setup.py',
... '''
... from setuptools import setup
... setup(name='recipe', version='2', py_modules=['recipe'],
... entry_points={'zc.buildout': ['default = recipe:Recipe']},
... )
... ''')
>>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS
buildout: Running setup script recipe/setup.py
...
We won't get the update if we specify -N:
>>> print system(buildout+' -N'),
buildout: Updating foo
recipe v1
or if we use -o:
>>> print system(buildout+' -o'),
buildout: Updating foo
recipe v1
But we will if we use neither of these:
>>> print system(buildout),
zc.buildout.easy_install: Getting new distribution for recipe
zc.buildout.easy_install: Got recipe 2
buildout: Uninstalling foo
buildout: Installing foo
recipe v1
We can also select a particular recipe version:
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = foo
... find-links = %s
...
... [foo]
... recipe = recipe ==1
... ''' % join('recipe', 'dist'))
>>> print system(buildout),
buildout: Uninstalling foo
buildout: Installing foo
recipe v1
"""
def update_adds_to_uninstall_list():
"""
Paths returned by the update method are added to the list of paths to
uninstall
>>> mkdir('recipe')
>>> write('recipe', 'setup.py',
... '''
... from setuptools import setup
... setup(name='recipe',
... entry_points={'zc.buildout': ['default = recipe:Recipe']},
... )
... ''')
>>> write('recipe', 'recipe.py',
... '''
... import os
... class Recipe:
... def __init__(*_): pass
... def install(self):
... r = ('a', 'b', 'c')
... for p in r: os.mkdir(p)
... return r
... def update(self):
... r = ('c', 'd', 'e')
... for p in r:
... if not os.path.exists(p):
... os.mkdir(p)
... return r
... ''')
>>> write('buildout.cfg',
... '''
... [buildout]
... develop = recipe
... parts = foo
...
... [foo]
... recipe = recipe
... ''')
>>> print system(buildout),
buildout: Develop: /tmp/tmpbHOHnU/_TEST_/sample-buildout/recipe
buildout: Installing foo
>>> print system(buildout),
buildout: Develop: /tmp/tmpbHOHnU/_TEST_/sample-buildout/recipe
buildout: Updating foo
>>> cat('.installed.cfg') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
[buildout]
...
[foo]
__buildout_installed__ = c
d
e
a
b
__buildout_signature__ = ...
"""
###################################################################### ######################################################################
def create_sample_eggs(test, executable=sys.executable): def create_sample_eggs(test, executable=sys.executable):
......
...@@ -59,12 +59,10 @@ zc.buildout used: ...@@ -59,12 +59,10 @@ zc.buildout used:
... ) ... )
... """) ... """)
Now if we run the buildout, the buildout will upgrade itself to the Now if we run the buildout, the buildout will upgrade itself to the
new versions found in new releases: new versions found in new releases:
>>> import os
>>> os.chdir(sample_buildout)
>>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
>>> print system(buildout), >>> print system(buildout),
zc.buildout.easy_install: Getting new distribution for zc.buildout zc.buildout.easy_install: Getting new distribution for zc.buildout
zc.buildout.easy_install: Got zc.buildout 99.99 zc.buildout.easy_install: Got zc.buildout 99.99
...@@ -136,18 +134,25 @@ We won't upgrade in offline mode: ...@@ -136,18 +134,25 @@ We won't upgrade in offline mode:
... index = %(new_releases)s ... index = %(new_releases)s
... parts = show-versions ... parts = show-versions
... develop = showversions ... develop = showversions
... offline = true
... ...
... [show-versions] ... [show-versions]
... recipe = showversions ... recipe = showversions
... """ % dict(new_releases=new_releases)) ... """ % dict(new_releases=new_releases))
>>> print system(buildout), >>> print system(buildout+' -o'),
buildout: Develop: /sample-buildout/showversions buildout: Develop: /sample-buildout/showversions
buildout: Updating show-versions buildout: Updating show-versions
zc.buildout 1.0.0 zc.buildout 1.0.0
setuptools 0.6 setuptools 0.6
Or in non-newest mode:
>>> print system(buildout+' -N'),
buildout: Develop: /sample-buildout/showversions
buildout: Updating show-versions
zc.buildout 1.0.0
setuptools 0.6
We also won't upgrade if the buildout script bing run isn't in the We also won't upgrade if the buildout script bing run isn't in the
buildouts bin directory. To see this we'll create a new buildout buildouts bin directory. To see this we'll create a new buildout
directory: directory:
......
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