@@ -, +, @@ pre-update) etckeeper pre-install ;; post-update) etckeeper post-install ;; --- bin/dispatch-conf | 7 ++++++- lib/portage/dispatch_conf.py | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) --- a/bin/dispatch-conf +++ a/bin/dispatch-conf @@ -29,7 +29,7 @@ import portage portage._internal_caller = True from portage import os, shutil from portage import _encodings, _unicode_decode -from portage.dispatch_conf import diffstatusoutput, diff_mixed_wrapper +from portage.dispatch_conf import diffstatusoutput, diff_mixed_wrapper, perform_conf_update_hooks from portage.process import find_binary, spawn from portage.util import writemsg, writemsg_stdout @@ -382,11 +382,16 @@ class dispatch: encoding=_encodings["stdio"]) as f: f.write(output + "\n") + perform_conf_update_hooks("pre-update", curconf) + try: os.rename(newconf, curconf) except (IOError, os.error) as why: writemsg('dispatch-conf: Error renaming %s to %s: %s; fatal\n' % \ (newconf, curconf, str(why)), noiselevel=-1) + return + + perform_conf_update_hooks("post-update", curconf) def post_process(self, curconf): --- a/lib/portage/dispatch_conf.py +++ a/lib/portage/dispatch_conf.py @@ -16,11 +16,13 @@ import subprocess import sys import tempfile +from collections import OrderedDict + import portage from portage import _encodings, os, shutil from portage.env.loaders import KeyValuePairFileLoader from portage.localization import _ -from portage.util import shlex_split, varexpand +from portage.util import shlex_split, varexpand, _recursive_file_list from portage.util.path import iter_parents RCS_BRANCH = '1.1.1' @@ -386,3 +388,24 @@ def file_archive_post_process(archive): if os.path.isdir(dest) and not os.path.islink(dest): _file_archive_rotate(dest) os.rename(archive + '.dist.new', dest) + +def perform_conf_update_hooks(kind, conf): + conf_update_dir = os.path.join(portage.settings["PORTAGE_CONFIGROOT"], + portage.USER_CONFIG_PATH, "conf-update.d") + hooks = OrderedDict() + for filepath in _recursive_file_list(conf_update_dir): + name = filepath.split(conf_update_dir)[1].lstrip(os.sep) + if os.access(filepath, os.X_OK): + hooks[filepath] = name + else: + writemsg_level(" %s %s hook: '%s' is not executable\n" + % (warn("*"), _dir, _unicode_decode(name),), + level=logging.WARN, noiselevel=2) + + for filepath in hooks: + retval = portage.process.spawn([filepath, kind, conf]) + + if retval != os.EX_OK: + writemsg_level(" %s Spawn failed for: %s, %s\n" % (bad("*"), + _unicode_decode(_hooks[filepath]), filepath), + level=logging.ERROR, noiselevel=-1) --