[PATCH] dispatch-conf: Add support for update-conf.d hook directory

Florian Schmaus <[email protected]>
Newsgroups gmane.linux.gentoo.portage.devel
Message-ID <[email protected]>
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 <[email protected]>
Closes: https://bugs.gentoo.org/698316
---
 bin/dispatch-conf            |  8 +++++++-
 lib/portage/dispatch_conf.py | 25 ++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/bin/dispatch-conf b/bin/dispatch-conf
index 1759b89b8..ff9698f14 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,17 @@ 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.