diff options
Diffstat (limited to 'lib/portage/elog')
-rw-r--r-- | lib/portage/elog/__init__.py | 9 | ||||
-rw-r--r-- | lib/portage/elog/meson.build | 16 | ||||
-rw-r--r-- | lib/portage/elog/messages.py | 4 | ||||
-rw-r--r-- | lib/portage/elog/mod_custom.py | 73 | ||||
-rw-r--r-- | lib/portage/elog/mod_echo.py | 16 | ||||
-rw-r--r-- | lib/portage/elog/mod_mail.py | 2 | ||||
-rw-r--r-- | lib/portage/elog/mod_mail_summary.py | 4 | ||||
-rw-r--r-- | lib/portage/elog/mod_save.py | 10 | ||||
-rw-r--r-- | lib/portage/elog/mod_save_summary.py | 9 | ||||
-rw-r--r-- | lib/portage/elog/mod_syslog.py | 2 |
10 files changed, 114 insertions, 31 deletions
diff --git a/lib/portage/elog/__init__.py b/lib/portage/elog/__init__.py index 48e2a39de..2d835ddb1 100644 --- a/lib/portage/elog/__init__.py +++ b/lib/portage/elog/__init__.py @@ -2,7 +2,6 @@ # Copyright 2006-2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 -import sys import portage @@ -59,7 +58,7 @@ def _combine_logentries(logentries): for msgtype, msgcontent in logentries[phase]: if previous_type != msgtype: previous_type = msgtype - rValue.append("%s: %s" % (msgtype, phase)) + rValue.append(f"{msgtype}: {phase}") if isinstance(msgcontent, str): rValue.append(msgcontent.rstrip("\n")) else: @@ -200,8 +199,8 @@ def elog_process(cpv, mysettings, phasefilter=None): ) % str(s) ) - writemsg("%s\n" % str(e), noiselevel=-1) + writemsg(f"{str(e)}\n", noiselevel=-1) except AlarmSignal: - writemsg("Timeout in elog_process for system '%s'\n" % s, noiselevel=-1) + writemsg(f"Timeout in elog_process for system '{s}'\n", noiselevel=-1) except PortageException as e: - writemsg("%s\n" % str(e), noiselevel=-1) + writemsg(f"{str(e)}\n", noiselevel=-1) diff --git a/lib/portage/elog/meson.build b/lib/portage/elog/meson.build new file mode 100644 index 000000000..c76b5f017 --- /dev/null +++ b/lib/portage/elog/meson.build @@ -0,0 +1,16 @@ +py.install_sources( + [ + 'filtering.py', + 'messages.py', + 'mod_custom.py', + 'mod_echo.py', + 'mod_mail.py', + 'mod_mail_summary.py', + 'mod_save.py', + 'mod_save_summary.py', + 'mod_syslog.py', + '__init__.py', + ], + subdir : 'portage/elog', + pure : not native_extensions +) diff --git a/lib/portage/elog/messages.py b/lib/portage/elog/messages.py index 6a67a45de..3ec9dd80e 100644 --- a/lib/portage/elog/messages.py +++ b/lib/portage/elog/messages.py @@ -17,7 +17,6 @@ from portage import _encodings from portage import _unicode_encode from portage import _unicode_decode -import io import sys _log_levels = frozenset( @@ -57,9 +56,8 @@ def collect_ebuild_messages(path): logentries[msgfunction] = [] lastmsgtype = None msgcontent = [] - f = io.open( + f = open( _unicode_encode(filename, encoding=_encodings["fs"], errors="strict"), - mode="r", encoding=_encodings["repo.content"], errors="replace", ) diff --git a/lib/portage/elog/mod_custom.py b/lib/portage/elog/mod_custom.py index e0ae77e10..a3e199bcb 100644 --- a/lib/portage/elog/mod_custom.py +++ b/lib/portage/elog/mod_custom.py @@ -1,10 +1,33 @@ # elog/mod_custom.py - elog dispatch module -# Copyright 2006-2020 Gentoo Authors +# Copyright 2006-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 +import types + +import portage import portage.elog.mod_save import portage.exception import portage.process +from portage.util.futures import asyncio + +# Since elog_process is typically called while the event loop is +# running, hold references to spawned processes and wait for them +# asynchronously, ultimately waiting for them if necessary when +# the AsyncioEventLoop _close_main method calls _async_finalize +# via portage.process.run_coroutine_exitfuncs(). +_proc_refs = None + + +def _get_procs() -> list[tuple[portage.process.MultiprocessingProcess, asyncio.Future]]: + """ + Return list of (proc, asyncio.ensure_future(proc.wait())) which is not + inherited from the parent after fork. + """ + global _proc_refs + if _proc_refs is None or _proc_refs.pid != portage.getpid(): + _proc_refs = types.SimpleNamespace(pid=portage.getpid(), procs=[]) + portage.process.atexit_register(_async_finalize) + return _proc_refs.procs def process(mysettings, key, logentries, fulltext): @@ -18,8 +41,50 @@ def process(mysettings, key, logentries, fulltext): mylogcmd = mysettings["PORTAGE_ELOG_COMMAND"] mylogcmd = mylogcmd.replace("${LOGFILE}", elogfilename) mylogcmd = mylogcmd.replace("${PACKAGE}", key) - retval = portage.process.spawn_bash(mylogcmd) - if retval != 0: + loop = asyncio.get_event_loop() + proc = portage.process.spawn_bash(mylogcmd, returnproc=True) + procs = _get_procs() + procs.append((proc, asyncio.ensure_future(proc.wait(), loop=loop))) + for index, (proc, waiter) in reversed(list(enumerate(procs))): + if not waiter.done(): + continue + del procs[index] + if waiter.result() != 0: + raise portage.exception.PortageException( + f"!!! PORTAGE_ELOG_COMMAND failed with exitcode {waiter.result()}" + ) + + +async def _async_finalize(): + """ + Async finalize is preferred, since we can wait for process exit status. + """ + procs = _get_procs() + while procs: + proc, waiter = procs.pop() + if (await waiter) != 0: + raise portage.exception.PortageException( + f"!!! PORTAGE_ELOG_COMMAND failed with exitcode {waiter.result()}" + ) + + +def finalize(): + """ + NOTE: This raises PortageException if there are any processes + still running, so it's better to use _async_finalize instead + (invoked via portage.process.run_coroutine_exitfuncs() in + the AsyncioEventLoop _close_main method). + """ + procs = _get_procs() + while procs: + proc, waiter = procs.pop() + if not waiter.done(): + waiter.cancel() + proc.terminate() + raise portage.exception.PortageException( + f"!!! PORTAGE_ELOG_COMMAND was killed after it was found running in the background (pid {proc.pid})" + ) + elif waiter.result() != 0: raise portage.exception.PortageException( - "!!! PORTAGE_ELOG_COMMAND failed with exitcode %d" % retval + f"!!! PORTAGE_ELOG_COMMAND failed with exitcode {waiter.result()}" ) diff --git a/lib/portage/elog/mod_echo.py b/lib/portage/elog/mod_echo.py index a63939988..1043edf20 100644 --- a/lib/portage/elog/mod_echo.py +++ b/lib/portage/elog/mod_echo.py @@ -22,7 +22,12 @@ def process(mysettings, key, logentries, fulltext): and "PORTAGE_LOG_FILE" in mysettings ): logfile = mysettings["PORTAGE_LOG_FILE"] - _items.append((mysettings["ROOT"], key, logentries, logfile)) + + try: + binary = mysettings.configdict["pkg"]["MERGE_TYPE"] == "binary" + except KeyError: + binary = False + _items.append((mysettings["ROOT"], key, logentries, logfile, binary)) def finalize(): @@ -42,14 +47,17 @@ def finalize(): def _finalize(): global _items printer = EOutput() - for root, key, logentries, logfile in _items: + for root, key, logentries, logfile, binary in _items: + color = "PKG_BINARY_MERGE" if binary else "INFORM" + print() + if root == "/": - printer.einfo(_("Messages for package %s:") % colorize("INFORM", key)) + printer.einfo(_("Messages for package %s:") % colorize(color, key)) else: printer.einfo( _("Messages for package %(pkg)s merged to %(root)s:") - % {"pkg": colorize("INFORM", key), "root": root} + % {"pkg": colorize(color, key), "root": root} ) if logfile is not None: printer.einfo(_("Log file: %s") % colorize("INFORM", logfile)) diff --git a/lib/portage/elog/mod_mail.py b/lib/portage/elog/mod_mail.py index 22083ac5c..47293afc9 100644 --- a/lib/portage/elog/mod_mail.py +++ b/lib/portage/elog/mod_mail.py @@ -41,4 +41,4 @@ def process(mysettings, key, logentries, fulltext): try: portage.mail.send_mail(mysettings, mymessage) except PortageException as e: - writemsg("%s\n" % str(e), noiselevel=-1) + writemsg(f"{str(e)}\n", noiselevel=-1) diff --git a/lib/portage/elog/mod_mail_summary.py b/lib/portage/elog/mod_mail_summary.py index a695290ef..cd356911b 100644 --- a/lib/portage/elog/mod_mail_summary.py +++ b/lib/portage/elog/mod_mail_summary.py @@ -79,7 +79,7 @@ def _finalize(mysettings, items): "process %(pid)d on host %(host)s:\n" ) % {"pid": portage.getpid(), "host": socket.getfqdn()} for key in items: - mybody += "- %s\n" % key + mybody += f"- {key}\n" mymessage = portage.mail.create_message( myfrom, myrecipient, mysubject, mybody, attachments=list(items.values()) @@ -97,6 +97,6 @@ def _finalize(mysettings, items): "Timeout in finalize() for elog system 'mail_summary'\n", noiselevel=-1 ) except PortageException as e: - writemsg("%s\n" % (e,), noiselevel=-1) + writemsg(f"{e}\n", noiselevel=-1) return diff --git a/lib/portage/elog/mod_save.py b/lib/portage/elog/mod_save.py index aedfd0a38..126aded6e 100644 --- a/lib/portage/elog/mod_save.py +++ b/lib/portage/elog/mod_save.py @@ -3,7 +3,6 @@ # Distributed under the terms of the GNU General Public License v2 import errno -import io import time import portage from portage import os @@ -16,12 +15,11 @@ from portage.util import apply_permissions, ensure_dirs, normalize_path def process(mysettings, key, logentries, fulltext): - if mysettings.get("PORTAGE_LOGDIR"): logdir = normalize_path(mysettings["PORTAGE_LOGDIR"]) else: logdir = os.path.join( - os.sep, mysettings["EPREFIX"].lstrip(os.sep), "var", "log", "portage" + os.sep, mysettings["BROOT"].lstrip(os.sep), "var", "log", "portage" ) if not os.path.isdir(logdir): @@ -57,15 +55,15 @@ def process(mysettings, key, logentries, fulltext): _ensure_log_subdirs(logdir, log_subdir) try: - with io.open( + with open( _unicode_encode(elogfilename, encoding=_encodings["fs"], errors="strict"), mode="w", encoding=_encodings["content"], errors="backslashreplace", ) as elogfile: elogfile.write(_unicode_decode(fulltext)) - except IOError as e: - func_call = "open('%s', 'w')" % elogfilename + except OSError as e: + func_call = f"open('{elogfilename}', 'w')" if e.errno == errno.EACCES: raise portage.exception.PermissionDenied(func_call) elif e.errno == errno.EPERM: diff --git a/lib/portage/elog/mod_save_summary.py b/lib/portage/elog/mod_save_summary.py index 939198fdc..d2d10f475 100644 --- a/lib/portage/elog/mod_save_summary.py +++ b/lib/portage/elog/mod_save_summary.py @@ -3,7 +3,6 @@ # Distributed under the terms of the GNU General Public License v2 import errno -import io import time import portage from portage import os @@ -21,7 +20,7 @@ def process(mysettings, key, logentries, fulltext): logdir = normalize_path(mysettings["PORTAGE_LOGDIR"]) else: logdir = os.path.join( - os.sep, mysettings["EPREFIX"].lstrip(os.sep), "var", "log", "portage" + os.sep, mysettings["BROOT"].lstrip(os.sep), "var", "log", "portage" ) if not os.path.isdir(logdir): @@ -41,14 +40,14 @@ def process(mysettings, key, logentries, fulltext): # TODO: Locking elogfilename = elogdir + "/summary.log" try: - elogfile = io.open( + elogfile = open( _unicode_encode(elogfilename, encoding=_encodings["fs"], errors="strict"), mode="a", encoding=_encodings["content"], errors="backslashreplace", ) - except IOError as e: - func_call = "open('%s', 'a')" % elogfilename + except OSError as e: + func_call = f"open('{elogfilename}', 'a')" if e.errno == errno.EACCES: raise portage.exception.PermissionDenied(func_call) elif e.errno == errno.EPERM: diff --git a/lib/portage/elog/mod_syslog.py b/lib/portage/elog/mod_syslog.py index e34bd3a92..b2e2583b4 100644 --- a/lib/portage/elog/mod_syslog.py +++ b/lib/portage/elog/mod_syslog.py @@ -27,6 +27,6 @@ def process(mysettings, key, logentries, fulltext): if isinstance(msgcontent, str): msgcontent = [msgcontent] for line in msgcontent: - line = "%s: %s: %s" % (key, phase, line) + line = f"{key}: {phase}: {line}" syslog.syslog(_pri[msgtype], line.rstrip("\n")) syslog.closelog() |