Commit dffdeffc authored by Julien Muchembled's avatar Julien Muchembled

fixup! Add referred parts' hash strings in __buildout_signature__, that...

fixup! Add referred parts' hash strings in __buildout_signature__, that invokes rebuild of a part when one of its (recursive) dependencies are modified.

The purpose is to make the part signature available sooner,
during recipe's __init__.

Commit 8be81fe4 already
broke detection of unused options in sections.
parent 6f846515
......@@ -374,6 +374,7 @@ class Buildout(DictMixin):
self._data = {}
self._parts = []
self._initializing = []
self._signature_cache = {}
# provide some defaults before options are parsed
# because while parsing options those attributes might be
......@@ -704,9 +705,7 @@ class Buildout(DictMixin):
_save_options(section, self[section], sys.stdout)
print_()
# compute new part recipe signatures
self._compute_part_signatures(install_parts)
del self._signature_cache
# uninstall parts that are no-longer used or who's configs
# have changed
......@@ -939,31 +938,7 @@ class Buildout(DictMixin):
self._logger.warning(
"Unexpected entry, %r, in develop-eggs directory.", f)
def _compute_part_signatures(self, parts):
# The same recipe may appear many times.
sig_cache= {}
# Compute recipe signature and add to options
for part in parts:
options = self.get(part)
if options is None:
options = self[part] = {}
recipe, entry = _recipe(options)
try:
# Copy cached list, because sig.append is called later
sig = sig_cache[recipe][:]
except KeyError:
req = pkg_resources.Requirement.parse(recipe)
sig_result = sig_cache[recipe] = sorted(set(_dists_sig(pkg_resources.working_set.resolve([req]))))
sig = sig_result[:]
for dependency in sorted(options.depends):
m = md5()
for item in sorted(self[dependency].items()):
m.update(('%r\0%r\0' % item).encode())
sig.append('%s:%s' % (dependency, m.hexdigest()))
options['__buildout_signature__'] = ' '.join(sig)
_compute_part_signatures = None # BBB: monkey-patched by slapos.rebootstrap
def _read_installed_part_options(self):
old = self['buildout']['installed']
......@@ -1306,11 +1281,19 @@ class Buildout(DictMixin):
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)
sig = self._signature_cache[reqs]
except KeyError:
req = pkg_resources.Requirement.parse(reqs)
sig = self._signature_cache[reqs] = sorted(set(
_dists_sig(pkg_resources.working_set.resolve([req]))))
self._initializing.append((options, sig))
try:
recipe = recipe_class(self, options.name, options)
options['__buildout_signature__']
finally:
del self._initializing[-1]
return recipe
def __getitem__(self, section):
__doing__ = 'Getting section %s.', section
......@@ -1327,9 +1310,13 @@ class Buildout(DictMixin):
options._initialize()
if self._initializing:
caller = self._initializing[-1]
if 'buildout' != section != caller.name:
caller.depends.add(section)
caller = self._initializing[-1][0]
if 'buildout' != section and not (
section in caller.depends or
# Do not only check the caller,
# because of circular dependencies during substitutions.
section in (x[0].name for x in self._initializing)):
caller.depends.add(section)
return options
def __setitem__(self, name, data):
......@@ -1441,6 +1428,11 @@ class Options(DictMixin):
self.recipe = self.buildout.initialize(self, *_recipe(self._data))
self.buildout._parts.append(name)
m = md5()
for item in sorted(self.items()):
m.update(('%r\0%r\0' % item).encode())
self.items_signature = '%s:%s' % (name, m.hexdigest())
def _do_extend_raw(self, name, data, doing):
if name == 'buildout':
return data
......@@ -1502,6 +1494,16 @@ class Options(DictMixin):
if v is None:
v = self._raw.get(option)
if v is None:
if option == '__buildout_signature__':
buildout = self.buildout
options, sig = buildout._initializing[-1]
if options is self:
self.depends = frozenset(self.depends)
v = self._data[option] = ' '.join(sig + [
buildout[dependency].items_signature
for dependency in sorted(self.depends)])
return v
raise zc.buildout.UserError("premature access to " + option)
return default
__doing__ = 'Getting option %s:%s.', self.name, option
......@@ -1559,7 +1561,7 @@ class Options(DictMixin):
section = self.name
options = self
else:
self.buildout._initializing.append(self)
self.buildout._initializing.append((self,))
try:
options = self.buildout[section]
finally:
......
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