From de63b31f04bd8afdc51935b1bf601cb3e9909884 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 19 Jul 2020 21:49:45 +0200 Subject: [PATCH] dispatch-conf: Add support for update-conf.d hook directory Those hooks can be used by tools that manage /etc to get notified about updated configuration files. For example, etckeeper could hook this mechanism like the following: /etc/portage/conf-update.d/etckeeper case "${1}" in pre-update) etckeeper pre-install ;; post-update) etckeeper post-install ;; esac Signed-off-by: Florian Schmaus Closes: https://bugs.gentoo.org/698316 --- bin/dispatch-conf | 7 ++++++- lib/portage/dispatch_conf.py | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/bin/dispatch-conf b/bin/dispatch-conf index 1759b89b8..0383efa71 100755 --- a/bin/dispatch-conf +++ b/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): diff --git a/lib/portage/dispatch_conf.py b/lib/portage/dispatch_conf.py index 71693bb36..8f40c7724 100644 --- a/lib/portage/dispatch_conf.py +++ b/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) -- 2.26.2