aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/portage/elog')
-rw-r--r--lib/portage/elog/__init__.py9
-rw-r--r--lib/portage/elog/meson.build16
-rw-r--r--lib/portage/elog/messages.py4
-rw-r--r--lib/portage/elog/mod_custom.py73
-rw-r--r--lib/portage/elog/mod_echo.py16
-rw-r--r--lib/portage/elog/mod_mail.py2
-rw-r--r--lib/portage/elog/mod_mail_summary.py4
-rw-r--r--lib/portage/elog/mod_save.py10
-rw-r--r--lib/portage/elog/mod_save_summary.py9
-rw-r--r--lib/portage/elog/mod_syslog.py2
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()