tan-cli 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. tan/__init__.py +0 -0
  2. tan/__main__.py +120 -0
  3. tan/cli.py +939 -0
  4. tan/command_table.py +265 -0
  5. tan/commands/__init__.py +8 -0
  6. tan/commands/bootstrap_cmd.py +4856 -0
  7. tan/commands/bootstrap_patches.py +164 -0
  8. tan/commands/bootstrap_toolchain_fetch.py +155 -0
  9. tan/commands/bootstrap_toolchain_pin.py +36 -0
  10. tan/commands/build/__init__.py +1 -0
  11. tan/commands/build/configure_inputs.py +277 -0
  12. tan/commands/build/execute.py +1852 -0
  13. tan/commands/build/host_python.py +59 -0
  14. tan/commands/build/link_stale.py +78 -0
  15. tan/commands/build/manifest.py +428 -0
  16. tan/commands/build/materialise.py +81 -0
  17. tan/commands/build/token_substitution.py +381 -0
  18. tan/commands/build/toolchain.py +482 -0
  19. tan/commands/build/user_defines_wipe.py +115 -0
  20. tan/commands/build/workspace_patches.py +65 -0
  21. tan/commands/build_cmd.py +2236 -0
  22. tan/commands/build_output.py +331 -0
  23. tan/commands/clean_cmd.py +1183 -0
  24. tan/commands/completion_cmd.py +786 -0
  25. tan/commands/debug_config_cmd.py +2425 -0
  26. tan/commands/diff_cmd.py +940 -0
  27. tan/commands/doctor_cmd.py +4767 -0
  28. tan/commands/examples_cmd.py +644 -0
  29. tan/commands/explain_cmd.py +1319 -0
  30. tan/commands/faultdecode_cmd.py +931 -0
  31. tan/commands/flash_atoc_guard.py +240 -0
  32. tan/commands/flash_cmd.py +5731 -0
  33. tan/commands/flash_mram_guard.py +150 -0
  34. tan/commands/flash_ram.py +578 -0
  35. tan/commands/flash_raw.py +583 -0
  36. tan/commands/generate_cmd.py +1456 -0
  37. tan/commands/image_cmd.py +753 -0
  38. tan/commands/init_cmd.py +1740 -0
  39. tan/commands/inspect_cmd.py +377 -0
  40. tan/commands/kconfig_cmd.py +734 -0
  41. tan/commands/model_cmd.py +1514 -0
  42. tan/commands/model_device_cmd.py +351 -0
  43. tan/commands/model_device_live.py +234 -0
  44. tan/commands/model_host_cmd.py +430 -0
  45. tan/commands/model_zoo_cmd.py +363 -0
  46. tan/commands/monitor_actions.py +125 -0
  47. tan/commands/monitor_cmd.py +626 -0
  48. tan/commands/monitor_session.py +505 -0
  49. tan/commands/new_som_cmd.py +1522 -0
  50. tan/commands/pinmux_cmd.py +568 -0
  51. tan/commands/presets_cmd.py +1123 -0
  52. tan/commands/probe_cmd.py +421 -0
  53. tan/commands/reset_cmd.py +354 -0
  54. tan/commands/reset_confirm.py +168 -0
  55. tan/commands/run_cmd.py +637 -0
  56. tan/commands/scaffold_cmd.py +490 -0
  57. tan/commands/sdk_cmd.py +1723 -0
  58. tan/commands/size_cmd.py +1020 -0
  59. tan/commands/support_bundle_cmd.py +1073 -0
  60. tan/commands/trace_cmd.py +341 -0
  61. tan/commands/validate_cmd.py +2009 -0
  62. tan/commands/west_forward_cmd.py +736 -0
  63. tan/commands/workspace_patch_check.py +296 -0
  64. tan/core/__init__.py +1 -0
  65. tan/core/alp_conf_pregen.py +100 -0
  66. tan/core/artifact_provenance.py +240 -0
  67. tan/core/atoc_guard.py +276 -0
  68. tan/core/atoc_guard_messages.py +232 -0
  69. tan/core/atoc_replacement.py +118 -0
  70. tan/core/atomic_write.py +178 -0
  71. tan/core/board_context.py +351 -0
  72. tan/core/board_diagnostic.py +111 -0
  73. tan/core/board_files.py +221 -0
  74. tan/core/board_validator.py +542 -0
  75. tan/core/board_validator_compat.py +196 -0
  76. tan/core/board_validator_run.py +129 -0
  77. tan/core/board_validator_schema.py +186 -0
  78. tan/core/board_validator_skew.py +46 -0
  79. tan/core/board_yaml_edit.py +295 -0
  80. tan/core/board_yaml_pos.py +118 -0
  81. tan/core/bootstrap.py +2572 -0
  82. tan/core/build_plan.py +625 -0
  83. tan/core/consent.py +104 -0
  84. tan/core/console_filter.py +245 -0
  85. tan/core/debug_launch.py +1803 -0
  86. tan/core/devicetree_lint.py +168 -0
  87. tan/core/dir_removal.py +229 -0
  88. tan/core/doctor_git.py +172 -0
  89. tan/core/doctor_libraries.py +253 -0
  90. tan/core/doctor_render.py +185 -0
  91. tan/core/doctor_scope.py +66 -0
  92. tan/core/doctor_setools.py +237 -0
  93. tan/core/doctor_stale.py +180 -0
  94. tan/core/document_guards.py +723 -0
  95. tan/core/dp_id.py +97 -0
  96. tan/core/elf_load.py +63 -0
  97. tan/core/error_catalog.py +171 -0
  98. tan/core/example_catalog.py +499 -0
  99. tan/core/example_facets.py +151 -0
  100. tan/core/faultdecode.py +521 -0
  101. tan/core/flash_plan.py +2501 -0
  102. tan/core/flow_d_report.py +381 -0
  103. tan/core/flow_d_uptime.py +164 -0
  104. tan/core/fs_confine.py +130 -0
  105. tan/core/global_flags.py +230 -0
  106. tan/core/host_python.py +210 -0
  107. tan/core/image_bundle.py +247 -0
  108. tan/core/inert.py +147 -0
  109. tan/core/jlink_binary.py +128 -0
  110. tan/core/jlink_probe.py +481 -0
  111. tan/core/jsonc_splice.py +404 -0
  112. tan/core/launch_provenance.py +257 -0
  113. tan/core/link_refusal.py +76 -0
  114. tan/core/metadata_schema.py +376 -0
  115. tan/core/model_check.py +227 -0
  116. tan/core/model_device.py +449 -0
  117. tan/core/model_doctor.py +198 -0
  118. tan/core/model_host.py +48 -0
  119. tan/core/model_list.py +112 -0
  120. tan/core/model_zoo.py +353 -0
  121. tan/core/module_template.py +340 -0
  122. tan/core/mram_link.py +87 -0
  123. tan/core/new_som_ospi.py +94 -0
  124. tan/core/os_class.py +159 -0
  125. tan/core/patch_paths.py +87 -0
  126. tan/core/pending.py +40 -0
  127. tan/core/plain_zephyr_plan.py +138 -0
  128. tan/core/plan_exec.py +373 -0
  129. tan/core/plan_tokens.py +600 -0
  130. tan/core/probe.py +155 -0
  131. tan/core/probe_plan.py +237 -0
  132. tan/core/proxy.py +168 -0
  133. tan/core/publish.py +31 -0
  134. tan/core/python_floor.py +178 -0
  135. tan/core/ram_run.py +694 -0
  136. tan/core/ram_watch.py +231 -0
  137. tan/core/raw_write.py +160 -0
  138. tan/core/reset_plan.py +56 -0
  139. tan/core/run.py +161 -0
  140. tan/core/scaffold.py +2203 -0
  141. tan/core/scaffold_selftest_identity.py +225 -0
  142. tan/core/sdk_default_registry.py +565 -0
  143. tan/core/sdk_discovery.py +996 -0
  144. tan/core/sdk_removal.py +465 -0
  145. tan/core/serial_actions.py +175 -0
  146. tan/core/serial_capture.py +185 -0
  147. tan/core/serial_url.py +45 -0
  148. tan/core/setools.py +608 -0
  149. tan/core/setools_scratch.py +243 -0
  150. tan/core/shapes.py +194 -0
  151. tan/core/size.py +610 -0
  152. tan/core/som_buildability.py +204 -0
  153. tan/core/som_schema_version.py +62 -0
  154. tan/core/subprocess_env.py +201 -0
  155. tan/core/sysbuild_image.py +94 -0
  156. tan/core/system_manifest.py +827 -0
  157. tan/core/text_layout.py +73 -0
  158. tan/core/timestamp.py +182 -0
  159. tan/core/tool_lookup.py +383 -0
  160. tan/core/toolchain_pin.py +117 -0
  161. tan/core/toolchain_provision.py +1224 -0
  162. tan/core/trusted_path.py +134 -0
  163. tan/core/uboot_breakin.py +154 -0
  164. tan/core/uri_reference.py +415 -0
  165. tan/core/user_defines.py +152 -0
  166. tan/core/venv.py +332 -0
  167. tan/core/west_patches.py +143 -0
  168. tan/core/west_workspace_refusal.py +159 -0
  169. tan/core/zephyr_env.py +124 -0
  170. tan/env.py +185 -0
  171. tan/envelope.py +647 -0
  172. tan/exit_codes.py +12 -0
  173. tan/lazy_typer.py +185 -0
  174. tan/model/__init__.py +2 -0
  175. tan/model/_gen_fixture.py +132 -0
  176. tan/model/adapters/__init__.py +116 -0
  177. tan/model/adapters/cpu.py +26 -0
  178. tan/model/adapters/deepx.py +94 -0
  179. tan/model/adapters/drpai.py +242 -0
  180. tan/model/adapters/ethos_u.py +951 -0
  181. tan/model/adapters/executorch.py +55 -0
  182. tan/model/analyze.py +694 -0
  183. tan/model/build.py +304 -0
  184. tan/model/check.py +682 -0
  185. tan/model/manifest.py +625 -0
  186. tan/model/measure.py +216 -0
  187. tan/model/npu_ops_validate.py +130 -0
  188. tan/model/package.py +125 -0
  189. tan/model/perf.py +635 -0
  190. tan/model/perf_apply.py +721 -0
  191. tan/model/prep.py +193 -0
  192. tan/model/sram_fit.py +502 -0
  193. tan/model/targets.py +374 -0
  194. tan/model/tensorio.py +287 -0
  195. tan/net.py +73 -0
  196. tan/output_format.py +213 -0
  197. tan/planner/__init__.py +219 -0
  198. tan/planner/aperture.py +202 -0
  199. tan/planner/buildplan.py +1092 -0
  200. tan/planner/camera_owner.py +192 -0
  201. tan/planner/cameras.py +132 -0
  202. tan/planner/carveout.py +755 -0
  203. tan/planner/cli.py +274 -0
  204. tan/planner/headers.py +315 -0
  205. tan/planner/kconfig.py +2435 -0
  206. tan/planner/kconfig_symbols.py +473 -0
  207. tan/planner/libraries.py +677 -0
  208. tan/planner/link_target.py +237 -0
  209. tan/planner/linux_ownership.py +216 -0
  210. tan/planner/loader.py +1525 -0
  211. tan/planner/manifest.py +116 -0
  212. tan/planner/memory.py +161 -0
  213. tan/planner/memregion.py +56 -0
  214. tan/planner/models.py +533 -0
  215. tan/planner/orchestrator.py +874 -0
  216. tan/planner/ownership.py +203 -0
  217. tan/planner/partition.py +1160 -0
  218. tan/planner/paths.py +32 -0
  219. tan/planner/plain_slice.py +139 -0
  220. tan/planner/project_emit/__init__.py +60 -0
  221. tan/planner/project_emit/bom_netlist.py +375 -0
  222. tan/planner/project_emit/dts.py +580 -0
  223. tan/planner/project_emit/hw_info.py +221 -0
  224. tan/planner/project_emit/native_sim.py +136 -0
  225. tan/planner/project_emit/west_libs.py +213 -0
  226. tan/planner/project_loader.py +264 -0
  227. tan/planner/sdk_capability.py +203 -0
  228. tan/planner/sdk_compat.py +395 -0
  229. tan/planner/secure.py +350 -0
  230. tan/planner/slugs.py +394 -0
  231. tan/planner/som_metadata.py +325 -0
  232. tan/planner/strict_loaders.py +131 -0
  233. tan/planner/template.py +1037 -0
  234. tan/planner/template_pins.py +535 -0
  235. tan/planner/template_rewrite.py +714 -0
  236. tan/planner/topology.py +208 -0
  237. tan/planner/validate.py +365 -0
  238. tan/planner/whole_device_alias.py +67 -0
  239. tan/planner/zephyr_board.py +3510 -0
  240. tan/planner_cli.py +97 -0
  241. tan/planner_emit.py +617 -0
  242. tan/planner_root.py +119 -0
  243. tan/soc_ref.py +58 -0
  244. tan/templates/__init__.py +34 -0
  245. tan/templates/vendored/MANIFEST.md +1862 -0
  246. tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
  247. tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
  248. tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
  249. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
  250. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
  251. tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
  252. tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
  253. tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
  254. tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
  255. tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
  256. tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
  257. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
  258. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
  259. tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
  260. tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
  261. tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
  262. tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
  263. tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
  264. tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
  265. tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
  266. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
  267. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
  268. tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
  269. tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
  270. tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
  271. tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
  272. tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
  273. tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
  274. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
  275. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
  276. tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
  277. tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
  278. tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
  279. tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
  280. tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
  281. tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
  282. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
  283. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
  284. tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
  285. tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
  286. tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
  287. tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
  288. tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
  289. tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
  290. tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
  291. tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
  292. tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
  293. tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
  294. tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
  295. tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
  296. tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
  297. tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
  298. tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
  299. tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
  300. tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
  301. tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
  302. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
  303. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
  304. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
  305. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
  306. tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
  307. tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
  308. tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
  309. tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
  310. tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
  311. tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
  312. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
  313. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
  314. tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
  315. tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
  316. tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
  317. tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
  318. tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
  319. tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
  320. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
  321. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
  322. tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
  323. tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
  324. tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
  325. tan/version.py +102 -0
  326. tan_cli-0.7.0.dist-info/METADATA +125 -0
  327. tan_cli-0.7.0.dist-info/RECORD +330 -0
  328. tan_cli-0.7.0.dist-info/WHEEL +5 -0
  329. tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
  330. tan_cli-0.7.0.dist-info/top_level.txt +1 -0
