Extract per-target compilation failures from ninja output. Parses FAILED: lines to identify which targets had errors and collects the associated error output. Handles timestamped output (e.g., "7.59 FAILED: ...") and [code=N] prefixes. Returns: Dict mapping target name to e
(compile_output: str)
| 292 | |
| 293 | |
| 294 | def _extract_compile_failures(compile_output: str) -> dict[str, str]: |
| 295 | """Extract per-target compilation failures from ninja output. |
| 296 | |
| 297 | Parses FAILED: lines to identify which targets had errors and collects |
| 298 | the associated error output. Handles timestamped output (e.g., "7.59 FAILED: ...") |
| 299 | and [code=N] prefixes. |
| 300 | |
| 301 | Returns: |
| 302 | Dict mapping target name to error output text. |
| 303 | """ |
| 304 | failures: dict[str, str] = {} |
| 305 | lines = compile_output.splitlines() |
| 306 | i = 0 |
| 307 | while i < len(lines): |
| 308 | line = lines[i] |
| 309 | if "FAILED:" in line: |
| 310 | target = line.split("FAILED:", 1)[1].strip() |
| 311 | target = re.sub(r"^\[code=\d+\]\s*", "", target) |
| 312 | m = re.match(r"tests[/\\]([^.]+)\.", target) |
| 313 | test_name = m.group(1) if m else "unknown" |
| 314 | |
| 315 | error_lines = [line] |
| 316 | i += 1 |
| 317 | while i < len(lines): |
| 318 | if "FAILED:" in lines[i] or ( |
| 319 | "ninja:" in lines[i] and "build stopped" in lines[i] |
| 320 | ): |
| 321 | break |
| 322 | error_lines.append(lines[i]) |
| 323 | i += 1 |
| 324 | |
| 325 | existing = failures.get(test_name, "") |
| 326 | failures[test_name] = existing + "\n".join(error_lines) + "\n" |
| 327 | else: |
| 328 | i += 1 |
| 329 | |
| 330 | return failures |
| 331 | |
| 332 | |
| 333 | def _write_testlog_failures(build_dir: Path, log_dir: Path) -> None: |
no test coverage detected