horto_os_ui_shared/
step.rs1use crate::context::HostContext;
4use crate::error::Result;
5
6pub trait Step: Send + Sync {
11 fn id(&self) -> &'static str;
13 fn title(&self) -> &'static str;
15 fn reference_script(&self) -> &'static str;
17 fn schema_version(&self) -> u32 {
19 1
20 }
21 fn step_version(&self) -> u32;
23 fn depends_on(&self) -> &'static [&'static str] {
25 &[]
26 }
27 fn is_done(&self, ctx: &HostContext) -> bool;
29 fn plan(&self, ctx: &mut HostContext) -> Result<Vec<crate::context::PlannedAction>>;
35 fn apply(&self, ctx: &mut HostContext) -> Result<()>;
41 fn needs_reboot_after(&self) -> bool {
43 false
44 }
45 fn destructive(&self) -> bool {
47 false
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::context::{ApplyMode, HostContext};
55 use crate::pipeline::SetupKind;
56
57 struct DefaultsOnly;
59
60 impl Step for DefaultsOnly {
61 fn id(&self) -> &'static str {
62 "t0"
63 }
64 fn title(&self) -> &'static str {
65 "defaults-only"
66 }
67 fn reference_script(&self) -> &'static str {
68 "none"
69 }
70 fn step_version(&self) -> u32 {
71 1
72 }
73 fn is_done(&self, _ctx: &HostContext) -> bool {
74 false
75 }
76 fn plan(&self, _ctx: &mut HostContext) -> Result<Vec<crate::context::PlannedAction>> {
77 Ok(Vec::new())
78 }
79 fn apply(&self, _ctx: &mut HostContext) -> Result<()> {
80 Ok(())
81 }
82 }
83
84 #[test]
85 fn trait_defaults_are_stable() {
86 let concrete = DefaultsOnly;
87 let step: &dyn Step = &concrete;
88 assert_eq!(step.schema_version(), 1);
89 assert_eq!(step.depends_on(), &[] as &[&str]);
90 assert!(!step.needs_reboot_after());
91 assert!(!step.destructive());
92 let mut ctx = HostContext::new(ApplyMode::DryRun, SetupKind::Minimal);
93 assert!(!step.is_done(&ctx));
94 assert_eq!(step.plan(&mut ctx).unwrap(), Vec::new());
95 step.apply(&mut ctx).unwrap();
96 assert_eq!(step.id(), "t0");
97 assert_eq!(step.title(), "defaults-only");
98 assert_eq!(step.reference_script(), "none");
99 assert_eq!(step.step_version(), 1);
100 }
101}