Add --target-board flag for board interpolation#179
Merged
Conversation
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>
nicksinas
reviewed
Jul 17, 2026
nicksinas
left a comment
Contributor
There was a problem hiding this comment.
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.
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>
nicksinas
approved these changes
Jul 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
{{ avocado.target.board }}could only be set through theAVOCADO_TARGET_BOARDenv var oravocado.yaml. There was no CLI flag forit, unlike
--target.Solution
Add a per-subcommand
--target-boardflag that overrides the board whenresolving
{{ avocado.target.board }}, giving it parity with--target. Theresolved 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-boardon build, provision, runtime provision, ext build, rootfsinstall, initramfs install, sdk install, and install (per-subcommand, not a
root global).
resolve_target_board_value, the singlepoint all
AvocadoContextconstruction funnels through, so the flag reachesextension discovery and the composed-config first pass, not just the
directly-threaded callers.
--target-board>AVOCADO_TARGET_BOARD> runtimetarget_board>default_target_board> fallback to the resolved target.Scope
The flag is intentionally on the 8 user-facing build/install entry points
listed above. Sub-steps that
avocado buildorchestrates (ext image,runtime build,sdk run/compile/dnf) inherit the board through theprocess-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-sonatainstalls
avocado-bsp-variscite-sonatafrom the2024/nextfeed (exit 0),matching what
default_target_board: variscite-sonatainavocado.yamlproduces.
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings, and the fullcargo testsuite are green.