From c24c00c1d89990d44d796c4fd2b84e92162b044a Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 12 Aug 2026 00:04:41 +0000 Subject: Add validated image build stage graph --- src/cli.rs | 4 ++++ src/lib.rs | 2 ++ src/plan.rs | 10 +++++++++- src/stage.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ tests/stage_graph.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/stage.rs create mode 100644 tests/stage_graph.rs diff --git a/src/cli.rs b/src/cli.rs index de9404a..c91d4fd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -49,6 +49,10 @@ pub fn run(cli: Cli) -> Result<()> { println!("target: {}", plan.spec().target.name); println!("architecture: {}", plan.spec().target.architecture.as_str()); println!("format: tar"); + println!("stages:"); + for (index, stage) in plan.stages().iter().enumerate() { + println!(" {}. {stage}", index + 1); + } Ok(()) } Command::Build { .. } => bail!("build execution is not available yet"), diff --git a/src/lib.rs b/src/lib.rs index 52a875d..792e7a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ pub mod cli; pub mod model; pub mod plan; +pub mod stage; pub use model::{Architecture, BootSpec, ImageSpec, OutputFormat, PackageSelector, PackageSpec, Target}; pub use plan::BuildPlan; +pub use stage::Stage; diff --git a/src/plan.rs b/src/plan.rs index 16158e5..3d28d96 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -1,6 +1,6 @@ use anyhow::Result; -use crate::ImageSpec; +use crate::{ImageSpec, Stage}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct BuildPlan { @@ -16,4 +16,12 @@ impl BuildPlan { pub fn spec(&self) -> &ImageSpec { &self.spec } + + pub fn stages(&self) -> &'static [Stage] { + &Stage::ORDERED + } + + pub fn dependencies(&self, stage: Stage) -> &'static [Stage] { + stage.dependencies() + } } diff --git a/src/stage.rs b/src/stage.rs new file mode 100644 index 0000000..612b594 --- /dev/null +++ b/src/stage.rs @@ -0,0 +1,45 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Stage { + Resolve, + Install, + FinalizeRootfs, + BuildInitramfs, + Package, + Manifest, +} + +impl Stage { + pub const ORDERED: [Self; 6] = [ + Self::Resolve, + Self::Install, + Self::FinalizeRootfs, + Self::BuildInitramfs, + Self::Package, + Self::Manifest, + ]; + + pub fn dependencies(self) -> &'static [Self] { + match self { + Self::Resolve => &[], + Self::Install => &[Self::Resolve], + Self::FinalizeRootfs => &[Self::Install], + Self::BuildInitramfs => &[Self::Install], + Self::Package => &[Self::FinalizeRootfs, Self::BuildInitramfs], + Self::Manifest => &[Self::Package], + } + } +} + +impl std::fmt::Display for Stage { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = match self { + Self::Resolve => "resolve", + Self::Install => "install", + Self::FinalizeRootfs => "finalize-rootfs", + Self::BuildInitramfs => "initramfs", + Self::Package => "package", + Self::Manifest => "manifest", + }; + formatter.write_str(name) + } +} diff --git a/tests/stage_graph.rs b/tests/stage_graph.rs new file mode 100644 index 0000000..cd6fc93 --- /dev/null +++ b/tests/stage_graph.rs @@ -0,0 +1,40 @@ +use alt_controller_image::{BuildPlan, ImageSpec, Stage}; + +const SPEC: &str = r#" +[target] +name = "alt-controller" +architecture = "x86_64" +format = "tar" + +[kernel] +flavour = "rt" + +[boot] +initrd_features = ["rootfs"] +initrd_modules = ["ext4"] + +[packages] +base = ["basesystem"] +selectors = ["^kernel-image-rt$"] +"#; + +#[test] +fn stage_graph_orders_artifact_producers_before_consumers() { + let spec: ImageSpec = toml::from_str(SPEC).expect("spec parses"); + let plan = BuildPlan::compile(spec).expect("plan compiles"); + + assert_eq!( + plan.stages(), + [ + Stage::Resolve, + Stage::Install, + Stage::FinalizeRootfs, + Stage::BuildInitramfs, + Stage::Package, + Stage::Manifest, + ] + ); + assert_eq!(plan.dependencies(Stage::Package), &[Stage::FinalizeRootfs, Stage::BuildInitramfs]); + assert_eq!(plan.dependencies(Stage::BuildInitramfs), &[Stage::Install]); + assert_eq!(plan.dependencies(Stage::Manifest), &[Stage::Package]); +} -- cgit v1.2.3