Skip to content

Add --target-board flag for board interpolation#179

Merged
jetm merged 13 commits into
mainfrom
target-board-flag
Jul 17, 2026
Merged

Add --target-board flag for board interpolation#179
jetm merged 13 commits into
mainfrom
target-board-flag

Conversation

@jetm

@jetm jetm commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Problem

{{ avocado.target.board }} could only be set through the
AVOCADO_TARGET_BOARD env var or avocado.yaml. There was no CLI flag for
it, unlike --target.

Solution

Add a per-subcommand --target-board flag that overrides the board when
resolving {{ avocado.target.board }}, giving it parity with --target. The
resolved value is parked once at the CLI boundary in a process-scoped override
that the interpolation resolver reads as its top tier, so every
config-composition path honors the flag without threading a parameter through
each site.

Key changes

  • --target-board on build, provision, runtime provision, ext build, rootfs
    install, initramfs install, sdk install, and install (per-subcommand, not a
    root global).
  • Override read as the top tier of resolve_target_board_value, the single
    point all AvocadoContext construction funnels through, so the flag reaches
    extension discovery and the composed-config first pass, not just the
    directly-threaded callers.
  • Precedence: --target-board > AVOCADO_TARGET_BOARD > runtime
    target_board > default_target_board > fallback to the resolved target.
  • Unit tests for the precedence chain plus an end-to-end interpolation test.

Scope

The flag is intentionally on the 8 user-facing build/install entry points
listed above. Sub-steps that avocado build orchestrates (ext image,
runtime build, sdk run/compile/dnf) inherit the board through the
process-scoped override, so their stamp hashes stay consistent in the
orchestrated flow; run standalone they resolve the board from env/config as
before. Extending the flag to those sub-commands for standalone parity is a
possible follow-up.

Reviewer notes

Verified end to end on a real target:
avocado sdk install --target imx8mp-var-dart --target-board variscite-sonata
installs avocado-bsp-variscite-sonata from the 2024/next feed (exit 0),
matching what default_target_board: variscite-sonata in avocado.yaml
produces. cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, and the full cargo test suite are green.

jetm added 11 commits July 16, 2026 15:24
The `{{ avocado.target_board }}` value was resolvable only from the
AVOCADO_TARGET_BOARD env var, a runtime's target_board field, or
default_target_board. Its sibling target has a CLI override that sits
above the env var, but target_board had no equivalent entry point for a
caller to pass a per-invocation value.

Add a cli_target_board parameter to resolve_target_board_value and
from_main_config, checked at the top of the precedence chain so a Some
value wins over env and config. When None, the chain is unchanged, so
every existing caller (all threaded None here) keeps today's behavior.
The remaining callers and the CLI surface are wired in later commits.

Signed-off-by: Javier Tia <javier@peridio.com>
Group 1 added the cli_target_board parameter to from_main_config, but
the build path reaches interpolation through interpolate_config in
config.rs, which had no way to pass an override down.

Add cli_target_board to interpolate_config and forward it to
from_main_config. Every current caller passes None, so resolution is
unchanged; the seven config.rs composition sites and the test callers
are updated to the new arity. The real per-command value is wired into
the composition calls in the following commits.

Signed-off-by: Javier Tia <javier@peridio.com>
avocado build could set the target architecture per invocation with
--target, but the target board it interpolates into
`{{ avocado.target.board }}` was reachable only through the environment
or avocado.yaml, forcing a config edit or an exported var to override it.

Add a --target-board flag on the root Cli and the build subcommand,
merged the same way --target is, and carry it into BuildCommand. The
build path composes config through load_composed, so add a
load_composed_with_board variant that forwards the override into
interpolate_config; the existing load_composed delegates with None so
its other callers are untouched.

Signed-off-by: Javier Tia <javier@peridio.com>
The unit test for resolve_target_board_value proves the precedence
branch in isolation, but nothing covered the value actually reaching
`{{ avocado.target.board }}` through the interpolate_config seam the
build path uses.

