1 |
On Fri, 19 Jun 2020 13:39:19 -0700 |
2 |
Zac Medico <zmedico@g.o> wrote: |
3 |
|
4 |
> This variable specifies a command that filters build log output to a |
5 |
> log file. The plan is to extend this to support a separate filter for |
6 |
> tty output in the future. |
7 |
> |
8 |
> In order to enable the EbuildPhase class to write elog messages to |
9 |
> the build log with PORTAGE_LOG_FILTER_FILE_CMD support, convert its |
10 |
> _elog method to a coroutine, and add a SchedulerInterface async_output |
11 |
> method for it to use. |
12 |
> |
13 |
> Use a new BuildLogger class to manage log output (with or without a |
14 |
> filter command), with compression support provided by PipeLogger. |
15 |
> BuildLogger has a stdin property which provides access to a writable |
16 |
> binary file stream (refers to a pipe) that log content is written to. |
17 |
> |
18 |
> Bug: https://bugs.gentoo.org/709746 |
19 |
> Signed-off-by: Zac Medico <zmedico@g.o> |
20 |
> --- |
21 |
> lib/_emerge/AbstractEbuildProcess.py | 3 +- |
22 |
> lib/_emerge/BinpkgFetcher.py | 3 +- |
23 |
> lib/_emerge/EbuildFetcher.py | 3 +- |
24 |
> lib/_emerge/EbuildPhase.py | 47 ++++++-- |
25 |
> lib/_emerge/SpawnProcess.py | 58 +++++++--- |
26 |
> lib/portage/dbapi/_MergeProcess.py | 3 +- |
27 |
> .../ebuild/_config/special_env_vars.py | 8 +- |
28 |
> lib/portage/util/_async/BuildLogger.py | 109 |
29 |
> ++++++++++++++++++ lib/portage/util/_async/SchedulerInterface.py | |
30 |
> 32 ++++- man/make.conf.5 | 7 +- |
31 |
> 10 files changed, 243 insertions(+), 30 deletions(-) |
32 |
> create mode 100644 lib/portage/util/_async/BuildLogger.py |
33 |
> |
34 |
> diff --git a/lib/_emerge/AbstractEbuildProcess.py |
35 |
> b/lib/_emerge/AbstractEbuildProcess.py index 1c1955cfe..ae1aae55f |
36 |
> 100644 --- a/lib/_emerge/AbstractEbuildProcess.py |
37 |
> +++ b/lib/_emerge/AbstractEbuildProcess.py |
38 |
> @@ -1,4 +1,4 @@ |
39 |
> -# Copyright 1999-2019 Gentoo Foundation |
40 |
> +# Copyright 1999-2020 Gentoo Authors |
41 |
> # Distributed under the terms of the GNU General Public License v2 |
42 |
> |
43 |
> import errno |
44 |
> @@ -196,6 +196,7 @@ class AbstractEbuildProcess(SpawnProcess): |
45 |
> null_fd = os.open('/dev/null', os.O_RDONLY) |
46 |
> self.fd_pipes[0] = null_fd |
47 |
> |
48 |
> + self.log_filter_file = |
49 |
> self.settings.get('PORTAGE_LOG_FILTER_FILE_CMD') try: |
50 |
> SpawnProcess._start(self) |
51 |
> finally: |
52 |
> diff --git a/lib/_emerge/BinpkgFetcher.py |
53 |
> b/lib/_emerge/BinpkgFetcher.py index 36d027de3..2e5861cc1 100644 |
54 |
> --- a/lib/_emerge/BinpkgFetcher.py |
55 |
> +++ b/lib/_emerge/BinpkgFetcher.py |
56 |
> @@ -1,4 +1,4 @@ |
57 |
> -# Copyright 1999-2018 Gentoo Foundation |
58 |
> +# Copyright 1999-2020 Gentoo Authors |
59 |
> # Distributed under the terms of the GNU General Public License v2 |
60 |
> |
61 |
> import functools |
62 |
> @@ -158,6 +158,7 @@ class _BinpkgFetcherProcess(SpawnProcess): |
63 |
> self.env = fetch_env |
64 |
> if settings.selinux_enabled(): |
65 |
> self._selinux_type = |
66 |
> settings["PORTAGE_FETCH_T"] |
67 |
> + self.log_filter_file = |
68 |
> settings.get('PORTAGE_LOG_FILTER_FILE_CMD') SpawnProcess._start(self) |
69 |
> |
70 |
> def _pipe(self, fd_pipes): |
71 |
> diff --git a/lib/_emerge/EbuildFetcher.py |
72 |
> b/lib/_emerge/EbuildFetcher.py index 1e40994fb..55349c33c 100644 |
73 |
> --- a/lib/_emerge/EbuildFetcher.py |
74 |
> +++ b/lib/_emerge/EbuildFetcher.py |
75 |
> @@ -1,4 +1,4 @@ |
76 |
> -# Copyright 1999-2018 Gentoo Foundation |
77 |
> +# Copyright 1999-2020 Gentoo Authors |
78 |
> # Distributed under the terms of the GNU General Public License v2 |
79 |
> |
80 |
> import copy |
81 |
> @@ -225,6 +225,7 @@ class _EbuildFetcherProcess(ForkProcess): |
82 |
> settings["NOCOLOR"] = nocolor |
83 |
> |
84 |
> self._settings = settings |
85 |
> + self.log_filter_file = |
86 |
> settings.get('PORTAGE_LOG_FILTER_FILE_CMD') ForkProcess._start(self) |
87 |
> |
88 |
> # Free settings now since it's no longer needed in |
89 |
> diff --git a/lib/_emerge/EbuildPhase.py b/lib/_emerge/EbuildPhase.py |
90 |
> index 477e0ba97..ddb3dc719 100644 |
91 |
> --- a/lib/_emerge/EbuildPhase.py |
92 |
> +++ b/lib/_emerge/EbuildPhase.py |
93 |
> @@ -26,6 +26,8 @@ from portage.package.ebuild.prepare_build_dirs |
94 |
> import (_prepare_workdir, from portage.util.futures.compat_coroutine |
95 |
> import coroutine from portage.util import writemsg |
96 |
> from portage.util._async.AsyncTaskFuture import AsyncTaskFuture |
97 |
> +from portage.util._async.BuildLogger import BuildLogger |
98 |
> +from portage.util.futures import asyncio |
99 |
> from portage.util.futures.executor.fork import ForkExecutor |
100 |
> |
101 |
> try: |
102 |
> @@ -69,6 +71,11 @@ class EbuildPhase(CompositeTask): |
103 |
> _locked_phases = ("setup", "preinst", "postinst", "prerm", |
104 |
> "postrm") |
105 |
> def _start(self): |
106 |
> + future = asyncio.ensure_future(self._async_start(), |
107 |
> loop=self.scheduler) |
108 |
> + self._start_task(AsyncTaskFuture(future=future), |
109 |
> self._async_start_exit) + |
110 |
> + @coroutine |
111 |
> + def _async_start(self): |
112 |
> |
113 |
> need_builddir = self.phase not in |
114 |
> EbuildProcess._phases_without_builddir |
115 |
> @@ -126,7 +133,7 @@ class EbuildPhase(CompositeTask): |
116 |
> # Force background=True for this header |
117 |
> since it's intended # for the log and it doesn't necessarily need to |
118 |
> be visible # elsewhere. |
119 |
> - self._elog('einfo', msg, background=True) |
120 |
> + yield self._elog('einfo', msg, |
121 |
> background=True) |
122 |
> if self.phase == 'package': |
123 |
> if 'PORTAGE_BINPKG_TMPFILE' not in |
124 |
> self.settings: @@ -134,6 +141,12 @@ class EbuildPhase(CompositeTask): |
125 |
> os.path.join(self.settings['PKGDIR'], |
126 |
> self.settings['CATEGORY'], |
127 |
> self.settings['PF']) + '.tbz2' |
128 |
> + def _async_start_exit(self, task): |
129 |
> + task.future.cancelled() or task.future.result() |
130 |
> + if self._default_exit(task) != os.EX_OK: |
131 |
> + self.wait() |
132 |
> + return |
133 |
> + |
134 |
> if self.phase in ("pretend", "prerm"): |
135 |
> env_extractor = |
136 |
> BinpkgEnvExtractor(background=self.background, |
137 |
> scheduler=self.scheduler, settings=self.settings) @@ -391,6 +404,7 @@ |
138 |
> class EbuildPhase(CompositeTask): self.returncode = 1 |
139 |
> self.wait() |
140 |
> |
141 |
> + @coroutine |
142 |
> def _elog(self, elog_funcname, lines, background=None): |
143 |
> if background is None: |
144 |
> background = self.background |
145 |
> @@ -407,11 +421,30 @@ class EbuildPhase(CompositeTask): |
146 |
> portage.output.havecolor = global_havecolor |
147 |
> msg = out.getvalue() |
148 |
> if msg: |
149 |
> - log_path = None |
150 |
> - if self.settings.get("PORTAGE_BACKGROUND") |
151 |
> != "subprocess": |
152 |
> - log_path = |
153 |
> self.settings.get("PORTAGE_LOG_FILE") |
154 |
> - self.scheduler.output(msg, log_path=log_path, |
155 |
> - background=background) |
156 |
> + build_logger = None |
157 |
> + try: |
158 |
> + log_file = None |
159 |
> + log_path = None |
160 |
> + if |
161 |
> self.settings.get("PORTAGE_BACKGROUND") != "subprocess": |
162 |
> + log_path = |
163 |
> self.settings.get("PORTAGE_LOG_FILE") |
164 |
> + if log_path: |
165 |
> + build_logger = |
166 |
> BuildLogger(env=self.settings.environ(), |
167 |
> + log_path=log_path, |
168 |
> + |
169 |
> log_filter_file=self.settings.get('PORTAGE_LOG_FILTER_FILE_CMD'), |
170 |
> + |
171 |
> scheduler=self.scheduler) |
172 |
> + build_logger.start() |
173 |
> + log_file = build_logger.stdin |
174 |
> + |
175 |
> + yield |
176 |
> self.scheduler.async_output(msg, log_file=log_file, |
177 |
> + background=background) |
178 |
> + |
179 |
> + if build_logger is not None: |
180 |
> + build_logger.stdin.close() |
181 |
> + yield |
182 |
> build_logger.async_wait() |
183 |
> + except asyncio.CancelledError: |
184 |
> + if build_logger is not None: |
185 |
> + build_logger.cancel() |
186 |
> + raise |
187 |
> |
188 |
> |
189 |
> class _PostPhaseCommands(CompositeTask): |
190 |
> @@ -480,4 +513,4 @@ class _PostPhaseCommands(CompositeTask): |
191 |
> qa_msg.extend("\t%s: %s" % (filename, " |
192 |
> ".join(sorted(soname_deps))) for filename, soname_deps in unresolved) |
193 |
> qa_msg.append("") |
194 |
> - self.elog("eqawarn", qa_msg) |
195 |
> + yield self.elog("eqawarn", qa_msg) |
196 |
> diff --git a/lib/_emerge/SpawnProcess.py b/lib/_emerge/SpawnProcess.py |
197 |
> index 395d66bb9..f96911571 100644 |
198 |
> --- a/lib/_emerge/SpawnProcess.py |
199 |
> +++ b/lib/_emerge/SpawnProcess.py |
200 |
> @@ -1,4 +1,4 @@ |
201 |
> -# Copyright 2008-2018 Gentoo Foundation |
202 |
> +# Copyright 2008-2020 Gentoo Authors |
203 |
> # Distributed under the terms of the GNU General Public License v2 |
204 |
> |
205 |
> try: |
206 |
> @@ -19,7 +19,10 @@ from portage.const import BASH_BINARY |
207 |
> from portage.localization import _ |
208 |
> from portage.output import EOutput |
209 |
> from portage.util import writemsg_level |
210 |
> +from portage.util._async.BuildLogger import BuildLogger |
211 |
> from portage.util._async.PipeLogger import PipeLogger |
212 |
> +from portage.util.futures import asyncio |
213 |
> +from portage.util.futures.compat_coroutine import coroutine |
214 |
> |
215 |
> class SpawnProcess(SubProcess): |
216 |
> |
217 |
> @@ -34,8 +37,8 @@ class SpawnProcess(SubProcess): |
218 |
> "path_lookup", "pre_exec", "close_fds", "cgroup", |
219 |
> "unshare_ipc", "unshare_mount", "unshare_pid", |
220 |
> "unshare_net") |
221 |
> - __slots__ = ("args",) + \ |
222 |
> - _spawn_kwarg_names + ("_pipe_logger", |
223 |
> "_selinux_type",) |
224 |
> + __slots__ = ("args", "log_filter_file") + \ |
225 |
> + _spawn_kwarg_names + ("_main_task", "_selinux_type",) |
226 |
> |
227 |
> # Max number of attempts to kill the processes listed in |
228 |
> cgroup.procs, # given that processes may fork before they can be |
229 |
> killed. @@ -137,13 +140,43 @@ class SpawnProcess(SubProcess): |
230 |
> fcntl.fcntl(stdout_fd, |
231 |
> fcntl.F_GETFD) | |
232 |
> fcntl.FD_CLOEXEC) |
233 |
> - self._pipe_logger = |
234 |
> PipeLogger(background=self.background, |
235 |
> + build_logger = BuildLogger(env=self.env, |
236 |
> + log_path=log_file_path, |
237 |
> + log_filter_file=self.log_filter_file, |
238 |
> + scheduler=self.scheduler) |
239 |
> + build_logger.start() |
240 |
> + |
241 |
> + pipe_logger = PipeLogger(background=self.background, |
242 |
> scheduler=self.scheduler, input_fd=master_fd, |
243 |
> - log_file_path=log_file_path, |
244 |
> + log_file_path=build_logger.stdin, |
245 |
> stdout_fd=stdout_fd) |
246 |
> - |
247 |
> self._pipe_logger.addExitListener(self._pipe_logger_exit) |
248 |
> - self._pipe_logger.start() |
249 |
> + |
250 |
> + pipe_logger.start() |
251 |
> + |
252 |
> self._registered = True |
253 |
> + self._main_task = |
254 |
> asyncio.ensure_future(self._main(build_logger, pipe_logger), |
255 |
> loop=self.scheduler) |
256 |
> + self._main_task.add_done_callback(self._main_exit) |
257 |
> + |
258 |
> + @coroutine |
259 |
> + def _main(self, build_logger, pipe_logger): |
260 |
> + try: |
261 |
> + if pipe_logger.poll() is None: |
262 |
> + yield pipe_logger.async_wait() |
263 |
> + if build_logger.poll() is None: |
264 |
> + yield build_logger.async_wait() |
265 |
> + except asyncio.CancelledError: |
266 |
> + if pipe_logger.poll() is None: |
267 |
> + pipe_logger.cancel() |
268 |
> + if build_logger.poll() is None: |
269 |
> + build_logger.cancel() |
270 |
> + raise |
271 |
> + |
272 |
> + def _main_exit(self, main_task): |
273 |
> + try: |
274 |
> + main_task.result() |
275 |
> + except asyncio.CancelledError: |
276 |
> + self.cancel() |
277 |
> + self._async_waitpid() |
278 |
> |
279 |
> def _can_log(self, slave_fd): |
280 |
> return True |
281 |
> @@ -167,20 +200,17 @@ class SpawnProcess(SubProcess): |
282 |
> |
283 |
> return spawn_func(args, **kwargs) |
284 |
> |
285 |
> - def _pipe_logger_exit(self, pipe_logger): |
286 |
> - self._pipe_logger = None |
287 |
> - self._async_waitpid() |
288 |
> - |
289 |
> def _unregister(self): |
290 |
> SubProcess._unregister(self) |
291 |
> if self.cgroup is not None: |
292 |
> self._cgroup_cleanup() |
293 |
> self.cgroup = None |
294 |
> - if self._pipe_logger is not None: |
295 |
> - self._pipe_logger.cancel() |
296 |
> - self._pipe_logger = None |
297 |
> + if self._main_task is not None: |
298 |
> + self._main_task.done() or |
299 |
> self._main_task.cancel() |
300 |
> def _cancel(self): |
301 |
> + if self._main_task is not None: |
302 |
> + self._main_task.done() or |
303 |
> self._main_task.cancel() SubProcess._cancel(self) |
304 |
> self._cgroup_cleanup() |
305 |
> |
306 |
> diff --git a/lib/portage/dbapi/_MergeProcess.py |
307 |
> b/lib/portage/dbapi/_MergeProcess.py index 371550079..236d1a255 100644 |
308 |
> --- a/lib/portage/dbapi/_MergeProcess.py |
309 |
> +++ b/lib/portage/dbapi/_MergeProcess.py |
310 |
> @@ -1,4 +1,4 @@ |
311 |
> -# Copyright 2010-2018 Gentoo Foundation |
312 |
> +# Copyright 2010-2020 Gentoo Authors |
313 |
> # Distributed under the terms of the GNU General Public License v2 |
314 |
> |
315 |
> import io |
316 |
> @@ -57,6 +57,7 @@ class MergeProcess(ForkProcess): |
317 |
> self.fd_pipes = self.fd_pipes.copy() |
318 |
> self.fd_pipes.setdefault(0, |
319 |
> portage._get_stdin().fileno()) |
320 |
> + self.log_filter_file = |
321 |
> self.settings.get('PORTAGE_LOG_FILTER_FILE_CMD') super(MergeProcess, |
322 |
> self)._start() |
323 |
> def _lock_vdb(self): |
324 |
> diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py |
325 |
> b/lib/portage/package/ebuild/_config/special_env_vars.py index |
326 |
> 440dd00b2..f44cb9b1b 100644 --- |
327 |
> a/lib/portage/package/ebuild/_config/special_env_vars.py +++ |
328 |
> b/lib/portage/package/ebuild/_config/special_env_vars.py @@ -1,4 +1,4 |
329 |
> @@ -# Copyright 2010-2019 Gentoo Authors |
330 |
> +# Copyright 2010-2020 Gentoo Authors |
331 |
> # Distributed under the terms of the GNU General Public License v2 |
332 |
> |
333 |
> from __future__ import unicode_literals |
334 |
> @@ -175,7 +175,7 @@ environ_filter += [ |
335 |
> "PORTAGE_RO_DISTDIRS", |
336 |
> "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS", |
337 |
> "PORTAGE_RSYNC_RETRIES", "PORTAGE_SSH_OPTS", |
338 |
> "PORTAGE_SYNC_STALE", |
339 |
> - "PORTAGE_USE", |
340 |
> + "PORTAGE_USE", "PORTAGE_LOG_FILTER_FILE_CMD", |
341 |
> "PORTAGE_LOGDIR", "PORTAGE_LOGDIR_CLEAN", |
342 |
> "QUICKPKG_DEFAULT_OPTS", "REPOMAN_DEFAULT_OPTS", |
343 |
> "RESUMECOMMAND", "RESUMECOMMAND_FTP", |
344 |
> @@ -204,7 +204,9 @@ default_globals = { |
345 |
> 'PORTAGE_BZIP2_COMMAND': 'bzip2', |
346 |
> } |
347 |
> |
348 |
> -validate_commands = ('PORTAGE_BZIP2_COMMAND', |
349 |
> 'PORTAGE_BUNZIP2_COMMAND',) +validate_commands = |
350 |
> ('PORTAGE_BZIP2_COMMAND', 'PORTAGE_BUNZIP2_COMMAND', |
351 |
> + 'PORTAGE_LOG_FILTER_FILE_CMD', |
352 |
> +) |
353 |
> |
354 |
> # To enhance usability, make some vars case insensitive |
355 |
> # by forcing them to lower case. |
356 |
> diff --git a/lib/portage/util/_async/BuildLogger.py |
357 |
> b/lib/portage/util/_async/BuildLogger.py new file mode 100644 |
358 |
> index 000000000..f5fea77ea |
359 |
> --- /dev/null |
360 |
> +++ b/lib/portage/util/_async/BuildLogger.py |
361 |
> @@ -0,0 +1,109 @@ |
362 |
> +# Copyright 2020 Gentoo Authors |
363 |
> +# Distributed under the terms of the GNU General Public License v2 |
364 |
> + |
365 |
> +import subprocess |
366 |
> + |
367 |
> +from portage import os |
368 |
> +from portage.util import shlex_split |
369 |
> +from _emerge.AsynchronousTask import AsynchronousTask |
370 |
> +from portage.util._async.PipeLogger import PipeLogger |
371 |
> +from portage.util._async.PopenProcess import PopenProcess |
372 |
> +from portage.util.futures import asyncio |
373 |
> +from portage.util.futures.compat_coroutine import coroutine |
374 |
> + |
375 |
> + |
376 |
> +class BuildLogger(AsynchronousTask): |
377 |
> + """ |
378 |
> + Write to a log file, with compression support provided by |
379 |
> PipeLogger. |
380 |
> + If the log_filter_file parameter is specified, then it is |
381 |
> interpreted |
382 |
> + as a command to execute which filters log output (see the |
383 |
> + PORTAGE_LOG_FILTER_FILE_CMD variable in make.conf(5)). The |
384 |
> stdin property |
385 |
> + provides access to a writable binary file stream (refers to |
386 |
> a pipe) |
387 |
> + that log content should be written to (usually redirected |
388 |
> from |
389 |
> + subprocess stdout and stderr streams). |
390 |
> + """ |
391 |
> + |
392 |
> + __slots__ = ('env', 'log_path', 'log_filter_file', |
393 |
> '_main_task', '_stdin') + |
394 |
> + @property |
395 |
> + def stdin(self): |
396 |
> + return self._stdin |
397 |
> + |
398 |
> + def _start(self): |
399 |
> + filter_proc = None |
400 |
> + log_input = None |
401 |
> + if self.log_path is not None: |
402 |
> + log_filter_file = self.log_filter_file |
403 |
> + if log_filter_file is not None: |
404 |
> + split_value = |
405 |
> shlex_split(log_filter_file) |
406 |
> + log_filter_file = split_value if |
407 |
> split_value else None |
408 |
> + if log_filter_file: |
409 |
> + filter_input, stdin = os.pipe() |
410 |
> + log_input, filter_output = os.pipe() |
411 |
> + try: |
412 |
> + filter_proc = PopenProcess( |
413 |
> + |
414 |
> proc=subprocess.Popen( |
415 |
> + |
416 |
> log_filter_file, |
417 |
> + env=self.env, |
418 |
> + |
419 |
> stdin=filter_input, |
420 |
> + |
421 |
> stdout=filter_output, |
422 |
> + |
423 |
> stderr=filter_output, |
424 |
> + ), |
425 |
> + |
426 |
> scheduler=self.scheduler, |
427 |
> + ) |
428 |
> + filter_proc.start() |
429 |
> + except EnvironmentError: |
430 |
> + # Maybe the command is |
431 |
> missing or broken somehow... |
432 |
> + os.close(filter_input) |
433 |
> + os.close(stdin) |
434 |
> + os.close(log_input) |
435 |
> + os.close(filter_output) |
436 |
> + else: |
437 |
> + self._stdin = |
438 |
> os.fdopen(stdin, 'wb', 0) |
439 |
> + os.close(filter_input) |
440 |
> + os.close(filter_output) |
441 |
> + |
442 |
> + if self._stdin is None: |
443 |
> + # Since log_filter_file is unspecified or |
444 |
> refers to a file |
445 |
> + # that is missing or broken somehow, create |
446 |
> a pipe that |
447 |
> + # logs directly to pipe_logger. |
448 |
> + log_input, stdin = os.pipe() |
449 |
> + self._stdin = os.fdopen(stdin, 'wb', 0) |
450 |
> + |
451 |
> + # Set background=True so that pipe_logger does not |
452 |
> log to stdout. |
453 |
> + pipe_logger = PipeLogger(background=True, |
454 |
> + scheduler=self.scheduler, input_fd=log_input, |
455 |
> + log_file_path=self.log_path) |
456 |
> + pipe_logger.start() |
457 |
> + |
458 |
> + self._main_task = |
459 |
> asyncio.ensure_future(self._main(filter_proc, pipe_logger), |
460 |
> loop=self.scheduler) |
461 |
> + self._main_task.add_done_callback(self._main_exit) |
462 |
> + |
463 |
> + @coroutine |
464 |
> + def _main(self, filter_proc, pipe_logger): |
465 |
> + try: |
466 |
> + if pipe_logger.poll() is None: |
467 |
> + yield pipe_logger.async_wait() |
468 |
> + if filter_proc is not None and |
469 |
> filter_proc.poll() is None: |
470 |
> + yield filter_proc.async_wait() |
471 |
> + except asyncio.CancelledError: |
472 |
> + if pipe_logger.poll() is None: |
473 |
> + pipe_logger.cancel() |
474 |
> + if filter_proc is not None and |
475 |
> filter_proc.poll() is None: |
476 |
> + filter_proc.cancel() |
477 |
> + raise |
478 |
> + |
479 |
> + def _cancel(self): |
480 |
> + if self._main_task is not None: |
481 |
> + self._main_task.done() or |
482 |
> self._main_task.cancel() |
483 |
> + if self._stdin is not None and not |
484 |
> self._stdin.closed: |
485 |
> + self._stdin.close() |
486 |
> + |
487 |
> + def _main_exit(self, main_task): |
488 |
> + try: |
489 |
> + main_task.result() |
490 |
> + except asyncio.CancelledError: |
491 |
> + self.cancel() |
492 |
> + self._was_cancelled() |
493 |
> + self.returncode = self.returncode or 0 |
494 |
> + self._async_wait() |
495 |
> diff --git a/lib/portage/util/_async/SchedulerInterface.py |
496 |
> b/lib/portage/util/_async/SchedulerInterface.py index |
497 |
> ec6417da1..3ff250d1d 100644 --- |
498 |
> a/lib/portage/util/_async/SchedulerInterface.py +++ |
499 |
> b/lib/portage/util/_async/SchedulerInterface.py @@ -1,4 +1,4 @@ |
500 |
> -# Copyright 2012-2018 Gentoo Foundation |
501 |
> +# Copyright 2012-2020 Gentoo Authors |
502 |
> # Distributed under the terms of the GNU General Public License v2 |
503 |
> |
504 |
> import gzip |
505 |
> @@ -7,6 +7,8 @@ import errno |
506 |
> from portage import _encodings |
507 |
> from portage import _unicode_encode |
508 |
> from portage.util import writemsg_level |
509 |
> +from portage.util.futures._asyncio.streams import _writer |
510 |
> +from portage.util.futures.compat_coroutine import coroutine |
511 |
> from ..SlotObject import SlotObject |
512 |
> |
513 |
> class SchedulerInterface(SlotObject): |
514 |
> @@ -53,6 +55,34 @@ class SchedulerInterface(SlotObject): |
515 |
> def _return_false(): |
516 |
> return False |
517 |
> |
518 |
> + @coroutine |
519 |
> + def async_output(self, msg, log_file=None, background=None, |
520 |
> + level=0, noiselevel=-1): |
521 |
> + """ |
522 |
> + Output a msg to stdio (if not in background) and to |
523 |
> a log file |
524 |
> + if provided. |
525 |
> + |
526 |
> + @param msg: a message string, including newline if |
527 |
> appropriate |
528 |
> + @type msg: str |
529 |
> + @param log_file: log file in binary mode |
530 |
> + @type log_file: file |
531 |
> + @param background: send messages only to log (not to |
532 |
> stdio) |
533 |
> + @type background: bool |
534 |
> + @param level: a numeric logging level (see the |
535 |
> logging module) |
536 |
> + @type level: int |
537 |
> + @param noiselevel: passed directly to writemsg |
538 |
> + @type noiselevel: int |
539 |
> + """ |
540 |
> + global_background = self._is_background() |
541 |
> + if background is None or global_background: |
542 |
> + background = global_background |
543 |
> + |
544 |
> + if not background: |
545 |
> + writemsg_level(msg, level=level, |
546 |
> noiselevel=noiselevel) + |
547 |
> + if log_file is not None: |
548 |
> + yield _writer(log_file, _unicode_encode(msg)) |
549 |
> + |
550 |
> def output(self, msg, log_path=None, background=None, |
551 |
> level=0, noiselevel=-1): |
552 |
> """ |
553 |
> diff --git a/man/make.conf.5 b/man/make.conf.5 |
554 |
> index a3bd662ae..eb812150f 100644 |
555 |
> --- a/man/make.conf.5 |
556 |
> +++ b/man/make.conf.5 |
557 |
> @@ -1,4 +1,4 @@ |
558 |
> -.TH "MAKE.CONF" "5" "May 2020" "Portage VERSION" "Portage" |
559 |
> +.TH "MAKE.CONF" "5" "Jun 2020" "Portage VERSION" "Portage" |
560 |
> .SH "NAME" |
561 |
> make.conf \- custom settings for Portage |
562 |
> .SH "SYNOPSIS" |
563 |
> @@ -979,6 +979,11 @@ with an integer pid. For example, a value of |
564 |
> "ionice \-c 3 \-p \\${PID}" will set idle io priority. For more |
565 |
> information about ionice, see \fBionice\fR(1). This variable is unset |
566 |
> by default. .TP |
567 |
> +.B PORTAGE_LOG_FILTER_FILE_CMD |
568 |
> +This variable specifies a command that filters build log output to a |
569 |
> +log file. In order to filter ANSI escape codes from build logs, |
570 |
> +\fBansifilter\fR(1) is a convenient setting for this variable. |
571 |
> +.TP |
572 |
> .B PORTAGE_LOGDIR |
573 |
> This variable defines the directory in which per\-ebuild logs are |
574 |
> kept. Logs are created only when this is set. They are stored as |
575 |
|
576 |
That's a lot of code...but I couldn't spot anything wrong, so looks good |