Commit 9e5dcbc6 authored by Julien Muchembled's avatar Julien Muchembled

Be more verbose for the first part to reinstall (changed option or missing path)

Sometimes, most parts are reinstalled for a reason that the user
didn't think about and it can take time to understand why.
Explaining for all parts would be too verbose and useless because
many are reinstalled just because their dependencies changed.
parent a2bcbf2d
...@@ -716,8 +716,25 @@ class Buildout(DictMixin): ...@@ -716,8 +716,25 @@ class Buildout(DictMixin):
# uninstall parts that are no-longer used or who's configs # uninstall parts that are no-longer used or who's configs
# have changed # have changed
if self._logger.getEffectiveLevel() < logging.DEBUG:
reinstall_reason_score = -1
elif int(os.getenv('BUILDOUT_INFO_REINSTALL_REASON') or 1):
# We rely on the fact that installed_parts is sorted according to
# dependencies (unless install_args). This is not the case of
# installed_parts.
reinstall_reason_score = len(installed_parts)
else:
# Provide a way to disable in tests
# or we'd have to update all recipe eggs.
reinstall_reason_score = 0
reinstall_reason = None
for part in reversed(installed_parts): for part in reversed(installed_parts):
if part in install_parts: try:
part_index = install_parts.index(part)
except ValueError:
if not uninstall_missing:
continue
else:
old_options = installed_part_options[part].copy() old_options = installed_part_options[part].copy()
installed_files = old_options.pop('__buildout_installed__') installed_files = old_options.pop('__buildout_installed__')
new_options = self.get(part).copy() new_options = self.get(part).copy()
...@@ -740,35 +757,29 @@ class Buildout(DictMixin): ...@@ -740,35 +757,29 @@ class Buildout(DictMixin):
# reinstall. # reinstall.
if not installed_files: if not installed_files:
continue continue
for f in installed_files.split('\n'): for installed_path in installed_files.split('\n'):
if not os.path.exists(self._buildout_path(f)): if not os.path.exists(
self._buildout_path(installed_path)):
break break
else: else:
continue continue
else:
installed_path = None
# output debugging info if part_index < reinstall_reason_score:
if self._logger.getEffectiveLevel() < logging.DEBUG: reinstall_reason_score = part_index
for k in old_options: reinstall_reason = (
if k not in new_options: part, old_options, new_options, installed_path)
self._logger.debug("Part %s, dropped option %s.", elif reinstall_reason_score < 0:
part, k) self._log_reinstall_reason(logging.DEBUG,
elif old_options[k] != new_options[k]: part, old_options, new_options, installed_path)
self._logger.debug(
"Part %s, option %s changed:\n%r != %r",
part, k, new_options[k], old_options[k],
)
for k in new_options:
if k not in old_options:
self._logger.debug("Part %s, new option %s.",
part, k)
elif not uninstall_missing:
continue
self._uninstall_part(part, installed_part_options) self._uninstall_part(part, installed_part_options)
installed_parts = [p for p in installed_parts if p != part] installed_parts = [p for p in installed_parts if p != part]
installed_part_options['buildout']['parts'] = ( installed_part_options['buildout']['parts'] = (
' '.join(installed_parts)) ' '.join(installed_parts))
if reinstall_reason:
self._log_reinstall_reason(logging.INFO, *reinstall_reason)
# Check for unused buildout options: # Check for unused buildout options:
_check_for_unused_options_in_section(self, 'buildout') _check_for_unused_options_in_section(self, 'buildout')
...@@ -854,6 +865,22 @@ class Buildout(DictMixin): ...@@ -854,6 +865,22 @@ class Buildout(DictMixin):
if self._log_level < logging.INFO: if self._log_level < logging.INFO:
self._save_installed_options() self._save_installed_options()
def _log_reinstall_reason(self, level, part,
old_options, new_options, missing):
log = self._logger.log
if missing:
log(level, "Part %s, missing path: %s", part, missing)
return
for k in old_options:
if k not in new_options:
log(level, "Part %s, dropped option %s.", part, k)
elif old_options[k] != new_options[k]:
log(level, "Part %s, option %s changed: %r != %r",
part, k, new_options[k], old_options[k])
for k in new_options:
if k not in old_options:
log(level, "Part %s, new option %s.", part, k)
def _uninstall_part(self, part, installed_part_options): def _uninstall_part(self, part, installed_part_options):
# uninstall part # uninstall part
__doing__ = 'Uninstalling %s.', part __doing__ = 'Uninstalling %s.', part
......
...@@ -559,3 +559,5 @@ easy_install_deprecated = ( ...@@ -559,3 +559,5 @@ easy_install_deprecated = (
re.compile( re.compile(
'WARNING: The easy_install command is deprecated and will be removed in a future version.\n' 'WARNING: The easy_install command is deprecated and will be removed in a future version.\n'
), '') ), '')
os.environ['BUILDOUT_INFO_REINSTALL_REASON'] = '0'
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