Commit 0c8f821b authored by Julien Muchembled's avatar Julien Muchembled

In __buildout_signature__, fix missing parts that are pulled by recipes' __init__

Fixup to commit "Add referred parts' hash strings in __buildout_signature__,
that invokes rebuild of a part when one of its (recursive) dependencies are
modified."
parent 248170dc
...@@ -374,6 +374,7 @@ class Buildout(DictMixin): ...@@ -374,6 +374,7 @@ class Buildout(DictMixin):
self._raw = _unannotate(data) self._raw = _unannotate(data)
self._data = {} self._data = {}
self._parts = [] self._parts = []
self._initializing = []
# provide some defaults before options are parsed # provide some defaults before options are parsed
# because while parsing options those attributes might be # because while parsing options those attributes might be
...@@ -924,9 +925,9 @@ class Buildout(DictMixin): ...@@ -924,9 +925,9 @@ class Buildout(DictMixin):
recipe, entry = _recipe(options) recipe, entry = _recipe(options)
req = pkg_resources.Requirement.parse(recipe) req = pkg_resources.Requirement.parse(recipe)
sig = sorted(set(_dists_sig(pkg_resources.working_set.resolve([req])))) sig = sorted(set(_dists_sig(pkg_resources.working_set.resolve([req]))))
for dependency in sorted(getattr(options, '_dependency', ())): for dependency in sorted(options.depends):
m = md5() m = md5()
for item in sorted(self.get(dependency).items()): for item in sorted(self[dependency].items()):
m.update(('%r\0%r\0' % item).encode()) m.update(('%r\0%r\0' % item).encode())
sig.append('%s:%s' % (dependency, m.hexdigest())) sig.append('%s:%s' % (dependency, m.hexdigest()))
options['__buildout_signature__'] = ' '.join(sig) options['__buildout_signature__'] = ' '.join(sig)
...@@ -1271,8 +1272,20 @@ class Buildout(DictMixin): ...@@ -1271,8 +1272,20 @@ class Buildout(DictMixin):
v = ' '+v v = ' '+v
print_("%s =%s" % (k, v)) print_("%s =%s" % (k, v))
def initialize(self, options, reqs, entry):
recipe_class = _install_and_load(reqs, 'zc.buildout', entry, self)
self._initializing.append(options)
try:
return recipe_class(self, options.name, options)
finally:
del self._initializing[-1]
def __getitem__(self, section): def __getitem__(self, section):
__doing__ = 'Getting section %s.', section __doing__ = 'Getting section %s.', section
if self._initializing:
caller = self._initializing[-1]
if 'buildout' != section != caller.name:
caller.depends.add(section)
try: try:
return self._data[section] return self._data[section]
except KeyError: except KeyError:
...@@ -1368,7 +1381,7 @@ class Options(DictMixin): ...@@ -1368,7 +1381,7 @@ class Options(DictMixin):
self._raw = data self._raw = data
self._cooked = {} self._cooked = {}
self._data = {} self._data = {}
self._dependency = set() self.depends = set()
def _initialize(self): def _initialize(self):
name = self.name name = self.name
...@@ -1386,17 +1399,9 @@ class Options(DictMixin): ...@@ -1386,17 +1399,9 @@ class Options(DictMixin):
return # buildout section can never be a part return # buildout section can never be a part
if self.get('recipe'): if self.get('recipe'):
self.initialize() self.recipe = self.buildout.initialize(self, *_recipe(self._data))
self.buildout._parts.append(name) self.buildout._parts.append(name)
def initialize(self):
reqs, entry = _recipe(self._data)
buildout = self.buildout
recipe_class = _install_and_load(reqs, 'zc.buildout', entry, buildout)
name = self.name
self.recipe = recipe_class(buildout, name, self)
def _do_extend_raw(self, name, data, doing): def _do_extend_raw(self, name, data, doing):
if name == 'buildout': if name == 'buildout':
return data return data
...@@ -1504,7 +1509,10 @@ class Options(DictMixin): ...@@ -1504,7 +1509,10 @@ class Options(DictMixin):
if not section: if not section:
section = self.name section = self.name
elif section != 'buildout': elif section != 'buildout':
self._dependency.add(section) assert not self.buildout._initializing, (self.name,
self.buildout._initializing[-1],
len(self.buildout._initializing))
self.depends.add(section)
v = self.buildout[section].get(option, None, seen, last=last) v = self.buildout[section].get(option, None, seen, last=last)
if v is None: if v is None:
if option == '_buildout_section_name_': if option == '_buildout_section_name_':
......
...@@ -173,18 +173,14 @@ def wait_until(label, func, *args, **kw): ...@@ -173,18 +173,14 @@ 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)
class TestOptions(zc.buildout.buildout.Options):
def initialize(self):
pass
class Buildout(zc.buildout.buildout.Buildout): class Buildout(zc.buildout.buildout.Buildout):
def __init__(self): def __init__(self):
zc.buildout.buildout.Buildout.__init__( zc.buildout.buildout.Buildout.__init__(
self, '', [('buildout', 'directory', os.getcwd())]) self, '', [('buildout', 'directory', os.getcwd())])
Options = TestOptions def initialize(self, *args):
pass
def buildoutSetUp(test): def buildoutSetUp(test):
......
...@@ -2079,6 +2079,77 @@ def dealing_with_extremely_insane_dependencies(): ...@@ -2079,6 +2079,77 @@ def dealing_with_extremely_insane_dependencies():
Error: Couldn't find a distribution for 'pack5'. Error: Couldn't find a distribution for 'pack5'.
""" """
def test_part_pulled_by_recipe():
"""
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'test.py',
... '''
... class Recipe:
...
... def __init__(self, buildout, name, options):
... self.x = buildout[options['x']][name]
...
... def install(self):
... print self.x
... return ()
...
... update = install
... ''')
>>> write(sample_buildout, 'recipes', 'setup.py',
... '''
... from setuptools import setup
... setup(
... name = "recipes",
... entry_points = {'zc.buildout': ['test = test:Recipe']},
... )
... ''')
>>> write(sample_buildout, 'buildout.cfg',
... '''
... [buildout]
... develop = recipes
... parts = a
... [a]
... recipe = recipes:test
... x = b
... [b]
... <= a
... a = A
... b = B
... ''')
>>> os.chdir(sample_buildout)
>>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
>>> print_(system(buildout), end='')
Develop: '/sample-buildout/recipes'
Installing b.
B
Installing a.
A
>>> print_(system(buildout), end='')
Develop: '/sample-buildout/recipes'
Updating b.
B
Updating a.
A
>>> cat('.installed.cfg') # doctest: +ELLIPSIS
[buildout]
...
[b]
__buildout_installed__ =
__buildout_signature__ = recipes-c79aac86a90182467ce2fdae8b56eb1c
...
[a]
__buildout_installed__ =
__buildout_signature__ = recipes-c79aac86a90182467ce2fdae8b56eb1c b:...
...
"""
def read_find_links_to_load_extensions(): def read_find_links_to_load_extensions():
r""" r"""
We'll create a wacky buildout extension that just announces itself when used: We'll create a wacky buildout extension that just announces itself when used:
......
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