tan/planner_root.py ADDED
@@ -0,0 +1,119 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Where the relocated planner finds the SDK -- bound once, before import.
3
+
4
+ `tan.planner` is alp-sdk's `scripts/alp_orchestrate/` relocated verbatim. In
5
+ alp-sdk its `paths.py` derived the repo root by walking up from its own
6
+ `__file__`; inside `tan` that walk lands on the `tan` package and every
7
+ `metadata/**` path would be wrong. So the root becomes an explicit binding.
8
+
9
+ **Binding must happen before `tan.planner` is imported.** `paths.py` evaluates
10
+ `REPO = sdk_root()` at module scope, and half the package takes
11
+ `metadata_root: Path = METADATA_ROOT` as a *default argument* -- both freeze at
12
+ import time. An unbound import therefore raises `PlannerRootError` loudly
13
+ rather than silently resolving `metadata/**` against the wrong tree; that is
14
+ the same refuse-don't-degrade posture the executor's token substitution takes
15
+ (`tan/commands/build/token_substitution.py`).
16
+
17
+ `metadata/**` stays in alp-sdk (ADR-0017): what relocated is the generators,
18
+ never the facts. The fact READERS relocated with them -- `resolve_memory_map`,
19
+ `resolve_capabilities`, `silicon_to_kconfig` and `som_unpopulated_capabilities`
20
+ now live in `tan/planner/som_metadata.py`, `peripheral_kconfig` in
21
+ `tan/planner/slugs.py`, `iter_schema_errors` in `tan/planner/loader.py`, the
22
+ SKU/board/pad-route resolvers in `tan/planner/project_loader.py`, and the
23
+ `alp_project.py`-owned emitters in `tan/planner/project_emit/` +
24
+ `tan/planner/zephyr_board.py` -- and every one of them reads the same files out
25
+ of the bound checkout. **No `tan.planner` module imports anything under
26
+ `<sdk_root>/scripts` any more**, which is what makes an in-process emit load zero
27
+ of alp-sdk's Python
28
+ (`tests/parity/test_planner_emit_parity.py::test_the_in_process_path_loads_none_of_the_sdks_python`
29
+ is the measurement, per mode across all twelve).
30
+
31
+ **Binding does NOT put `<sdk_root>/scripts` on `sys.path`, deliberately.** Nothing
32
+ in `tan`'s own execution needs it: every `tan generate` target renders
33
+ in-process, `tan build` plans in-process, and the one remaining SDK script --
34
+ `alp_project.py` under `TAN_GENERATE_EXECUTOR=subprocess` -- is SPAWNED, and a
35
+ spawned interpreter gets its own script directory regardless of this
36
+ process's `sys.path`. (The Kconfig dumper Zephyr's `EXTRA_KCONFIG_TARGET`
37
+ hook spawns is no longer an SDK edge either: `tan.planner.kconfig_symbols`
38
+ renders it into the run's own scratch tree.)
39
+
40
+ Removing the entry is what turns the zero closure from **measured** into
41
+ **structural**. With `<sdk_root>/scripts` importable, a re-introduced
42
+ `from alp_project import ...` would silently work and only a closure measurement
43
+ would catch it; without it, that import fails loudly at the moment it is written.
44
+ The measurement
45
+ (`tests/parity/test_planner_emit_parity.py::test_the_in_process_path_loads_none_of_the_sdks_python`)
46
+ stays as the belt to this braces.
47
+
48
+ A caller that genuinely needs an SDK module by name in tan's own process must put
49
+ the path there itself and own it. Exactly one does: the parity harness's oracle,
50
+ whose `planners` fixture inserts `<sdk>/scripts` explicitly so it can import
51
+ `alp_project` and diff the relocated planner against the original. That is a test
52
+ comparing two implementations, not `tan` depending on one.
53
+ """
54
+
55
+ from __future__ import annotations
56
+
57
+ import sys
58
+ from pathlib import Path
59
+
60
+ __all__ = ["PlannerRootError", "bind_sdk_root", "sdk_root", "emit"]
61
+
62
+
63
+ class PlannerRootError(RuntimeError):
64
+ """The planner's SDK root is unbound, or a rebind came too late."""
65
+
66
+
67
+ _BOUND: Path | None = None
68
+
69
+
70
+ def bind_sdk_root(root: Path | str) -> Path:
71
+ """Point the relocated planner at an alp-sdk checkout. Idempotent.
72
+
73
+ Rebinding to a *different* root once `tan.planner` is imported is an error,
74
+ not a no-op: the already-frozen module constants and default arguments would
75
+ keep reading the first root's `metadata/**` while callers believed the
76
+ second -- a silent wrong-SDK build, which is precisely the split-brain the
77
+ plan's `sdkCommit` guard exists to catch.
78
+
79
+ Binding touches `sys.path` not at all -- see the module docstring. The root is
80
+ a value the relocated planner reads, not an import route.
81
+ """
82
+ global _BOUND
83
+ resolved = Path(root).resolve()
84
+ if (
85
+ _BOUND is not None
86
+ and _BOUND != resolved
87
+ and "tan.planner" in sys.modules
88
+ ):
89
+ raise PlannerRootError(
90
+ f"the planner is already bound to `{_BOUND}` and imported; "
91
+ f"cannot rebind to `{resolved}` in the same process.")
92
+ _BOUND = resolved
93
+ return resolved
94
+
95
+
96
+ def sdk_root() -> Path:
97
+ """The bound alp-sdk checkout root. Raises if unbound."""
98
+ if _BOUND is None:
99
+ raise PlannerRootError(
100
+ "tan.planner was imported before `bind_sdk_root(<alp-sdk root>)`; "
101
+ "its metadata paths freeze at import time, so an unbound import "
102
+ "cannot be repaired -- bind first, then import.")
103
+ return _BOUND
104
+
105
+
106
+ def emit(mode: str, *, root: Path | str, board_yaml: Path,
107
+ build_root: Path = Path("build"), core: str | None = None) -> str:
108
+ """Bind, load `board_yaml`, and return one emit artefact as text.
109
+
110
+ The in-process twin of `python -m tan.planner --emit <mode>`; both route
111
+ through the same `tan.planner.cli.emit_artefact` dispatch so a mode can
112
+ never render differently depending on how it was reached.
113
+ """
114
+ bind_sdk_root(root)
115
+ from tan.planner import load_board_yaml
116
+ from tan.planner.cli import emit_artefact
117
+ project = load_board_yaml(Path(board_yaml))
118
+ return emit_artefact(project, mode, board_yaml=Path(board_yaml),
119
+ build_root=Path(build_root), core=core)
tan/soc_ref.py ADDED
@@ -0,0 +1,58 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Pure `silicon:` ref -> SoC-JSON path resolution.
3
+
4
+ A leaf module: no imports of `tan.planner` or anything else that reads real
5
+ files at import time. `tan.planner.som_metadata` imports `resolve_soc_path`
6
+ from here and re-exports it (its own four call sites keep working
7
+ unchanged); `tan.model.targets` imports it from here directly so that
8
+ `tan.model` stays importable without a bound alp-sdk checkout -- importing
9
+ `tan.planner` pulls in `tan/planner/__init__.py`, which transitively reads
10
+ real `metadata/registries/*` content at import time (`tan/planner/slugs.py`'s
11
+ module-scope `_PERIPHERAL_KCONFIG = peripheral_kconfig()`), a dependency
12
+ `tan.model` never had in alp-sdk and should not gain here.
13
+
14
+ One definition, re-exported -- alp-sdk spent issues #997/#1004/#1096
15
+ collapsing this resolution to a single source; do not create a second copy.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ from pathlib import Path
20
+
21
+
22
+ def resolve_soc_path(silicon: str | None, metadata_root: Path) -> Path | None:
23
+ """Resolve a `vendor:family:part` `silicon:` key to the SoC-JSON path
24
+ it names: `metadata/socs/<vendor>/<family>/<part>.json`.
25
+
26
+ Returns None when `silicon` is falsy or not exactly 3 colon-separated
27
+ parts -- does NOT check the path exists, callers decide what an
28
+ unresolved/missing SoC spec means for them (e.g. a SoM preset with no
29
+ `silicon:` at all is a valid, if incomplete, state; a `silicon:` that
30
+ names a spec that isn't on disk is not).
31
+
32
+ alp-sdk keeps its own copies of this resolution behind differing failure
33
+ shapes (`OrchestratorError`, `ZephyrBoardEmitError`, a diagnostic list);
34
+ `loader._silicon_to_soc_path` is the planner's raising variant. This is the
35
+ soft-fail one `tan.planner.som_metadata` and `tan.model.targets` share.
36
+ """
37
+ if not isinstance(silicon, str) or not silicon:
38
+ # A non-string `silicon:` (e.g. a hand-authored `silicon: 7`) is
39
+ # "not exactly 3 colon-separated parts" exactly as much as a falsy
40
+ # one is -- the docstring above already promises None for that
41
+ # shape, `silicon.split(":")` below just didn't deliver on it
42
+ # (`AttributeError: 'int' object has no attribute 'split'`,
43
+ # tan-cli#967 review). This is a SHARED leaf (re-exported by
44
+ # `tan.planner.som_metadata`, imported directly by
45
+ # `tan.model.targets`) -- fixing it here, once, fixes every caller
46
+ # identically rather than needing a matching guard at each call
47
+ # site. Every existing caller already treats a None return as
48
+ # "unresolved" and reports it through its own error message
49
+ # (`_load_soc_spec` -> `ZephyrBoardEmitError("... is not a
50
+ # triple-colon string")`, `resolve_targets` -> `ValueError`), so
51
+ # this changes a crash into the SAME clean diagnostic those callers
52
+ # already produce for a malformed-but-string ref, not a new
53
+ # behaviour.
54
+ return None
55
+ parts = silicon.split(":")
56
+ if len(parts) != 3:
57
+ return None
58
+ return metadata_root / "socs" / parts[0] / parts[1] / f"{parts[2]}.json"
@@ -0,0 +1,34 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """tan's OWN copy of the SDK scaffold trees `tan init` lays down.
3
+
4
+ ``vendored/`` is ``alp-sdk --emit scaffold`` output captured byte-for-byte (LF,
5
+ no retouching) -- a verbatim copy of ``crates/tan-core/src/wizard/vendored/``,
6
+ which the Rust binary bakes in with ``include_str!``. It is checked in for the
7
+ same reason it is checked in there: **I-32 -- `tan init` is SDK-free.** A
8
+ customer's first command must work with no alp-sdk checkout anywhere on the
9
+ machine, so the scaffold content cannot be fetched, and shelling the SDK's
10
+ scaffold emit would hand `tan init` a dependency it deliberately does not have.
11
+
12
+ Two consequences worth stating where the bytes live:
13
+
14
+ * **Re-vendor by re-running the emit, never by hand-editing these files.**
15
+ ``vendored/MANIFEST.md`` carries the exact source commit and the template x
16
+ SKU matrix. ``tests/core/test_scaffold.py`` byte-diffs this tree against the
17
+ Rust one, so a re-vendor that updates only one language fails there.
18
+ * **LF is load-bearing.** These bytes are written to the customer's files
19
+ verbatim, and the byte-diff above compares them to an LF capture. The repo
20
+ root's ``.gitattributes`` pins ``text eol=lf`` for this path; without it a
21
+ Windows checkout with ``autocrlf=true`` silently rewrites every one.
22
+
23
+ The tree ships in the frozen binary via ``--add-data`` (``scripts/
24
+ build_binary.sh``). It is data, not code, so PyInstaller's static import graph
25
+ does NOT pull it in on its own -- when it is missing, `tan init` reports
26
+ ``init.template-unreadable`` rather than raising (``tan.core.scaffold``).
27
+ """
28
+ from pathlib import Path
29
+
30
+ #: Root of the vendored scaffold trees: ``vendored/<sdk-template-id>/<SKU>/``.
31
+ #: Derived from ``__file__`` so it resolves both from source and from a frozen
32
+ #: onefile bundle, where PyInstaller sets ``__file__`` under ``sys._MEIPASS``
33
+ #: and ``--add-data`` has placed the tree at the same package-relative path.
34
+ VENDORED_ROOT = Path(__file__).resolve().parent / "vendored"