xref: /aosp_15_r20/external/pigweed/pw_presubmit/py/pw_presubmit/bazel_parser.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2022 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Extracts a concise error from a bazel log."""
15
16from pathlib import Path
17import re
18import sys
19
20
21def parse_bazel_stdout(bazel_stdout: Path) -> str:
22    """Extracts a concise error from a bazel log."""
23    seen_error: bool = False
24    error_lines: list[str] = []
25
26    with bazel_stdout.open() as ins:
27        for line in ins:
28            # Trailing whitespace isn't significant, as it doesn't affect the
29            # way the line shows up in the logs. However, leading whitespace may
30            # be significant, especially for compiler error messages.
31            line = line.rstrip()
32
33            if re.match(r'^(ERROR|FAIL):', line):
34                seen_error = True
35
36            if seen_error:
37                # Ignore long lines that just show the environment.
38                if re.search(r' +[\w_]*(PATH|PWD)=.* \\', line):
39                    continue
40
41                # Ignore lines that only show bazel sandboxing.
42                if line.strip().startswith(('(cd /', 'exec env')):
43                    continue
44
45                if line.strip().startswith('Use --sandbox_debug to see'):
46                    continue
47
48                if line.strip().startswith('# Configuration'):
49                    continue
50
51                # Ignore passing and skipped tests.
52                if 'PASSED' in line or 'SKIPPED' in line:
53                    continue
54
55                # Ignore intermixed lines from other build steps.
56                if re.match(r'\[\s*[\d,]+\s*/\s*[\d,]+\s*\]', line):
57                    continue
58
59                if re.match(r'Executed \d+ out of \d+ tests', line):
60                    error_lines.append(line)
61                    break
62
63                line = re.sub(
64                    r'/b/s/w/ir/\S*/bazel-out(/k8-fastbuild)?(/bin)?'
65                    r'(/testlogs?)',
66                    '<truncated>',
67                    line,
68                )
69
70                error_lines.append(line)
71
72    result = '\n'.join(error_lines)
73    return re.sub(r'\n+', '\n', result)
74
75
76if __name__ == '__main__':
77    print(parse_bazel_stdout(Path(sys.argv[1])))
78