1 |
This variable specifies a command that filters stdout and stderr of |
2 |
build logs. |
3 |
|
4 |
Bug: https://bugs.gentoo.org/709746 |
5 |
Signed-off-by: Zac Medico <zmedico@g.o> |
6 |
--- |
7 |
lib/_emerge/AbstractEbuildProcess.py | 8 +++- |
8 |
lib/_emerge/SpawnProcess.py | 43 ++++++++++++++++++- |
9 |
.../ebuild/_config/special_env_vars.py | 2 +- |
10 |
man/make.conf.5 | 3 ++ |
11 |
4 files changed, 52 insertions(+), 4 deletions(-) |
12 |
|
13 |
diff --git a/lib/_emerge/AbstractEbuildProcess.py b/lib/_emerge/AbstractEbuildProcess.py |
14 |
index ddf04e9b3..96801f200 100644 |
15 |
--- a/lib/_emerge/AbstractEbuildProcess.py |
16 |
+++ b/lib/_emerge/AbstractEbuildProcess.py |
17 |
@@ -20,7 +20,7 @@ from portage.package.ebuild._ipc.QueryCommand import QueryCommand |
18 |
from portage import shutil, os |
19 |
from portage.util.futures import asyncio |
20 |
from portage.util._pty import _create_pty_or_pipe |
21 |
-from portage.util import apply_secpass_permissions |
22 |
+from portage.util import apply_secpass_permissions, shlex_split |
23 |
|
24 |
portage.proxy.lazyimport.lazyimport(globals(), |
25 |
'portage.package.ebuild.doebuild:_global_pid_phases', |
26 |
@@ -196,6 +196,12 @@ class AbstractEbuildProcess(SpawnProcess): |
27 |
null_fd = os.open('/dev/null', os.O_RDONLY) |
28 |
self.fd_pipes[0] = null_fd |
29 |
|
30 |
+ log_filter_command = self.settings.get('PORTAGE_LOG_FILTER_COMMAND') |
31 |
+ if log_filter_command is not None: |
32 |
+ log_filter_command = shlex_split(log_filter_command) |
33 |
+ if log_filter_command: |
34 |
+ self.log_filter_command = log_filter_command |
35 |
+ |
36 |
try: |
37 |
SpawnProcess._start(self) |
38 |
finally: |
39 |
diff --git a/lib/_emerge/SpawnProcess.py b/lib/_emerge/SpawnProcess.py |
40 |
index 395d66bb9..f439a5241 100644 |
41 |
--- a/lib/_emerge/SpawnProcess.py |
42 |
+++ b/lib/_emerge/SpawnProcess.py |
43 |
@@ -34,8 +34,8 @@ class SpawnProcess(SubProcess): |
44 |
"path_lookup", "pre_exec", "close_fds", "cgroup", |
45 |
"unshare_ipc", "unshare_mount", "unshare_pid", "unshare_net") |
46 |
|
47 |
- __slots__ = ("args",) + \ |
48 |
- _spawn_kwarg_names + ("_pipe_logger", "_selinux_type",) |
49 |
+ __slots__ = ("args", "log_filter_command") + \ |
50 |
+ _spawn_kwarg_names + ("_filter_proc", "_pipe_logger", "_selinux_type",) |
51 |
|
52 |
# Max number of attempts to kill the processes listed in cgroup.procs, |
53 |
# given that processes may fork before they can be killed. |
54 |
@@ -137,6 +137,32 @@ class SpawnProcess(SubProcess): |
55 |
fcntl.fcntl(stdout_fd, |
56 |
fcntl.F_GETFD) | fcntl.FD_CLOEXEC) |
57 |
|
58 |
+ if self.log_filter_command is not None: |
59 |
+ pr, pw = os.pipe() |
60 |
+ # stderr goes to /dev/null because the program is expected |
61 |
+ # to generate an EIO error when master_fd reaches EOF. |
62 |
+ with open(os.devnull, 'wb', 0) as null_fd: |
63 |
+ filter_fd_pipes = {0: master_fd, 1: pw, 2: null_fd.fileno()} |
64 |
+ self._filter_proc = SpawnProcess( |
65 |
+ args=self.log_filter_command, |
66 |
+ env=self.env, |
67 |
+ fd_pipes=filter_fd_pipes, |
68 |
+ scheduler=self.scheduler) |
69 |
+ self._filter_proc.addExitListener(self._filter_proc_exit) |
70 |
+ try: |
71 |
+ self._filter_proc.start() |
72 |
+ except portage.exception.CommandNotFound: |
73 |
+ self._filter_proc.removeExitListener(self._filter_proc_exit) |
74 |
+ self._filter_proc._unregister() |
75 |
+ self._filter_proc = None |
76 |
+ os.close(pw) |
77 |
+ os.close(pr) |
78 |
+ else: |
79 |
+ os.close(pw) |
80 |
+ os.close(master_fd) |
81 |
+ # Send self._filter_proc output to PipeLogger |
82 |
+ master_fd = pr |
83 |
+ |
84 |
self._pipe_logger = PipeLogger(background=self.background, |
85 |
scheduler=self.scheduler, input_fd=master_fd, |
86 |
log_file_path=log_file_path, |
87 |
@@ -171,11 +197,24 @@ class SpawnProcess(SubProcess): |
88 |
self._pipe_logger = None |
89 |
self._async_waitpid() |
90 |
|
91 |
+ def _filter_proc_exit(self, filter_proc): |
92 |
+ self._filter_proc = None |
93 |
+ |
94 |
+ def _async_waitpid(self): |
95 |
+ if self._filter_proc is not None: |
96 |
+ # All output should have been collected by now, so kill it. |
97 |
+ self._filter_proc.cancel() |
98 |
+ SubProcess._async_waitpid(self) |
99 |
+ |
100 |
def _unregister(self): |
101 |
SubProcess._unregister(self) |
102 |
if self.cgroup is not None: |
103 |
self._cgroup_cleanup() |
104 |
self.cgroup = None |
105 |
+ if self._filter_proc is not None: |
106 |
+ self._filter_proc.removeExitListener(self._filter_proc_exit) |
107 |
+ self._filter_proc.cancel() |
108 |
+ self._filter_proc = None |
109 |
if self._pipe_logger is not None: |
110 |
self._pipe_logger.cancel() |
111 |
self._pipe_logger = None |
112 |
diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py b/lib/portage/package/ebuild/_config/special_env_vars.py |
113 |
index dc01339f7..4f9430e58 100644 |
114 |
--- a/lib/portage/package/ebuild/_config/special_env_vars.py |
115 |
+++ b/lib/portage/package/ebuild/_config/special_env_vars.py |
116 |
@@ -175,7 +175,7 @@ environ_filter += [ |
117 |
"PORTAGE_RO_DISTDIRS", |
118 |
"PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS", |
119 |
"PORTAGE_RSYNC_RETRIES", "PORTAGE_SSH_OPTS", "PORTAGE_SYNC_STALE", |
120 |
- "PORTAGE_USE", |
121 |
+ "PORTAGE_USE", "PORTAGE_LOG_FILTER_COMMAND", |
122 |
"PORTAGE_LOGDIR", "PORTAGE_LOGDIR_CLEAN", |
123 |
"QUICKPKG_DEFAULT_OPTS", "REPOMAN_DEFAULT_OPTS", |
124 |
"RESUMECOMMAND", "RESUMECOMMAND_FTP", |
125 |
diff --git a/man/make.conf.5 b/man/make.conf.5 |
126 |
index f82fed65a..04ac75de4 100644 |
127 |
--- a/man/make.conf.5 |
128 |
+++ b/man/make.conf.5 |
129 |
@@ -979,6 +979,9 @@ with an integer pid. For example, a value of "ionice \-c 3 \-p \\${PID}" |
130 |
will set idle io priority. For more information about ionice, see |
131 |
\fBionice\fR(1). This variable is unset by default. |
132 |
.TP |
133 |
+.B PORTAGE_LOG_FILTER_COMMAND |
134 |
+This variable specifies a command that filters build log content. |
135 |
+.TP |
136 |
.B PORTAGE_LOGDIR |
137 |
This variable defines the directory in which per\-ebuild logs are kept. |
138 |
Logs are created only when this is set. They are stored as |
139 |
-- |
140 |
2.24.1 |