Orchestrates parallel execution of lint stages. Handles: - Parallel execution with ThreadPoolExecutor - Dependency-aware scheduling - Output capture and replay - Timeout handling - Ctrl-C cleanup
| 13 | |
| 14 | |
| 15 | class LintOrchestrator: |
| 16 | """ |
| 17 | Orchestrates parallel execution of lint stages. |
| 18 | |
| 19 | Handles: |
| 20 | - Parallel execution with ThreadPoolExecutor |
| 21 | - Dependency-aware scheduling |
| 22 | - Output capture and replay |
| 23 | - Timeout handling |
| 24 | - Ctrl-C cleanup |
| 25 | """ |
| 26 | |
| 27 | def __init__( |
| 28 | self, |
| 29 | stages: list[LintStage], |
| 30 | tracker: DurationTracker, |
| 31 | parallel: bool = True, |
| 32 | ) -> None: |
| 33 | self.stages = stages |
| 34 | self.tracker = tracker |
| 35 | self.parallel = parallel |
| 36 | self.tmpdir: Path | None = None |
| 37 | self.stage_futures: dict[str, Future[tuple[bool, str]]] = {} |
| 38 | self.stage_metadata: dict[str, dict[str, str]] = {} |
| 39 | |
| 40 | def run(self) -> bool: |
| 41 | """ |
| 42 | Run all lint stages. |
| 43 | |
| 44 | Returns: |
| 45 | True if all stages passed, False otherwise |
| 46 | """ |
| 47 | if not self.stages: |
| 48 | return True |
| 49 | |
| 50 | # Create temp directory for output capture |
| 51 | self.tmpdir = Path(tempfile.mkdtemp(prefix="fastled_lint_")) |
| 52 | |
| 53 | try: |
| 54 | if self.parallel and len(self.stages) > 1: |
| 55 | return self._run_parallel() |
| 56 | else: |
| 57 | return self._run_inline() |
| 58 | finally: |
| 59 | # Cleanup temp directory |
| 60 | if self.tmpdir and self.tmpdir.exists(): |
| 61 | import shutil |
| 62 | |
| 63 | shutil.rmtree(self.tmpdir, ignore_errors=True) |
| 64 | |
| 65 | def _run_parallel(self) -> bool: |
| 66 | """Run stages in parallel with ThreadPoolExecutor.""" |
| 67 | assert self.tmpdir is not None, "tmpdir must be initialized before running" |
| 68 | |
| 69 | print("") |
| 70 | print(f"⚡ PARALLEL LINTING ({len(self.stages)} stages)") |
| 71 | print("================================") |
| 72 |