Skip to content

audit: consolidate duplicated board / config resolution call sites across the workspace #519

@zackees

Description

@zackees

Background

While fixing #515 / #518 it became clear that fbuild has several near-duplicate code paths that all want to resolve a board id (and other config pieces) but each reach for the underlying primitive independently. Every time one of those primitives gains a new parameter — like the recently added project_dir for project-local boards/*.json — every call site has to be updated by hand, and missing one is silent (the build just behaves as if the new feature isn't there).

The proximate example: #516 added BoardConfig::from_board_id_in_project(..., project_dir) and updated compile_many::platform_for_board. But pipeline::BuildContext::new_with_perf (the daemon's actual fbuild build path) and script_runtime::build_script_runtime_board_config were both missed — they kept calling the legacy from_board_id and silently dropped the project_dir context. End users still saw unknown board 'X' (no built-in defaults) even though the underlying lookup primitive could find it. PR #518 catches them up, but the structural issue remains.

Ask

Audit the workspace for duplicated config-resolution logic and consolidate into a small set of shared entry points that take ALL needed context (project_dir, env_name, overrides, etc.) once. Concretely:

Board lookup (immediate)

  • crates/fbuild-build/src/compile_many.rs:platform_for_board
  • crates/fbuild-build/src/pipeline/context.rs:BuildContext::new_with_perf
  • crates/fbuild-build/src/script_runtime.rs:build_script_runtime_board_config
  • crates/fbuild-cli/src/cli/deploy.rs:run_deploy (two consecutive from_board_id calls with a fallback pattern repeated 3+ times in daemon/src/handlers/operations/deploy.rs)
  • crates/fbuild-daemon/src/handlers/operations/deploy.rs — there are ~5 instances of the same from_board_id(&board_id, &deploy_board_overrides).or_else(|_| from_board_id(&board_id, &HashMap::new())) pattern (lines ~154, ~427, ~667, ~699). That fallback strongly suggests a shared helper.

Other likely candidates worth checking

  • platformio.ini reading: are there multiple places that parse / hold a PlatformIOConfig per build? from_path + from_path_with_overrides + get_env_config are called from many sites.
  • project_dir handling: many places independently derive things like project_dir.join(\"platformio.ini\"), project_dir.join(\".fbuild\"), etc.
  • toolchain resolution + extra-script overlay setup — large per-orchestrator copies might share a common pre-build shim.

Proposed shape

A small fbuild_build::resolution (or similar) module with a couple of entry points:

pub struct ResolutionContext<'a> {
    pub project_dir: &'a Path,
    pub env_name:    &'a str,
    pub config:      &'a PlatformIOConfig,
    pub board_overrides: &'a HashMap<String, String>,
}

impl ResolutionContext<'_> {
    pub fn resolve_board(&self) -> Result<BoardConfig> { ... }
    pub fn resolve_platform(&self) -> Result<Platform> { ... }
    pub fn resolve_extra_script_overlay(&self) -> Result<BuildOverlay> { ... }
}

Then every existing site becomes one call instead of three. Adding the next parameter is then a one-line change to the context struct rather than a workspace-wide rename.

Acceptance

  • A single grep for BoardConfig::from_board_id (and variants) returns ≤2 call sites outside fbuild-config (the new entry points + one test helper), down from the ~12 production sites today.
  • Tests still green, no behavior change.
  • A short doc comment on the new module pointing future feature work at the right injection point.

Why now

Every feature that adds a knob (project_dir was just the most recent) gets paid for N times instead of once, and N-1 of those payments are silent regressions waiting for a CI run to surface them. This is cheap to consolidate while the call-site list is still small enough to enumerate.

Filed alongside #518 (which is the minimum fix to unblock the immediate user).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions