commit: 6e86186244d048e3edd5c11c18cfb4eee98a0d56 Author: Florian Schmaus <flo <AT> geekplace <DOT> eu> AuthorDate: Sun Mar 28 12:55:04 2021 +0000 Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> CommitDate: Sun Aug 22 15:32:07 2021 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=6e861862
dispatch-conf: Add support for conf-update.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 Currently conf-update.d hooks are called with 4 different events: - pre-session - post-session - pre-update - post-update The *-session events are emitted prior starting a new configuration update sesssion, and when it is finished. That is, the pre-session event is emitted just before dispatch-conf displays the first configuration file, and right before it exists. The *-update events are emitted before and after a configuration file has been updated. The path of the configuration file is provided as second hook argument. Signed-off-by: Florian Schmaus <flo <AT> geekplace.eu> Closes: https://bugs.gentoo.org/698316 Bug: https://bugs.gentoo.org/260623 Closes: https://github.com/gentoo/portage/pull/689 Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> bin/dispatch-conf | 13 ++++++++++++- lib/portage/dispatch_conf.py | 14 ++++++++++++++ lib/portage/util/hooks.py | 12 ++++++++++++ man/dispatch-conf.1 | 5 +++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/bin/dispatch-conf b/bin/dispatch-conf index 0fdfbaa81..f36815a52 100755 --- a/bin/dispatch-conf +++ b/bin/dispatch-conf @@ -34,7 +34,8 @@ 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, perform_conf_update_session_hooks) from portage.process import find_binary, spawn from portage.util import writemsg, writemsg_stdout @@ -97,6 +98,8 @@ class dispatch: confs = [] count = 0 + perform_conf_update_session_hooks("pre-session") + config_root = portage.settings["EPREFIX"] or os.sep self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS) @@ -317,6 +320,7 @@ class dispatch: break if c == 'q': + perform_conf_update_session_hooks("post-session") sys.exit (0) if c == 'h': self.do_help () @@ -378,6 +382,8 @@ class dispatch: writemsg_stdout(" * '%s'\n" % frozen, noiselevel=-1) print() + perform_conf_update_session_hooks("post-session") + def replace (self, newconf, curconf): """Replace current config with the new/merged version. Also logs the diff of what changed into the configured log file.""" @@ -387,11 +393,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 3ef659852..851e6c747 100644 --- a/lib/portage/dispatch_conf.py +++ b/lib/portage/dispatch_conf.py @@ -384,3 +384,17 @@ 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): + """Invoke the hooks in the conf-update.d directory. The notification + 'kind' must either be 'pre-update' or 'post-update'. And 'conf' is the + absolute path to the configuration file that is going to be or was + updated.""" + perform_hooks("conf-update.d", kind, conf) + + +def perform_conf_update_session_hooks(kind): + """Invoke the hooks in the conf-update-session.d directory. The + notification 'kind' must either be 'pre-session' or 'post-session'.""" + perform_hooks("conf-update.d", kind) diff --git a/lib/portage/util/hooks.py b/lib/portage/util/hooks.py index d10ec7a59..942b15543 100644 --- a/lib/portage/util/hooks.py +++ b/lib/portage/util/hooks.py @@ -12,6 +12,7 @@ from portage.output import create_color_func from portage.util import writemsg_level, _recursive_file_list from warnings import warn +bad = create_color_func("BAD") warn = create_color_func("WARN") @@ -29,3 +30,14 @@ def get_hooks_from_dir(rel_directory, prefix="/"): level=logging.WARN, noiselevel=2) return hooks + + +def perform_hooks(rel_directory, *argv, prefix="/"): + for filepath, name in get_hooks_from_dir(rel_directory, prefix).items(): + hook_command = filepath + " " + " ".join(map(str, argv)) + retval = portage.process.spawn(hook_command) + + if retval != portage.os.EX_OK: + writemsg_level(" %s Spawn failed for: %s, %s\n" % \ + (bad("*"), name, filepath), + level=logging.ERROR, noiselevel=-1) diff --git a/man/dispatch-conf.1 b/man/dispatch-conf.1 index a3d233bc0..b877b6942 100644 --- a/man/dispatch-conf.1 +++ b/man/dispatch-conf.1 @@ -70,6 +70,11 @@ older permissions of the first check in may be inherited. As mentioned in the \fBci\fR(1) man page, users can control access to RCS files by setting the permissions of the directory containing the files. +.SH "CONF-UPDATE HOOKS" +\fIdispatch\-conf\fR will run hooks in \fB/etc/portage/conf-update.d\fR. +The first argument of the hook is either \fIpre-session\fR, \fIpost-ression\fR, +\fIpre-update\fR, or, \fIpost-update\fR. In case of *-update events, a second +argument containing the path of the configuration file is also provided. .SH "REPORTING BUGS" Please report bugs via https://bugs.gentoo.org/ .SH "AUTHORS"