Build a list of examples with proper lock management. For fbuild boards, runs synchronously on the main thread so that Ctrl+C / SIGINT is delivered immediately. The Rust native extension (conn.build) can hold the GIL in a worker thread, preventing signal delivery on
(self, examples: list[str])
| 386 | sys.stdout.flush() |
| 387 | |
| 388 | def build(self, examples: list[str]) -> list[Future[SketchResult]]: |
| 389 | """Build a list of examples with proper lock management. |
| 390 | |
| 391 | For fbuild boards, runs synchronously on the main thread so that |
| 392 | Ctrl+C / SIGINT is delivered immediately. The Rust native extension |
| 393 | (conn.build) can hold the GIL in a worker thread, preventing signal |
| 394 | delivery on Windows. |
| 395 | """ |
| 396 | if not examples: |
| 397 | return [] |
| 398 | |
| 399 | # fbuild path: run on main thread for reliable Ctrl+C handling |
| 400 | if self.use_fbuild: |
| 401 | return self._build_fbuild(examples) |
| 402 | |
| 403 | # Acquire the global package lock for the first build (package installation) |
| 404 | |
| 405 | count = len(examples) |
| 406 | |
| 407 | def release_platform_lock(fut: Future[SketchResult]) -> None: |
| 408 | """Release the platform lock when all builds complete.""" |
| 409 | nonlocal count |
| 410 | count -= 1 |
| 411 | if count == 0: |
| 412 | print(f"Releasing platform lock: {self.platform_lock.lock_file_path}\n") |
| 413 | self.platform_lock.release() |
| 414 | |
| 415 | futures: list[Future[SketchResult]] = [] |
| 416 | |
| 417 | # Package installation lock is now handled by daemon (in _internal_build_no_lock) |
| 418 | # No global lock acquire/release needed here |
| 419 | cancelled = threading.Event() |
| 420 | try: |
| 421 | for example in examples: |
| 422 | future = self.executor.submit( |
| 423 | self._internal_build_no_lock, example, cancelled |
| 424 | ) |
| 425 | future.add_done_callback(release_platform_lock) |
| 426 | futures.append(future) |
| 427 | except KeyboardInterrupt as ki: |
| 428 | print("KeyboardInterrupt: Cancelling all builds") |
| 429 | cancelled.set() |
| 430 | for future in futures: |
| 431 | future.cancel() |
| 432 | handle_keyboard_interrupt(ki) |
| 433 | raise |
| 434 | except Exception as e: |
| 435 | print(f"Exception: {e}") |
| 436 | for future in futures: |
| 437 | future.cancel() |
| 438 | raise |
| 439 | |
| 440 | return futures |
| 441 | |
| 442 | def _build_fbuild(self, examples: list[str]) -> list[Future[SketchResult]]: |
| 443 | """Build examples using fbuild, preferring ``ci`` when available. |