Source code for spack.util.log_parse
# Copyright Spack Project Developers. See COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import io
from typing import List, Optional, TextIO, Tuple, Union
from spack.llnl.util.tty.color import cescape, colorize
from spack.util.ctest_log_parser import BuildError, BuildWarning, CTestLogParser, LogEvent
__all__ = ["parse_log_events", "make_log_context"]
_PARSER: Optional[CTestLogParser] = None
[docs]
def parse_log_events(
stream: Union[str, TextIO], context: int = 6, profile: bool = False, tail: int = 0
) -> Tuple[List[BuildError], List[BuildWarning], Union[LogEvent, None]]:
"""Extract interesting events from a log file.
Args:
stream: build log name or file object
context: lines of context to extract around each log event
profile: print out profile information for parsing
tail: if > 0, also return the last ``tail`` lines
Returns:
two lists containing :class:`~spack.util.ctest_log_parser.BuildError` and
:class:`~spack.util.ctest_log_parser.BuildWarning` objects, plus an optional
:class:`~spack.util.ctest_log_parser.LogEvent` for the tail (None when ``tail=0``).
"""
global _PARSER
if profile:
parser = CTestLogParser(profile=True)
elif _PARSER is None:
_PARSER = parser = CTestLogParser()
else:
parser = _PARSER
result = parser.parse(stream, context, tail)
if profile:
parser.print_timings()
return result
[docs]
def make_log_context(log_events: List[LogEvent]) -> str:
"""Get error context from a log file.
Args:
log_events: list of events created by ``ctest_log_parser.parse()``
Returns:
str: context from the build log with errors highlighted
Parses the log file for lines containing errors, and prints them out with context.
Errors are highlighted in red and warnings in yellow. Events are sorted by line number.
"""
event_colors = {e.line_no: e.color for e in log_events if e.color}
log_events = sorted(log_events, key=lambda e: e.line_no)
out = io.StringIO()
next_line = 1
block_start = -1
block_lines: List[str] = []
def flush_block():
block_end = block_start + len(block_lines) - 1
out.write(colorize("@c{-- lines %d to %d --}\n" % (block_start, block_end)))
out.writelines(block_lines)
block_lines.clear()
for event in log_events:
start = event.start
if start < next_line:
start = next_line
elif block_lines:
flush_block()
if not block_lines:
block_start = start
for i in range(start, event.end):
if i in event_colors:
color = event_colors[i]
block_lines.append(colorize("@%s{> %s}\n" % (color, cescape(event[i]))))
else:
block_lines.append(" %s\n" % event[i])
next_line = event.end
if block_lines:
flush_block()
return out.getvalue()