Skip to main content

eval_containers/
bake.rs

1//! Bake artifact discovery — single source of truth for "which
2//! docker-bake.hcl files compose the fleet's build graph." Used by
3//! `src/build.rs` (the CLI), `tests/common/mod.rs` (test bootstraps),
4//! and `tests/build/test.rs` (the principle-15 lint). Per RULES.md
5//! principle 11 (Reuse over repetition): one home for the category
6//! list, the seed file, and the walker.
7
8use std::path::PathBuf;
9
10/// The five artifact categories whose subdirectories ship Dockerfiles
11/// and `docker-bake.hcl` files per RULES.md principle 15. Adding a
12/// sixth category is the only place this constant changes.
13pub const ARTIFACT_CATEGORIES: &[&str] = &["core", "agents", "benchmarks", "models", "gateways"];
14
15/// Path to the parameterized eval combination template.
16pub const COMBINATION_BAKE_FILE: &str = "core/combination.docker-bake.hcl";
17
18/// Path to the root bake file. Declares fleet-wide variables (`REGISTRY`)
19/// that per-artifact files reference via `${REGISTRY}/...` without
20/// redeclaring (principle 11 — reuse over repetition).
21pub const ROOT_BAKE_FILE: &str = "docker-bake.hcl";
22
23/// Every `docker-bake.hcl` in the fleet, plus the root and combination
24/// seeds. Order doesn't matter — bake merges by target name.
25pub fn artifact_bake_files() -> Vec<PathBuf> {
26    let mut files: Vec<PathBuf> = vec![ROOT_BAKE_FILE.into(), COMBINATION_BAKE_FILE.into()];
27    for category in ARTIFACT_CATEGORIES {
28        let Ok(entries) = std::fs::read_dir(category) else {
29            continue;
30        };
31        for entry in entries.flatten() {
32            let p = entry.path().join("docker-bake.hcl");
33            if p.exists() {
34                files.push(p);
35            }
36        }
37    }
38    files
39}
40
41/// Construct the `docker buildx bake` argument list for the given
42/// targets and `--set` overrides. Bake files come from
43/// [`artifact_bake_files`]. With no `builder`, `--load` is appended so
44/// the result lands in the local image store; with a named `builder`
45/// (a remote/in-cluster BuildKit), `--builder <name> --push` is appended
46/// instead, since a remote builder can't load into local Docker.
47///
48/// Both consumers (`src/build.rs` for the CLI, `tests/common/mod.rs`
49/// for test bootstraps) need this shape; sync vs. async `Command` and
50/// per-consumer env passthrough prevent a single Command-builder helper,
51/// but the arg list itself is identical.
52pub fn base_args(targets: &[&str], overrides: &[&str], builder: Option<&str>) -> Vec<String> {
53    let mut args: Vec<String> = vec!["buildx".into(), "bake".into()];
54    for f in artifact_bake_files() {
55        args.push("-f".into());
56        args.push(f.to_string_lossy().into_owned());
57    }
58    // A named builder is a remote/in-cluster BuildKit (e.g. the
59    // `--driver kubernetes` builder); it can't `--load` into the local
60    // Docker image store, so its output goes to the registry via `--push`.
61    // The default (local docker driver) loads into the local store.
62    match builder {
63        Some(name) => {
64            args.push("--builder".into());
65            args.push(name.to_string());
66            args.push("--push".into());
67        }
68        None => args.push("--load".into()),
69    }
70    for o in overrides {
71        args.push("--set".into());
72        args.push((*o).to_string());
73    }
74    for t in targets {
75        args.push((*t).to_string());
76    }
77    args
78}
79
80/// Every artifact directory (a subdirectory of one of the five
81/// categories) that contains a `Dockerfile`. Sorted for stable test
82/// failure output.
83pub fn artifact_dirs_with_dockerfile() -> Vec<PathBuf> {
84    let mut out = Vec::new();
85    for category in ARTIFACT_CATEGORIES {
86        let Ok(entries) = std::fs::read_dir(category) else {
87            continue;
88        };
89        for e in entries.flatten() {
90            let p = e.path();
91            if p.is_dir() && p.join("Dockerfile").exists() {
92                out.push(p);
93            }
94        }
95    }
96    out.sort();
97    out
98}