initial commit
This commit is contained in:
87
libraries/FastLED/ci/util/output_formatter.py
Normal file
87
libraries/FastLED/ci/util/output_formatter.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import time
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class OutputFormatter(Protocol):
|
||||
"""Protocol for output formatters used with RunningProcess."""
|
||||
|
||||
def begin(self) -> None: ...
|
||||
|
||||
def transform(self, line: str) -> str: ...
|
||||
|
||||
def end(self) -> None: ...
|
||||
|
||||
|
||||
class NullOutputFormatter:
|
||||
"""No-op formatter that returns input unchanged and has no lifecycle effects."""
|
||||
|
||||
def begin(self) -> None:
|
||||
return None
|
||||
|
||||
def transform(self, line: str) -> str:
|
||||
return line
|
||||
|
||||
def end(self) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class _MultiPathSubstitutionFormatter:
|
||||
"""Formatter that applies multiple path replacements and prefixes timestamps."""
|
||||
|
||||
def __init__(self, substitutions: list[tuple[str, str, str]]) -> None:
|
||||
"""Initialize with list of (needle, regex_pattern, replacement) tuples."""
|
||||
self._substitutions: list[tuple[str, str, re.Pattern[str]]] = []
|
||||
for needle, regex_pattern, replacement in substitutions:
|
||||
compiled_pattern = re.compile(regex_pattern)
|
||||
self._substitutions.append((needle, replacement, compiled_pattern))
|
||||
self._start_time: float = 0.0
|
||||
|
||||
def begin(self) -> None:
|
||||
self._start_time = time.time()
|
||||
|
||||
def transform(self, line: str) -> str:
|
||||
if not line:
|
||||
return line
|
||||
formatted: str = self._format_paths(line)
|
||||
elapsed: float = time.time() - self._start_time
|
||||
return f"{elapsed:.2f} {formatted}"
|
||||
|
||||
def end(self) -> None:
|
||||
return None
|
||||
|
||||
def _format_paths(self, line: str) -> str:
|
||||
result = line
|
||||
for needle, replacement, compiled_pattern in self._substitutions:
|
||||
if needle in result and compiled_pattern.search(result):
|
||||
result = compiled_pattern.sub(replacement, result)
|
||||
return result
|
||||
|
||||
|
||||
def create_sketch_path_formatter(example: str) -> OutputFormatter:
|
||||
"""Create a formatter that maps lib/FastLED paths to src/ and src/sketch paths to examples/{example}/ and timestamps lines.
|
||||
|
||||
Args:
|
||||
example: Example name or path (e.g., "Pintest" or "examples/SmartMatrix").
|
||||
|
||||
Returns:
|
||||
OutputFormatter: Configured formatter instance.
|
||||
"""
|
||||
# Normalize example path
|
||||
display_example_str: str
|
||||
if "/" in example or "\\" in example:
|
||||
display_example_str = example.replace("\\", "/")
|
||||
else:
|
||||
display_example_str = f"examples/{example}"
|
||||
|
||||
# Define multiple path substitutions
|
||||
substitutions = [
|
||||
# Replace lib/FastLED/ paths with src/ for better UX
|
||||
("lib/FastLED", r"lib[/\\]+FastLED[/\\]+", "src/"),
|
||||
# Replace src/sketch/ paths with examples/{example}/
|
||||
("sketch", r"src[/\\]+sketch[/\\]+", f"{display_example_str}/"),
|
||||
]
|
||||
|
||||
return _MultiPathSubstitutionFormatter(substitutions)
|
||||
Reference in New Issue
Block a user