Add a serial test that interpolates a config referencing the board
variable: with the override set it resolves to the flag value over a
competing AVOCADO_TARGET_BOARD, and with no override the env var still
wins, guarding the no-flag path.

Signed-off-by: Javier Tia <javier@peridio.com>
The build command honored --target-board, but the other commands that
interpolate `{{ avocado.target.board }}` still had no way to override the
board per invocation, leaving the flag surface inconsistent across the
CLI.

Add the flag to runtime provision, the top-level provision shortcut,
ext build, and rootfs install, merged the same way each command already
merges --target, and carry it into their config-composition calls via
load_composed_with_board. The two overlay-preprocess passes (ext build
and rootfs sysroot install) build a fresh interpolation context, so the
override is threaded there too, including through SysrootInstallParams.
The unrelated initramfs and sdk install callers of that params struct
pass None, preserving their behavior.

Signed-off-by: Javier Tia <javier@peridio.com>
The --target-board help and doc comments on the root Cli, the build
subcommand, and load_composed_with_board wrote the interpolation
variable as `{{ avocado.target_board }}`, but the resolver keys it on
the dotted path `{{ avocado.target.board }}` (["target","board"]). The
parity commands added alongside already used the dotted form, so the
help text was both inconsistent across commands and wrong for the two
that used the underscore.

Normalize all four strings to the dotted form the interpolator actually
resolves.

Signed-off-by: Javier Tia <javier@peridio.com>
The flag was declared as a root Cli field mirroring --target, but only
the five commands that interpolate {{ avocado.target.board }} consume it.
--target is merged by ~30 subcommands so its root field is effectively
universal; --target-board at five commands left the root flag a silent
no-op on the rest (avocado --target-board X sdk install parsed the value
and dropped it with no error).

Remove the root Cli.target_board field and collapse each dispatch
merge from target_board.or(cli.target_board) to the subcommand value.
The flag now appears in --help and takes effect only on build, provision
(and the runtime provision alias), ext build, and rootfs install; the
global position avocado --target-board X build is no longer accepted.

Signed-off-by: Javier Tia <javier@peridio.com>
The flag reached the composed-config interpolation but not the seams
that re-derive an AvocadoContext from raw config. avocado build
orchestrates ExtBuildCommand/ExtImageCommand without forwarding the
board, so an overlay file containing {{ avocado.target.board }} rendered
with the env/config board instead of the flag; and the ext/rootfs/
initramfs stamp input hashes folded overlay content with the board
resolved to None, so switching --target-board between builds produced an
identical digest and skipped the rebuild the flag exists to force.

Forward the board into all three orchestrated ExtBuildCommand and both
ExtImageCommand construction sites, add a target_board field to
ExtImageCommand, and thread cli_target_board through
fold_overlay_content_hash and the compute_ext_build/ext_image/rootfs/
initramfs input-hash helpers so the digest reflects the rendered board.
A new stamps test proves a --target-board switch changes the ext build
hash.

Signed-off-by: Javier Tia <javier@peridio.com>
Two more seams re-derived the board from raw config and so ignored the
flag. The local-extension path read its ext section through
get_merged_ext_config, which re-interpolates the file with the board
resolved to None, so an `overlay: "overlays/{{ avocado.target.board }}"`
picked the env/config board's directory; and derive_ext_path_mounts
re-parsed avocado.yaml to resolve `type: path` extension sources with
the board as None, mounting a board-referencing source.path from the
wrong location.

Add board-aware get_merged_section_with_board / get_merged_ext_config_with_board
variants (the originals stay thin delegators passing None, so their many
other callers are untouched) and point ext build/image at them. Carry an
optional cli_target_board on SdkContainer, set it on the wired command
paths, and use it in derive_ext_path_mounts. Also correct the stale
AvocadoContext.target_board precedence doc to list the CLI tier.

