Scan `` /data/`` for ``*.lnk`` asset links. Only the ``data/`` subdirectory is walked. Files whose names do NOT end in ``.lnk`` are ignored — they ship as-is as normal assets and don't need a manifest entry. Args: sketch_dir: Path to the sketch directory (the one
(sketch_dir: Path)
| 134 | |
| 135 | |
| 136 | def scan_sketch_assets(sketch_dir: Path) -> AssetScanResult: |
| 137 | """Scan ``<sketch_dir>/data/`` for ``*.lnk`` asset links. |
| 138 | |
| 139 | Only the ``data/`` subdirectory is walked. Files whose names do NOT end in |
| 140 | ``.lnk`` are ignored — they ship as-is as normal assets and don't need a |
| 141 | manifest entry. |
| 142 | |
| 143 | Args: |
| 144 | sketch_dir: Path to the sketch directory (the one containing the |
| 145 | ``.ino`` / ``.cpp`` file). |
| 146 | |
| 147 | Returns: |
| 148 | :class:`AssetScanResult` with the manifest plus any warnings. |
| 149 | """ |
| 150 | result = AssetScanResult() |
| 151 | data_dir = sketch_dir / "data" |
| 152 | if not data_dir.is_dir(): |
| 153 | return result |
| 154 | |
| 155 | for lnk_path in sorted(data_dir.rglob("*.lnk")): |
| 156 | if not lnk_path.is_file(): |
| 157 | continue |
| 158 | |
| 159 | # Relative asset path, with the ``.lnk`` suffix stripped so the key |
| 160 | # matches the name the sketch will write (e.g. ``"data/track.mp3"``). |
| 161 | rel_with_lnk = lnk_path.relative_to(sketch_dir).as_posix() |
| 162 | if not rel_with_lnk.endswith(".lnk"): |
| 163 | # Defensive — rglob should never hand us one of these, but be safe. |
| 164 | continue |
| 165 | rel_without_lnk = rel_with_lnk[: -len(".lnk")] |
| 166 | |
| 167 | try: |
| 168 | content = lnk_path.read_text(encoding="utf-8") |
| 169 | except UnicodeDecodeError as exc: |
| 170 | result.warnings.append( |
| 171 | f"asset-scan: {lnk_path}: not valid UTF-8 ({exc}); skipped" |
| 172 | ) |
| 173 | continue |
| 174 | except OSError as exc: |
| 175 | result.warnings.append( |
| 176 | f"asset-scan: {lnk_path}: read failed ({exc}); skipped" |
| 177 | ) |
| 178 | continue |
| 179 | |
| 180 | entry = _parse_lnk_content(content) |
| 181 | if entry is None: |
| 182 | result.warnings.append( |
| 183 | f"asset-scan: {lnk_path}: no URL found in .lnk; skipped" |
| 184 | ) |
| 185 | continue |
| 186 | |
| 187 | result.manifest[rel_without_lnk] = entry |
| 188 | |
| 189 | return result |
| 190 | |
| 191 | |
| 192 | def write_manifest_json(scan: AssetScanResult, out_path: Path) -> None: |