Skip to main content

horto_os_ui_shared/
pipeline.rs

1//! Ordered Full / Minimal step registries and id lookup.
2
3use crate::step::Step;
4use crate::steps::{
5    d0_docker_engine::D0DockerEngine, d1_docker::D1Docker, d2_start_stacks::D2StartStacks,
6    m1_minimal::M1Minimal, s1_packages::S1Packages, s2_env::S2Env, s3_backup::S3Backup,
7    s4_stage::S4Stage, s5_apply::S5Apply, s6_validate::S6Validate, s7_activate::S7Activate,
8};
9use std::sync::OnceLock;
10
11/// Which ordered pipeline to run or report status for.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum SetupKind {
14    /// Full IoT-LAN pipeline (`s1`…`s7` + `d0`…`d2`).
15    Full,
16    /// Minimal pipeline (`m1`, `s3`, `s4`).
17    Minimal,
18}
19
20impl SetupKind {
21    /// Stable string used in status JSON and CLI output.
22    #[must_use]
23    pub const fn as_str(self) -> &'static str {
24        match self {
25            Self::Full => "full",
26            Self::Minimal => "minimal",
27        }
28    }
29}
30
31static FULL: OnceLock<Vec<&'static dyn Step>> = OnceLock::new();
32static MINIMAL: OnceLock<Vec<&'static dyn Step>> = OnceLock::new();
33static ALL: OnceLock<Vec<&'static dyn Step>> = OnceLock::new();
34
35fn full_steps() -> &'static [&'static dyn Step] {
36    FULL.get_or_init(|| {
37        vec![
38            &S1Packages,
39            &S2Env,
40            &S3Backup,
41            &S4Stage,
42            &S5Apply,
43            &S6Validate,
44            &S7Activate,
45            &D0DockerEngine,
46            &D1Docker,
47            &D2StartStacks,
48        ]
49    })
50}
51
52fn minimal_steps() -> &'static [&'static dyn Step] {
53    MINIMAL.get_or_init(|| vec![&M1Minimal, &S3Backup, &S4Stage])
54}
55
56fn all_registered() -> &'static [&'static dyn Step] {
57    ALL.get_or_init(|| {
58        vec![
59            &S1Packages,
60            &S2Env,
61            &S3Backup,
62            &S4Stage,
63            &S5Apply,
64            &S6Validate,
65            &S7Activate,
66            &M1Minimal,
67            &D0DockerEngine,
68            &D1Docker,
69            &D2StartStacks,
70        ]
71    })
72}
73
74/// Ordered steps for `kind` (Full or Minimal).
75#[must_use]
76pub fn pipeline(kind: SetupKind) -> &'static [&'static dyn Step] {
77    match kind {
78        SetupKind::Full => full_steps(),
79        SetupKind::Minimal => minimal_steps(),
80    }
81}
82
83/// Look up a registered step by id (`s1`, `d1`, …).
84///
85/// Searches the union of Full and Minimal registries (including steps only on Full).
86///
87/// # Examples
88///
89/// ```
90/// use horto_os_ui_shared::lookup;
91///
92/// let s1 = lookup("s1").expect("s1 registered");
93/// assert_eq!(s1.id(), "s1");
94/// assert!(lookup("nope").is_none());
95/// ```
96#[must_use]
97pub fn lookup(id: &str) -> Option<&'static dyn Step> {
98    all_registered().iter().copied().find(|s| s.id() == id)
99}
100
101/// Step ids in Full pipeline order.
102#[must_use]
103pub fn full_ids() -> Vec<&'static str> {
104    full_steps().iter().map(|s| s.id()).collect()
105}
106
107/// Step ids in Minimal pipeline order.
108#[must_use]
109pub fn minimal_ids() -> Vec<&'static str> {
110    minimal_steps().iter().map(|s| s.id()).collect()
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn full_registry_ids() {
119        assert_eq!(
120            full_ids(),
121            vec!["s1", "s2", "s3", "s4", "s5", "s6", "s7", "d0", "d1", "d2"]
122        );
123    }
124
125    #[test]
126    fn minimal_registry_ids() {
127        assert_eq!(minimal_ids(), vec!["m1", "s3", "s4"]);
128    }
129
130    #[test]
131    fn docker_steps_only_on_full() {
132        assert!(full_ids().contains(&"d0"));
133        assert!(full_ids().contains(&"d1"));
134        assert!(full_ids().contains(&"d2"));
135        assert!(!minimal_ids().contains(&"d0"));
136        assert!(!minimal_ids().contains(&"d1"));
137        assert!(!minimal_ids().contains(&"d2"));
138    }
139}