aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2020-02-29 18:17:52 -0800
committerZac Medico <zmedico@gentoo.org>2020-02-29 20:29:41 -0800
commit73f72f526a66b9953a46868cc1390fde2820997f (patch)
treef6463a8896a80e667d0782fc47de312f12a2a75c /lib/_emerge
parent_PostPhaseCommands: avoid CancelledError in _soname_deps_qa done callback (diff)
downloadportage-73f72f526a66b9953a46868cc1390fde2820997f.tar.gz
portage-73f72f526a66b9953a46868cc1390fde2820997f.tar.bz2
portage-73f72f526a66b9953a46868cc1390fde2820997f.zip
Support PORTAGE_LOG_FILTER_FILE (bug 709746)
This variable specifies a command that filters build log output to a log file. The plan is to extend this to support a separate filter for tty output in the future. In order to enable the EbuildPhase class to write elog messages to the build log with PORTAGE_LOG_FILTER_FILE support, convert its _elog method to a coroutine, and add a SchedulerInterface async_output method for it to use. Bug: https://bugs.gentoo.org/709746 Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/_emerge')
-rw-r--r--lib/_emerge/AbstractEbuildProcess.py2
-rw-r--r--lib/_emerge/EbuildPhase.py36
-rw-r--r--lib/_emerge/SpawnProcess.py32
3 files changed, 55 insertions, 15 deletions
diff --git a/lib/_emerge/AbstractEbuildProcess.py b/lib/_emerge/AbstractEbuildProcess.py
index d1a6d1c4e..3732f80ed 100644
--- a/lib/_emerge/AbstractEbuildProcess.py
+++ b/lib/_emerge/AbstractEbuildProcess.py
@@ -181,6 +181,8 @@ class AbstractEbuildProcess(SpawnProcess):
null_fd = os.open('/dev/null', os.O_RDONLY)
self.fd_pipes[0] = null_fd
+ self.log_filter_file = self.settings.get('PORTAGE_LOG_FILTER_FILE')
+
try:
yield SpawnProcess._async_start(self)
finally:
diff --git a/lib/_emerge/EbuildPhase.py b/lib/_emerge/EbuildPhase.py
index f6b380e05..927a74b98 100644
--- a/lib/_emerge/EbuildPhase.py
+++ b/lib/_emerge/EbuildPhase.py
@@ -26,6 +26,8 @@ from portage.package.ebuild.prepare_build_dirs import (_prepare_workdir,
from portage.util.futures.compat_coroutine import coroutine, coroutine_return
from portage.util import writemsg
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture
+from portage.util._async.BuildLogger import BuildLogger
+from portage.util.futures import asyncio
from portage.util.futures.executor.fork import ForkExecutor
try:
@@ -130,7 +132,7 @@ class EbuildPhase(CompositeTask):
# Force background=True for this header since it's intended
# for the log and it doesn't necessarily need to be visible
# elsewhere.
- self._elog('einfo', msg, background=True)
+ yield self._elog('einfo', msg, background=True)
if self.phase == 'package':
if 'PORTAGE_BINPKG_TMPFILE' not in self.settings:
@@ -392,6 +394,7 @@ class EbuildPhase(CompositeTask):
self.returncode = 1
self.wait()
+ @coroutine
def _elog(self, elog_funcname, lines, background=None):
if background is None:
background = self.background
@@ -408,11 +411,30 @@ class EbuildPhase(CompositeTask):
portage.output.havecolor = global_havecolor
msg = out.getvalue()
if msg:
- log_path = None
- if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
- log_path = self.settings.get("PORTAGE_LOG_FILE")
- self.scheduler.output(msg, log_path=log_path,
- background=background)
+ build_logger = None
+ try:
+ log_file = None
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ if log_path:
+ build_logger = BuildLogger(env=self.settings.environ(),
+ log_path=log_path,
+ log_filter_file=self.settings.get('PORTAGE_LOG_FILTER_FILE'),
+ scheduler=self.scheduler)
+ yield build_logger.async_start()
+ log_file = build_logger.stdin
+
+ yield self.scheduler.async_output(msg, log_file=log_file,
+ background=background)
+
+ if build_logger is not None:
+ build_logger.stdin.close()
+ yield build_logger.async_wait()
+ except asyncio.CancelledError:
+ if build_logger is not None:
+ build_logger.cancel()
+ raise
class _PostPhaseCommands(CompositeTask):
@@ -481,4 +503,4 @@ class _PostPhaseCommands(CompositeTask):
qa_msg.extend("\t%s: %s" % (filename, " ".join(sorted(soname_deps)))
for filename, soname_deps in unresolved)
qa_msg.append("")
- self.elog("eqawarn", qa_msg)
+ yield self.elog("eqawarn", qa_msg)
diff --git a/lib/_emerge/SpawnProcess.py b/lib/_emerge/SpawnProcess.py
index ab7971ca8..34668b287 100644
--- a/lib/_emerge/SpawnProcess.py
+++ b/lib/_emerge/SpawnProcess.py
@@ -19,6 +19,7 @@ from portage.const import BASH_BINARY
from portage.localization import _
from portage.output import EOutput
from portage.util import writemsg_level
+from portage.util._async.BuildLogger import BuildLogger
from portage.util._async.PipeLogger import PipeLogger
from portage.util.futures import asyncio
from portage.util.futures.compat_coroutine import coroutine
@@ -36,7 +37,7 @@ class SpawnProcess(SubProcess):
"path_lookup", "pre_exec", "close_fds", "cgroup",
"unshare_ipc", "unshare_mount", "unshare_pid", "unshare_net")
- __slots__ = ("args",) + \
+ __slots__ = ("args", "log_filter_file") + \
_spawn_kwarg_names + ("_main_task", "_selinux_type",)
# Max number of attempts to kill the processes listed in cgroup.procs,
@@ -142,30 +143,45 @@ class SpawnProcess(SubProcess):
fcntl.fcntl(stdout_fd,
fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
- pipe_logger = PipeLogger(background=self.background,
- scheduler=self.scheduler, input_fd=master_fd,
- log_file_path=log_file_path,
- stdout_fd=stdout_fd)
+ build_logger = BuildLogger(env=self.env,
+ log_path=log_file_path,
+ log_filter_file=self.log_filter_file,
+ scheduler=self.scheduler)
+
self._registered = True
+ pipe_logger = None
try:
+ yield build_logger.async_start()
+
+ pipe_logger = PipeLogger(background=self.background,
+ scheduler=self.scheduler, input_fd=master_fd,
+ log_file_path=build_logger.stdin,
+ stdout_fd=stdout_fd)
+
yield pipe_logger.async_start()
except asyncio.CancelledError:
- if pipe_logger.poll() is None:
+ if pipe_logger is not None and pipe_logger.poll() is None:
pipe_logger.cancel()
+ if build_logger.poll() is None:
+ build_logger.cancel()
raise
self._main_task = asyncio.ensure_future(
- self._main(pipe_logger), loop=self.scheduler)
+ self._main(pipe_logger, build_logger), loop=self.scheduler)
self._main_task.add_done_callback(self._main_exit)
@coroutine
- def _main(self, pipe_logger):
+ def _main(self, pipe_logger, build_logger):
try:
if pipe_logger.poll() is None:
yield pipe_logger.async_wait()
+ if build_logger.poll() is None:
+ yield build_logger.async_wait()
except asyncio.CancelledError:
if pipe_logger.poll() is None:
pipe_logger.cancel()
+ if build_logger.poll() is None:
+ build_logger.cancel()
raise
def _main_exit(self, main_task):