summaryrefslogtreecommitdiffstats
path: root/meta/lib
diff options
context:
space:
mode:
authorChris Laplante <chris.laplante@agilent.com>2020-07-27 21:35:55 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2020-07-29 10:12:31 +0100
commit1739fee6338a445e4254893bc2bcac64e151949d (patch)
treea2ac77aaa26455055eed35b90793400b9b72bc4b /meta/lib
parent2a401a2959b5ba8948077883c159d3cdcfe268e3 (diff)
downloadpoky-1739fee6338a445e4254893bc2bcac64e151949d.tar.gz
lib/oe/log_colorizer.py: add LogColorizerProxyProgressHandler
This progress handler intercepts log output, stripping any ANSII color escape codes. Then the stripped output is fed to the underlying progress handler which will render the progress bar as usual. (From OE-Core rev: 312fb3c86a3d84e60867b132666c01859f73ceb2) Signed-off-by: Chris Laplante <chris.laplante@agilent.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib')
-rw-r--r--meta/lib/oe/log_colorizer.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/meta/lib/oe/log_colorizer.py b/meta/lib/oe/log_colorizer.py
new file mode 100644
index 0000000000..10021ef880
--- /dev/null
+++ b/meta/lib/oe/log_colorizer.py
@@ -0,0 +1,86 @@
1# Copyright (C) 2020 Agilent Technologies, Inc.
2# Author: Chris Laplante <chris.laplante@agilent.com>
3#
4# Released under the MIT license (see COPYING.MIT)
5
6from bb.progress import ProgressHandler
7from bb.build import create_progress_handler
8import contextlib
9import re
10import os.path
11
12# from https://stackoverflow.com/a/14693789/221061
13ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
14
15
16class LogColorizerProxyProgressHandler(ProgressHandler):
17 """
18 This is a proxy progress handler. It intercepts log output, stripping any
19 ANSII color escape codes. Then the stripped output is fed to the task's
20 original progress handler which will render the progress bar as usual.
21 """
22 def __init__(self, d, outfile=None, otherargs=None):
23 self._task = d.getVar("BB_RUNTASK")
24 self._color_log = None
25 self._nocolor_log = None
26 self._exit_stack = None
27 self._original_ph = None
28
29 self._suppress_color_output = not not d.getVar("LOG_COLORIZER_SUPPRESS_COLORIZED_OUTPUT")
30
31 self._tempdir = d.getVar("T")
32 logfmt = (d.getVar('BB_LOGFMT') or 'log.{task}.{pid}')
33 self._logbasename = logfmt.format(task=self._task, pid=os.getpid())
34
35 # Setup courtesy symlinks
36 for suffix in [".nocolor", ".color"]:
37 loglink = os.path.join(self._tempdir, 'log.{0}{1}'.format(self._task, suffix))
38 logfn = os.path.join(self._tempdir, self._logbasename + suffix)
39 if loglink:
40 bb.utils.remove(loglink)
41
42 try:
43 os.symlink(self._logbasename + suffix, loglink)
44 except OSError:
45 pass
46
47 super().__init__(d, outfile)
48
49 def __enter__(self):
50 with contextlib.ExitStack() as es:
51 self._color_log = es.enter_context(open(os.path.join(self._tempdir, self._logbasename) + ".color", "w"))
52 self._nocolor_log = es.enter_context(open(os.path.join(self._tempdir, self._logbasename) + ".nocolor", "w"))
53
54 # Reconstitute the original progress handler. We will feed stripped output to it so
55 # that the progress bar still shows up for the task.
56 original_ph = self._data.getVarFlag(self._task, "originalprogress")
57 if original_ph:
58 # We don't want task output showing up on the screen twice, so we'll just have
59 # the original progress handler write to /dev/null.
60 # Note the progress handler itself is responsible for closing the devnull handler.
61 devnull = open("/dev/null", "w")
62 self._original_ph = es.enter_context(create_progress_handler(self._task, original_ph, devnull, self._data))
63
64 self._exit_stack = es.pop_all()
65 super().__enter__()
66
67 def __exit__(self, *exc_info):
68 if self._exit_stack:
69 self._exit_stack.__exit__(*exc_info)
70 super().__exit__(*exc_info)
71
72 def write(self, string):
73 # Filter out ANSI escape sequences using the regular expression
74 filtered = ansi_escape.sub('', string)
75
76 if self._color_log:
77 self._color_log.write(string)
78
79 if self._nocolor_log:
80 self._nocolor_log.write(filtered)
81
82 if self._original_ph:
83 # Pass-through to the original progress handler so we get our progress bar
84 self._original_ph.write(filtered)
85
86 super().write(filtered if self._suppress_color_output else string)