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.
- tan/__init__.py +0 -0
- tan/__main__.py +120 -0
- tan/cli.py +939 -0
- tan/command_table.py +265 -0
- tan/commands/__init__.py +8 -0
- tan/commands/bootstrap_cmd.py +4856 -0
- tan/commands/bootstrap_patches.py +164 -0
- tan/commands/bootstrap_toolchain_fetch.py +155 -0
- tan/commands/bootstrap_toolchain_pin.py +36 -0
- tan/commands/build/__init__.py +1 -0
- tan/commands/build/configure_inputs.py +277 -0
- tan/commands/build/execute.py +1852 -0
- tan/commands/build/host_python.py +59 -0
- tan/commands/build/link_stale.py +78 -0
- tan/commands/build/manifest.py +428 -0
- tan/commands/build/materialise.py +81 -0
- tan/commands/build/token_substitution.py +381 -0
- tan/commands/build/toolchain.py +482 -0
- tan/commands/build/user_defines_wipe.py +115 -0
- tan/commands/build/workspace_patches.py +65 -0
- tan/commands/build_cmd.py +2236 -0
- tan/commands/build_output.py +331 -0
- tan/commands/clean_cmd.py +1183 -0
- tan/commands/completion_cmd.py +786 -0
- tan/commands/debug_config_cmd.py +2425 -0
- tan/commands/diff_cmd.py +940 -0
- tan/commands/doctor_cmd.py +4767 -0
- tan/commands/examples_cmd.py +644 -0
- tan/commands/explain_cmd.py +1319 -0
- tan/commands/faultdecode_cmd.py +931 -0
- tan/commands/flash_atoc_guard.py +240 -0
- tan/commands/flash_cmd.py +5731 -0
- tan/commands/flash_mram_guard.py +150 -0
- tan/commands/flash_ram.py +578 -0
- tan/commands/flash_raw.py +583 -0
- tan/commands/generate_cmd.py +1456 -0
- tan/commands/image_cmd.py +753 -0
- tan/commands/init_cmd.py +1740 -0
- tan/commands/inspect_cmd.py +377 -0
- tan/commands/kconfig_cmd.py +734 -0
- tan/commands/model_cmd.py +1514 -0
- tan/commands/model_device_cmd.py +351 -0
- tan/commands/model_device_live.py +234 -0
- tan/commands/model_host_cmd.py +430 -0
- tan/commands/model_zoo_cmd.py +363 -0
- tan/commands/monitor_actions.py +125 -0
- tan/commands/monitor_cmd.py +626 -0
- tan/commands/monitor_session.py +505 -0
- tan/commands/new_som_cmd.py +1522 -0
- tan/commands/pinmux_cmd.py +568 -0
- tan/commands/presets_cmd.py +1123 -0
- tan/commands/probe_cmd.py +421 -0
- tan/commands/reset_cmd.py +354 -0
- tan/commands/reset_confirm.py +168 -0
- tan/commands/run_cmd.py +637 -0
- tan/commands/scaffold_cmd.py +490 -0
- tan/commands/sdk_cmd.py +1723 -0
- tan/commands/size_cmd.py +1020 -0
- tan/commands/support_bundle_cmd.py +1073 -0
- tan/commands/trace_cmd.py +341 -0
- tan/commands/validate_cmd.py +2009 -0
- tan/commands/west_forward_cmd.py +736 -0
- tan/commands/workspace_patch_check.py +296 -0
- tan/core/__init__.py +1 -0
- tan/core/alp_conf_pregen.py +100 -0
- tan/core/artifact_provenance.py +240 -0
- tan/core/atoc_guard.py +276 -0
- tan/core/atoc_guard_messages.py +232 -0
- tan/core/atoc_replacement.py +118 -0
- tan/core/atomic_write.py +178 -0
- tan/core/board_context.py +351 -0
- tan/core/board_diagnostic.py +111 -0
- tan/core/board_files.py +221 -0
- tan/core/board_validator.py +542 -0
- tan/core/board_validator_compat.py +196 -0
- tan/core/board_validator_run.py +129 -0
- tan/core/board_validator_schema.py +186 -0
- tan/core/board_validator_skew.py +46 -0
- tan/core/board_yaml_edit.py +295 -0
- tan/core/board_yaml_pos.py +118 -0
- tan/core/bootstrap.py +2572 -0
- tan/core/build_plan.py +625 -0
- tan/core/consent.py +104 -0
- tan/core/console_filter.py +245 -0
- tan/core/debug_launch.py +1803 -0
- tan/core/devicetree_lint.py +168 -0
- tan/core/dir_removal.py +229 -0
- tan/core/doctor_git.py +172 -0
- tan/core/doctor_libraries.py +253 -0
- tan/core/doctor_render.py +185 -0
- tan/core/doctor_scope.py +66 -0
- tan/core/doctor_setools.py +237 -0
- tan/core/doctor_stale.py +180 -0
- tan/core/document_guards.py +723 -0
- tan/core/dp_id.py +97 -0
- tan/core/elf_load.py +63 -0
- tan/core/error_catalog.py +171 -0
- tan/core/example_catalog.py +499 -0
- tan/core/example_facets.py +151 -0
- tan/core/faultdecode.py +521 -0
- tan/core/flash_plan.py +2501 -0
- tan/core/flow_d_report.py +381 -0
- tan/core/flow_d_uptime.py +164 -0
- tan/core/fs_confine.py +130 -0
- tan/core/global_flags.py +230 -0
- tan/core/host_python.py +210 -0
- tan/core/image_bundle.py +247 -0
- tan/core/inert.py +147 -0
- tan/core/jlink_binary.py +128 -0
- tan/core/jlink_probe.py +481 -0
- tan/core/jsonc_splice.py +404 -0
- tan/core/launch_provenance.py +257 -0
- tan/core/link_refusal.py +76 -0
- tan/core/metadata_schema.py +376 -0
- tan/core/model_check.py +227 -0
- tan/core/model_device.py +449 -0
- tan/core/model_doctor.py +198 -0
- tan/core/model_host.py +48 -0
- tan/core/model_list.py +112 -0
- tan/core/model_zoo.py +353 -0
- tan/core/module_template.py +340 -0
- tan/core/mram_link.py +87 -0
- tan/core/new_som_ospi.py +94 -0
- tan/core/os_class.py +159 -0
- tan/core/patch_paths.py +87 -0
- tan/core/pending.py +40 -0
- tan/core/plain_zephyr_plan.py +138 -0
- tan/core/plan_exec.py +373 -0
- tan/core/plan_tokens.py +600 -0
- tan/core/probe.py +155 -0
- tan/core/probe_plan.py +237 -0
- tan/core/proxy.py +168 -0
- tan/core/publish.py +31 -0
- tan/core/python_floor.py +178 -0
- tan/core/ram_run.py +694 -0
- tan/core/ram_watch.py +231 -0
- tan/core/raw_write.py +160 -0
- tan/core/reset_plan.py +56 -0
- tan/core/run.py +161 -0
- tan/core/scaffold.py +2203 -0
- tan/core/scaffold_selftest_identity.py +225 -0
- tan/core/sdk_default_registry.py +565 -0
- tan/core/sdk_discovery.py +996 -0
- tan/core/sdk_removal.py +465 -0
- tan/core/serial_actions.py +175 -0
- tan/core/serial_capture.py +185 -0
- tan/core/serial_url.py +45 -0
- tan/core/setools.py +608 -0
- tan/core/setools_scratch.py +243 -0
- tan/core/shapes.py +194 -0
- tan/core/size.py +610 -0
- tan/core/som_buildability.py +204 -0
- tan/core/som_schema_version.py +62 -0
- tan/core/subprocess_env.py +201 -0
- tan/core/sysbuild_image.py +94 -0
- tan/core/system_manifest.py +827 -0
- tan/core/text_layout.py +73 -0
- tan/core/timestamp.py +182 -0
- tan/core/tool_lookup.py +383 -0
- tan/core/toolchain_pin.py +117 -0
- tan/core/toolchain_provision.py +1224 -0
- tan/core/trusted_path.py +134 -0
- tan/core/uboot_breakin.py +154 -0
- tan/core/uri_reference.py +415 -0
- tan/core/user_defines.py +152 -0
- tan/core/venv.py +332 -0
- tan/core/west_patches.py +143 -0
- tan/core/west_workspace_refusal.py +159 -0
- tan/core/zephyr_env.py +124 -0
- tan/env.py +185 -0
- tan/envelope.py +647 -0
- tan/exit_codes.py +12 -0
- tan/lazy_typer.py +185 -0
- tan/model/__init__.py +2 -0
- tan/model/_gen_fixture.py +132 -0
- tan/model/adapters/__init__.py +116 -0
- tan/model/adapters/cpu.py +26 -0
- tan/model/adapters/deepx.py +94 -0
- tan/model/adapters/drpai.py +242 -0
- tan/model/adapters/ethos_u.py +951 -0
- tan/model/adapters/executorch.py +55 -0
- tan/model/analyze.py +694 -0
- tan/model/build.py +304 -0
- tan/model/check.py +682 -0
- tan/model/manifest.py +625 -0
- tan/model/measure.py +216 -0
- tan/model/npu_ops_validate.py +130 -0
- tan/model/package.py +125 -0
- tan/model/perf.py +635 -0
- tan/model/perf_apply.py +721 -0
- tan/model/prep.py +193 -0
- tan/model/sram_fit.py +502 -0
- tan/model/targets.py +374 -0
- tan/model/tensorio.py +287 -0
- tan/net.py +73 -0
- tan/output_format.py +213 -0
- tan/planner/__init__.py +219 -0
- tan/planner/aperture.py +202 -0
- tan/planner/buildplan.py +1092 -0
- tan/planner/camera_owner.py +192 -0
- tan/planner/cameras.py +132 -0
- tan/planner/carveout.py +755 -0
- tan/planner/cli.py +274 -0
- tan/planner/headers.py +315 -0
- tan/planner/kconfig.py +2435 -0
- tan/planner/kconfig_symbols.py +473 -0
- tan/planner/libraries.py +677 -0
- tan/planner/link_target.py +237 -0
- tan/planner/linux_ownership.py +216 -0
- tan/planner/loader.py +1525 -0
- tan/planner/manifest.py +116 -0
- tan/planner/memory.py +161 -0
- tan/planner/memregion.py +56 -0
- tan/planner/models.py +533 -0
- tan/planner/orchestrator.py +874 -0
- tan/planner/ownership.py +203 -0
- tan/planner/partition.py +1160 -0
- tan/planner/paths.py +32 -0
- tan/planner/plain_slice.py +139 -0
- tan/planner/project_emit/__init__.py +60 -0
- tan/planner/project_emit/bom_netlist.py +375 -0
- tan/planner/project_emit/dts.py +580 -0
- tan/planner/project_emit/hw_info.py +221 -0
- tan/planner/project_emit/native_sim.py +136 -0
- tan/planner/project_emit/west_libs.py +213 -0
- tan/planner/project_loader.py +264 -0
- tan/planner/sdk_capability.py +203 -0
- tan/planner/sdk_compat.py +395 -0
- tan/planner/secure.py +350 -0
- tan/planner/slugs.py +394 -0
- tan/planner/som_metadata.py +325 -0
- tan/planner/strict_loaders.py +131 -0
- tan/planner/template.py +1037 -0
- tan/planner/template_pins.py +535 -0
- tan/planner/template_rewrite.py +714 -0
- tan/planner/topology.py +208 -0
- tan/planner/validate.py +365 -0
- tan/planner/whole_device_alias.py +67 -0
- tan/planner/zephyr_board.py +3510 -0
- tan/planner_cli.py +97 -0
- tan/planner_emit.py +617 -0
- tan/planner_root.py +119 -0
- tan/soc_ref.py +58 -0
- tan/templates/__init__.py +34 -0
- tan/templates/vendored/MANIFEST.md +1862 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
- tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
- tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
- tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
- tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
- tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
- tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
- tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
- tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
- tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
- tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
- tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
- tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
- tan/version.py +102 -0
- tan_cli-0.7.0.dist-info/METADATA +125 -0
- tan_cli-0.7.0.dist-info/RECORD +330 -0
- tan_cli-0.7.0.dist-info/WHEEL +5 -0
- tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
- tan_cli-0.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""The seam `tan image` and `tan size` share: both consume what a build
|
|
3
|
+
PRODUCED, so both resolve the same project context, the same build root, and the
|
|
4
|
+
same `build/system-manifest.yaml`.
|
|
5
|
+
|
|
6
|
+
Written once here rather than twice in the two command modules -- that
|
|
7
|
+
duplication is how the two halves of the same rule drift, and I-18 (the
|
|
8
|
+
`west build` nesting) is exactly such a rule: it has to hold identically for the
|
|
9
|
+
slice `tan size` measures and the slice `tan image` archives.
|
|
10
|
+
|
|
11
|
+
Ports the CLI-side halves of `crates/tan-cli/src/commands/{size,image}.rs` --
|
|
12
|
+
`resolve_cli_project_context`, `resolve_sdk_root`, the `app_path`/`--build-root`
|
|
13
|
+
resolution and the manifest load -- all of which are byte-identical between the
|
|
14
|
+
two commands in the oracle.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from tan.core.sdk_discovery import resolve_sdk_root_ladder, resolve_sdk_tiered
|
|
24
|
+
from tan.core.shapes import SDK_MARKER
|
|
25
|
+
from tan.core.system_manifest import (
|
|
26
|
+
find_manifest,
|
|
27
|
+
manifest_candidates,
|
|
28
|
+
SystemManifest,
|
|
29
|
+
SystemManifestError,
|
|
30
|
+
parse_system_manifest,
|
|
31
|
+
)
|
|
32
|
+
from tan.envelope import Project, SdkInfo
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def to_posix(path: str) -> str:
|
|
36
|
+
"""Forward slashes always. Mirrors `tan_core::project::to_posix`: every field
|
|
37
|
+
in the extension/CLI handshake must be platform-identical."""
|
|
38
|
+
return path.replace("\\", "/")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def normalise(path: str) -> str:
|
|
42
|
+
"""Rust's `normalize_path(cwd.join(p))`: cwd-anchored and lexically
|
|
43
|
+
normalised, in the platform's own separators.
|
|
44
|
+
|
|
45
|
+
`os.path.abspath`, not `Path.resolve()`: abspath is purely lexical, so a
|
|
46
|
+
project reached through a symlink keeps the name the user typed and a path
|
|
47
|
+
that does not exist yet still resolves.
|
|
48
|
+
"""
|
|
49
|
+
return os.path.abspath(path)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _has_loader(root: str) -> bool:
|
|
53
|
+
"""`scripts/alp_project.py` is THE marker for an alp-sdk checkout -- the same
|
|
54
|
+
literal `tan_core::project` hardcodes (I-31). Spelled once, in
|
|
55
|
+
`build_cmd.SDK_MARKER`."""
|
|
56
|
+
return Path(root).joinpath(*SDK_MARKER).exists()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class ProjectContext:
|
|
61
|
+
"""What both commands report and build their paths from."""
|
|
62
|
+
|
|
63
|
+
#: `project.root` -- posix, absolute.
|
|
64
|
+
workspace_root: str
|
|
65
|
+
#: The RESOLVER's own answer -- posix, absolute, joined onto `workspace_root`
|
|
66
|
+
#: unconditionally, matching `project.rs::resolve_board_yaml_path`: the
|
|
67
|
+
#: field names where one WOULD be. Existence is NOT checked here; `project()`
|
|
68
|
+
#: below is the seam that checks it (tan-cli#236).
|
|
69
|
+
board_yaml: str
|
|
70
|
+
#: The envelope's `sdk` block, or `None` when nothing resolved (absent, never
|
|
71
|
+
#: `null`).
|
|
72
|
+
sdk: SdkInfo | None
|
|
73
|
+
#: `ActiveSdk.broken_project_pin` carried through (tan-cli#263 review) --
|
|
74
|
+
#: `size`/`image`'s own `_run` turns this into the shared
|
|
75
|
+
#: `sdk.project-pin-unresolved` warning via `sdk_discovery.project_pin_issue`.
|
|
76
|
+
broken_project_pin: str | None = None
|
|
77
|
+
#: `ActiveSdk.tier`, unconditionally -- unlike `sdk` above, set even when
|
|
78
|
+
#: nothing resolved to a usable checkout (`sdk is None`), which is exactly
|
|
79
|
+
#: the shape `project_pin_issue` needs: a broken pin with NO working
|
|
80
|
+
#: fallback still has a real tier (`"none"`) to name in its message.
|
|
81
|
+
sdk_source_tier: str = "none"
|
|
82
|
+
#: `ActiveSdk.foreign_global_default_for` carried through (tan-cli#464) --
|
|
83
|
+
#: `size`/`image`'s own `_run` turns this into
|
|
84
|
+
#: `sdk_discovery.global_default_foreign_project_issue`, the sibling warning to
|
|
85
|
+
#: `broken_project_pin` above.
|
|
86
|
+
foreign_global_default_for: str | None = None
|
|
87
|
+
|
|
88
|
+
def project(self) -> Project:
|
|
89
|
+
return Project.resolved(self.workspace_root, self.board_yaml)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def resolve_project_context(
|
|
93
|
+
project_arg: str | None, board_yaml_arg: str | None, sdk_root_arg: str | None
|
|
94
|
+
) -> ProjectContext:
|
|
95
|
+
"""Port of `util::resolve_cli_project_context` for these two commands.
|
|
96
|
+
|
|
97
|
+
The `sdk` block is populated from the SAME resolution that produced
|
|
98
|
+
`workspace_root`, never a second lookup -- that is what `crate::sdk_report`
|
|
99
|
+
exists to guarantee. A `--sdk-root` that is not a checkout resolves to
|
|
100
|
+
NOTHING (core re-validates the loader marker), so the key is then absent
|
|
101
|
+
rather than advertising a path no command could use.
|
|
102
|
+
"""
|
|
103
|
+
workspace_root = normalise(project_arg or ".")
|
|
104
|
+
configured = board_yaml_arg or "board.yaml"
|
|
105
|
+
board_yaml = (
|
|
106
|
+
configured
|
|
107
|
+
if os.path.isabs(configured)
|
|
108
|
+
else os.path.join(workspace_root, configured)
|
|
109
|
+
)
|
|
110
|
+
active = resolve_sdk_tiered(sdk_root_arg, Path(workspace_root))
|
|
111
|
+
# `resolve_sdk_tiered` returns `--sdk-root` as-is EVEN WHEN INVALID (I-31,
|
|
112
|
+
# deliberately, so `tan sdk` can report the path the user typed). The
|
|
113
|
+
# envelope's `sdk` must not: `resolve_cli_project_context` only records what
|
|
114
|
+
# core's own loader-marker check accepted.
|
|
115
|
+
sdk = (
|
|
116
|
+
SdkInfo.from_resolution(to_posix(active.path), active)
|
|
117
|
+
if active.path is not None and _has_loader(active.path)
|
|
118
|
+
else None
|
|
119
|
+
)
|
|
120
|
+
return ProjectContext(
|
|
121
|
+
workspace_root=to_posix(workspace_root),
|
|
122
|
+
board_yaml=to_posix(board_yaml),
|
|
123
|
+
sdk=sdk,
|
|
124
|
+
broken_project_pin=active.broken_project_pin,
|
|
125
|
+
sdk_source_tier=active.tier,
|
|
126
|
+
foreign_global_default_for=active.foreign_global_default_for,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def resolve_metadata_sdk_root(
|
|
131
|
+
sdk_root_arg: str | None, workspace_root: str
|
|
132
|
+
) -> Path | None:
|
|
133
|
+
"""The alp-sdk checkout `tan size` reads `metadata/**` out of -- port of
|
|
134
|
+
`util::resolve_sdk_root`: `--sdk-root` (terminal) > the project's own
|
|
135
|
+
`.alp/sdk-path` pin > the machine-global default (`~/.alp/sdk-default`) >
|
|
136
|
+
the positional walk (`resolve_sdk_root_ladder`, the NARROW ladder shared
|
|
137
|
+
with `build`/`doctor`/the ten other narrowly-resolving commands -- not the
|
|
138
|
+
wide one `init`/`generate`/`examples` take). No `ALP_SDK_ROOT` tier
|
|
139
|
+
(tried and reverted -- see `resolve_sdk_root_ladder`'s own docstring).
|
|
140
|
+
|
|
141
|
+
Kept separate from [`resolve_project_context`] because the oracle keeps them
|
|
142
|
+
separate: `size.rs` calls BOTH, and they can legitimately disagree -- a
|
|
143
|
+
child checkout supplies the memory budget while the envelope's `sdk` stays
|
|
144
|
+
absent. Collapsing them would change which budget resolves.
|
|
145
|
+
|
|
146
|
+
An ABSENT `--sdk-root` with no checkout found is NOT fatal (the retired
|
|
147
|
+
Python's `find_sdk_root` die is deliberately dropped): the budget resolves
|
|
148
|
+
`unknown` and measurement still runs. A non-empty `--sdk-root` that fails
|
|
149
|
+
the loader-marker check returns `None` here too, but `size` treats THAT as
|
|
150
|
+
fatal (`size.sdk-root-unresolved`, tan-cli#1463): a typo'd flag silently
|
|
151
|
+
ignored is the bug.
|
|
152
|
+
"""
|
|
153
|
+
flag = (sdk_root_arg or "").strip()
|
|
154
|
+
if flag:
|
|
155
|
+
# Terminal: a bad `--sdk-root` must fail loudly as "no budget resolved",
|
|
156
|
+
# not silently fall through to some other checkout.
|
|
157
|
+
return Path(flag) if _has_loader(flag) else None
|
|
158
|
+
# `_broken_pin` unused here: `resolve_project_context` above already
|
|
159
|
+
# resolved (and each caller already reports) the SAME `.alp/sdk-path`
|
|
160
|
+
# pin's own status via `ProjectContext.broken_project_pin`; this walk is
|
|
161
|
+
# the deliberately SEPARATE metadata-budget resolution the module
|
|
162
|
+
# docstring describes, not a second envelope-facing resolution.
|
|
163
|
+
return resolve_sdk_root_ladder(None, Path(workspace_root)).path
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def read_sdk_som_and_soc(
|
|
167
|
+
metadata_root: str, sku: str, *, warnings: list[str] | None = None,
|
|
168
|
+
skipped: list[str] | None = None, explain_unsupported: bool = False,
|
|
169
|
+
) -> tuple[str, str | None, list[dict], float | None, list[tuple[str, float | None]]] | None:
|
|
170
|
+
"""`(silicon, silicon_variant, variants, soc_flash_mb, soc_cores)` for
|
|
171
|
+
`sku`'s SoM preset + SoC JSON under `<sdk>/metadata` -- port of the ONE
|
|
172
|
+
metadata-layout walk `util::read_sdk_som_and_soc` performs on the Rust
|
|
173
|
+
side: `metadata/e1m_modules/<sku>.yaml` -> `silicon.split(':')` ->
|
|
174
|
+
`metadata/socs/<vendor>/<family>/<part>.json`. `None` when the SoM preset
|
|
175
|
+
itself cannot be read (missing, unreadable, wrong `schema_version`).
|
|
176
|
+
|
|
177
|
+
`tan size` and `tan debug-config` both resolve a SoC variant off this same
|
|
178
|
+
walk and must call ONE reader, not two that could disagree -- a schema
|
|
179
|
+
with no reader, then two readers that could quietly diverge, is the exact
|
|
180
|
+
drift alp-sdk#1026 itself is about. Leaf parsing stays
|
|
181
|
+
`size_cmd._read_som_preset`/`_read_soc`; this only sequences them. A
|
|
182
|
+
caller wanting a FINER "file missing" vs "file unreadable" split (`tan
|
|
183
|
+
size`'s two different budget notes) still does its own existence check on
|
|
184
|
+
`<metadata_root>/e1m_modules/<sku>.yaml` before calling this.
|
|
185
|
+
|
|
186
|
+
Imported locally, not at module level: `size_cmd` already imports this
|
|
187
|
+
module for `resolve_project_context`/`resolve_metadata_sdk_root`, so a
|
|
188
|
+
top-level import the other way would cycle.
|
|
189
|
+
|
|
190
|
+
*warnings* (tan-cli#964), when given, is threaded to BOTH leaf readers --
|
|
191
|
+
a caller that does not pass it is entirely unaffected: `_read_som_preset`/
|
|
192
|
+
`_read_soc` only validate when the caller supplies a collector, so this
|
|
193
|
+
parameter defaults to a no-op. `tan debug-config` now passes one too
|
|
194
|
+
(tan-cli#964 review, major 5) -- this docstring used to name it as the
|
|
195
|
+
one caller that did not; it was.
|
|
196
|
+
|
|
197
|
+
*skipped* (tan-cli#964 review, major 6): same threading, same default,
|
|
198
|
+
for the "skip-but-disclose" half -- `missing_schema_note`'s notes rather
|
|
199
|
+
than `validate_document`'s violations.
|
|
200
|
+
"""
|
|
201
|
+
from tan.commands.size_cmd import _read_soc, _read_som_preset # noqa: PLC0415
|
|
202
|
+
|
|
203
|
+
preset_path = os.path.join(metadata_root, "e1m_modules", f"{sku}.yaml")
|
|
204
|
+
preset = _read_som_preset(
|
|
205
|
+
preset_path, metadata_root=metadata_root, warnings=warnings, skipped=skipped
|
|
206
|
+
)
|
|
207
|
+
if preset is None:
|
|
208
|
+
# Say WHY (tan-cli#1354 bench round 7: a stale alp-sdk checkout whose presets are
|
|
209
|
+
# schema_version 1 made every caller report a bare "unreadable"): a caller that
|
|
210
|
+
# passed a `skipped` collector AND `explain_unsupported` gets the real cause as a note
|
|
211
|
+
# (`tan size` keeps its own, richer `size.som-schema-version-skipped` instead).
|
|
212
|
+
if skipped is not None and explain_unsupported:
|
|
213
|
+
note = _unsupported_preset_note(preset_path)
|
|
214
|
+
if note is not None:
|
|
215
|
+
skipped.append(note)
|
|
216
|
+
return None
|
|
217
|
+
silicon, silicon_variant = preset
|
|
218
|
+
if not silicon:
|
|
219
|
+
return silicon, silicon_variant, [], None, []
|
|
220
|
+
parts = silicon.split(":")
|
|
221
|
+
if len(parts) != 3:
|
|
222
|
+
return silicon, silicon_variant, [], None, []
|
|
223
|
+
soc_path = os.path.join(metadata_root, "socs", parts[0], parts[1], f"{parts[2]}.json")
|
|
224
|
+
variants, soc_flash_mb, soc_cores = _read_soc(
|
|
225
|
+
soc_path, metadata_root=metadata_root, warnings=warnings, skipped=skipped
|
|
226
|
+
)
|
|
227
|
+
return silicon, silicon_variant, variants, soc_flash_mb, soc_cores
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _unsupported_preset_note(path: str) -> str | None:
|
|
231
|
+
"""`<path>: not read -- unsupported SoM preset schema_version 1 (tan needs 2) --
|
|
232
|
+
update alp-sdk` when the preset parses but declares a version tan does not read;
|
|
233
|
+
`None` for any other reason it could not be used (missing, unparseable)."""
|
|
234
|
+
from tan.commands.size_cmd import _read_text # noqa: PLC0415
|
|
235
|
+
from tan.core.som_schema_version import SOM_SCHEMA_VERSION, is_supported_som_schema_version
|
|
236
|
+
from tan.core.system_manifest import load_yaml_document # noqa: PLC0415
|
|
237
|
+
|
|
238
|
+
text = _read_text(path)
|
|
239
|
+
if text is None:
|
|
240
|
+
return None
|
|
241
|
+
try:
|
|
242
|
+
root = load_yaml_document(text)
|
|
243
|
+
except Exception: # noqa: BLE001 -- unparseable is `unreadable`, not this
|
|
244
|
+
return None
|
|
245
|
+
if not isinstance(root, dict):
|
|
246
|
+
return None
|
|
247
|
+
version = root.get("schema_version")
|
|
248
|
+
if is_supported_som_schema_version(version):
|
|
249
|
+
return None
|
|
250
|
+
return (
|
|
251
|
+
f"{path.replace(chr(92), '/')}: not read -- unsupported SoM preset schema_version "
|
|
252
|
+
f"{version} (tan needs {SOM_SCHEMA_VERSION}) -- update alp-sdk"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def resolve_app_base(app_path: str | None, workspace_root: str) -> str:
|
|
257
|
+
"""The directory whose `build/` is the default build root.
|
|
258
|
+
|
|
259
|
+
An explicit positional wins and is anchored on the CURRENT DIRECTORY, not on
|
|
260
|
+
`--project` -- it is typed at a shell prompt, so a relative value means what
|
|
261
|
+
the shell means by it (and `tan size app` therefore reports `project.root` as
|
|
262
|
+
the cwd while reading `app/build`, which is what the oracle does). `size`
|
|
263
|
+
spells "no positional" as the default `.`; `image` spells it as an absent
|
|
264
|
+
argument; both then fall back to the resolved workspace.
|
|
265
|
+
|
|
266
|
+
A STRING, joined with `os.path.join` -- see the note in
|
|
267
|
+
`tan.core.system_manifest`: the workspace root is posix and `PathBuf::join`
|
|
268
|
+
does not re-render it, so `pathlib` here would change every path this command
|
|
269
|
+
reports.
|
|
270
|
+
"""
|
|
271
|
+
if app_path is not None and app_path != ".":
|
|
272
|
+
return os.path.join(os.getcwd(), app_path)
|
|
273
|
+
return workspace_root
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def resolve_build_root(build_root_arg: str | None, app_base: str) -> str:
|
|
277
|
+
"""`--build-root` absolute as-is, relative against the CURRENT DIRECTORY;
|
|
278
|
+
default `<app_base>/build`."""
|
|
279
|
+
if build_root_arg is None:
|
|
280
|
+
return os.path.join(app_base, "build")
|
|
281
|
+
if os.path.isabs(build_root_arg):
|
|
282
|
+
return build_root_arg
|
|
283
|
+
return os.path.join(os.getcwd(), build_root_arg)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class ManifestUnavailable(Exception):
|
|
287
|
+
"""`build/system-manifest.yaml` could not be READ -- absent, unreadable, a
|
|
288
|
+
directory, or not UTF-8. All four are `*.manifest-unavailable` in the oracle,
|
|
289
|
+
including the decode failure (`read_to_string` returns an io error for
|
|
290
|
+
invalid UTF-8, so it never reaches the parser)."""
|
|
291
|
+
|
|
292
|
+
def __init__(self, path: str, detail: str) -> None:
|
|
293
|
+
super().__init__(detail)
|
|
294
|
+
self.path = path
|
|
295
|
+
self.detail = detail
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class ManifestInvalid(Exception):
|
|
299
|
+
"""It was read but is not a v1 system-manifest."""
|
|
300
|
+
|
|
301
|
+
def __init__(self, path: str, detail: str) -> None:
|
|
302
|
+
super().__init__(detail)
|
|
303
|
+
self.path = path
|
|
304
|
+
self.detail = detail
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def load_manifest(build_root: str) -> tuple[str, SystemManifest]:
|
|
308
|
+
"""Read + parse + version-guard the manifest, returning its raw text too --
|
|
309
|
+
`tan image` needs the bytes for the additive-field passthrough that a typed
|
|
310
|
+
projection would discard.
|
|
311
|
+
|
|
312
|
+
Every failure is one of the two exceptions above, so neither command can
|
|
313
|
+
ever let an OSError, a decode error or a YAML error escape as a traceback.
|
|
314
|
+
"""
|
|
315
|
+
path = find_manifest(build_root)
|
|
316
|
+
try:
|
|
317
|
+
# `newline=""`: no universal-newline translation, matching Rust's
|
|
318
|
+
# `read_to_string`. Explicit encoding, never the locale default -- a
|
|
319
|
+
# cp1252 host would raise UnicodeDecodeError on a manifest with any
|
|
320
|
+
# non-ASCII byte (I-27's read-side rule).
|
|
321
|
+
with open(path, encoding="utf-8", newline="") as handle:
|
|
322
|
+
text = handle.read()
|
|
323
|
+
except (OSError, UnicodeDecodeError, ValueError) as err:
|
|
324
|
+
if isinstance(err, FileNotFoundError):
|
|
325
|
+
# Neither spelling exists: name both paths tried (tan-cli#1405).
|
|
326
|
+
path = " or ".join(manifest_candidates(build_root))
|
|
327
|
+
raise ManifestUnavailable(path, str(err)) from err
|
|
328
|
+
try:
|
|
329
|
+
return text, parse_system_manifest(text)
|
|
330
|
+
except SystemManifestError as err:
|
|
331
|
+
raise ManifestInvalid(path, err.message) from err
|