Ensure ``compile_commands.json`` exists for ``board_name``; return its path. If the DB is already present at any known location (see :func:`_candidate_fbuild_release_dirs`), returns it immediately. Otherwise shells out to ``fbuild build -e --target compiledb`` a
(
project_root: Path, build_root: Path, board_name: str
)
| 92 | |
| 93 | |
| 94 | def ensure_compile_commands( |
| 95 | project_root: Path, build_root: Path, board_name: str |
| 96 | ) -> Path | None: |
| 97 | """Ensure ``compile_commands.json`` exists for ``board_name``; return its path. |
| 98 | |
| 99 | If the DB is already present at any known location (see |
| 100 | :func:`_candidate_fbuild_release_dirs`), returns it immediately. Otherwise |
| 101 | shells out to ``fbuild <project_root> build -e <env> --target compiledb`` |
| 102 | and returns the resulting path. Returns ``None`` if fbuild isn't on PATH |
| 103 | or the subprocess fails. |
| 104 | |
| 105 | Args: |
| 106 | project_root: FastLED repo root (the directory fbuild resolves |
| 107 | ``fbuild.toml`` / ``pyproject.toml`` from). |
| 108 | build_root: The ``.build/`` directory. |
| 109 | board_name: Canonical board / fbuild environment name (e.g. |
| 110 | ``esp32c2``, matching the ``-e`` flag on fbuild). |
| 111 | |
| 112 | Returns: |
| 113 | Path to ``compile_commands.json`` on success, ``None`` otherwise. |
| 114 | """ |
| 115 | cdb = _find_existing_compile_db(project_root, build_root, board_name) |
| 116 | if cdb is not None: |
| 117 | return cdb |
| 118 | |
| 119 | # Canonical FastLED fbuild invocation order (matches |
| 120 | # ``ci/util/fbuild_runner.py:104-114``): project dir goes *before* the |
| 121 | # ``build`` subcommand. ``cwd`` is still set so fbuild's config |
| 122 | # discovery works identically whether the positional is honored or |
| 123 | # ignored by future fbuild versions. |
| 124 | fbuild_exe = get_fbuild_executable() |
| 125 | if fbuild_exe is None: |
| 126 | print( |
| 127 | f"ensure_compile_commands: fbuild executable not found for '{board_name}'", |
| 128 | file=sys.stderr, |
| 129 | ) |
| 130 | return None |
| 131 | try: |
| 132 | subprocess.run( |
| 133 | [ |
| 134 | fbuild_exe, |
| 135 | str(project_root), |
| 136 | "build", |
| 137 | "-e", |
| 138 | board_name, |
| 139 | "--target", |
| 140 | "compiledb", |
| 141 | ], |
| 142 | check=True, |
| 143 | cwd=str(project_root), |
| 144 | ) |
| 145 | except KeyboardInterrupt as ki: |
| 146 | # Per project guideline: all try/except blocks must handle |
| 147 | # KeyboardInterrupt before broader exceptions so Ctrl-C is never |
| 148 | # swallowed. |
| 149 | from ci.util.global_interrupt_handler import handle_keyboard_interrupt |
| 150 | |
| 151 | handle_keyboard_interrupt(ki) |
no test coverage detected