Commit 61454ae3 authored by Julien Muchembled's avatar Julien Muchembled Committed by Xavier Thompson

[feat] 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 24d5b0bb
......@@ -902,8 +902,25 @@ class Buildout(DictMixin):
# uninstall parts that are no-longer used or who's configs
# 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):
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()
installed_files = old_options.pop('__buildout_installed__')
new_options = self.get(part).copy()
......@@ -913,35 +930,29 @@ class Buildout(DictMixin):
# reinstall.
if not installed_files:
continue
for f in installed_files.split('\n'):
if not os.path.exists(self._buildout_path(f)):
for installed_path in installed_files.split('\n'):
if not os.path.exists(
self._buildout_path(installed_path)):
break
else:
continue
else:
installed_path = None
# output debugging info
if self._logger.getEffectiveLevel() < logging.DEBUG:
for k in old_options:
if k not in new_options:
self._logger.debug("Part %s, dropped option %s.",
part, k)
elif old_options[k] != new_options[k]:
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
if part_index < reinstall_reason_score:
reinstall_reason_score = part_index
reinstall_reason = (
part, old_options, new_options, installed_path)
elif reinstall_reason_score < 0:
self._log_reinstall_reason(logging.DEBUG,
part, old_options, new_options, installed_path)
self._uninstall_part(part, installed_part_options)
installed_parts = [p for p in installed_parts if p != part]
installed_part_options['buildout']['parts'] = (
' '.join(installed_parts))
if reinstall_reason:
self._log_reinstall_reason(logging.INFO, *reinstall_reason)
# Check for unused buildout options:
_check_for_unused_options_in_section(self, 'buildout')
......@@ -1027,6 +1038,22 @@ class Buildout(DictMixin):
if self._log_level < logging.INFO:
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):
# uninstall part
__doing__ = 'Uninstalling %s.', part
......
......@@ -625,6 +625,8 @@ ignore_not_upgrading = (
'Not upgrading because not running a local buildout command.\n'
), '')
os.environ['BUILDOUT_INFO_REINSTALL_REASON'] = '0'
def run_buildout(command):
# Make sure we don't get .buildout
os.environ['HOME'] = os.path.join(os.getcwd(), 'home')
......
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