Signed-off-by: Javier Tia <javier@peridio.com>
Spec requirement 3 says --target-board appears on every command that
takes --target and interpolates the board. initramfs install and
sdk install run the same install_sysroot overlay-materialize path that
justified wiring rootfs install, but constructed SysrootInstallParams
with target_board: None and rejected the flag; the top-level
avocado install a bring-up runs first accepted --target but not
--target-board, leaving the env var the only lever for the install
phase.

Wire the flag on all three: field, load_composed_with_board, and the
board threaded into each command's SysrootInstallParams. Top-level
install also forwards the board into the SDK-install sub-command it
orchestrates. The ext/runtime dnf-package installs it orchestrates are
left board-unaware; they materialize no board overlays, so only an
interpolated package spec would be affected.

Signed-off-by: Javier Tia <javier@peridio.com>
The --target-board flag reached {{ avocado.target.board }} only where a
board parameter was explicitly threaded. The config-loading pipeline
interpolates with a None board at several sites -
parse_config_value_with_interpolation, discover_remote_extensions, and
load_composed's first pass - so on sdk install and build the flag was
silently dropped and the board fell back to the target. A real
`avocado build --target imx8mp-var-dart --target-board variscite-sonata`
against a project referencing the avocado-bsp-{{ avocado.target.board }}
extension resolved it to avocado-bsp-imx8mp-var-dart instead of
avocado-bsp-variscite-sonata; AVOCADO_TARGET_BOARD worked only because
the resolver reads the env var internally regardless of the parameter.

Park the flag in a process-scoped override at the CLI boundary and read
it as the top tier of resolve_target_board_value, the single point every
production AvocadoContext is built through. This mirrors the env channel,
which already reaches every site, so one change covers build, ext build,
rootfs install, and sdk install rather than a parameter threaded through
each - the threading discipline that already missed these sites twice.

Signed-off-by: Javier Tia <javier@peridio.com>
@jetm
jetm requested a review from nicksinas July 17, 2026 20:16

@nicksinas nicksinas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review focused on DRY, maintainability/portability, correctness, and code smells. Overall the feature works and is well-tested; the notes below are a mix of one clean fix, one architectural question, and several smells worth a look.

Comment thread src/commands/sdk/install.rs
Comment thread src/utils/interpolation/avocado.rs
Comment thread src/commands/ext/image.rs
Comment thread src/utils/interpolation/avocado.rs
Comment thread src/utils/interpolation/avocado.rs
Comment thread src/main.rs
jetm added 2 commits July 17, 2026 14:42
Review of the --target-board flag caught two documentation errors. The
sdk-install `with_target_board` builder carried a stray "Set the no_stamps
flag" doc line copied from its sibling, so its generated rustdoc was
mislabeled and `with_no_stamps` was left undocumented. In the ext
overlay-preprocess path the comment claimed the selected runtime drives the
runtime-scoped target board, but the code only overrides the runtime name -
the board stays as from_main_config resolved it (CLI flag > env >
default_target_board).

Drop the stray doc line and reword the overlay comment to describe what the
code actually does, so neither doc overstates the behavior.

Signed-off-by: Javier Tia <javier@peridio.com>
The --target-board override reaches every interpolation site on its own,
so the explicit cli_target_board threading is redundant at runtime.
Review flagged the two channels as belt-and-suspenders with no stated
rule for which one to use.

Document the boundary on the override static (the global is the
production channel; the threaded params exist only for hermetic test
injection), the park-once invariant that makes the lock-guard swallow
safe rather than a silent-failure hole, and the #[serial] requirement
for tests that touch the shared static. State the routing invariant on
park_target_board so a future command arm cannot thread the value while
leaving the global unset and silently reintroduce the dropped-flag bug.
Also move a doc comment that had slipped off with_no_stamps back onto
its own setter.

Signed-off-by: Javier Tia <javier@peridio.com>
@jetm
jetm requested a review from nicksinas July 17, 2026 21:21
@jetm
jetm merged commit 889ecb4 into main Jul 17, 2026
8 checks passed
@jetm
jetm deleted the target-board-flag branch July 17, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants