horto_os_ui_shared/steps/
m1_minimal.rs1use crate::context::{HostContext, PlannedAction};
5use crate::embed;
6use crate::error::{HortoError, Result};
7use crate::kits::{apt, envfile, fs};
8use crate::step::Step;
9use std::collections::BTreeMap;
10
11pub struct M1Minimal;
13
14impl Step for M1Minimal {
15 fn id(&self) -> &'static str {
16 "m1"
17 }
18 fn title(&self) -> &'static str {
19 "Minimal: cockpit + hostname env"
20 }
21 fn reference_script(&self) -> &'static str {
22 "m1_minimal_setup_run.sh"
23 }
24 fn step_version(&self) -> u32 {
25 1
26 }
27 fn is_done(&self, ctx: &HostContext) -> bool {
28 let path = ctx.paths.minimal_env_file();
29 path.exists()
30 && envfile::load(&path)
31 .ok()
32 .and_then(|m| envfile::require_keys(&m, &["MY_HOSTNAME"]).ok())
33 .is_some()
34 }
35 fn plan(&self, ctx: &mut HostContext) -> Result<Vec<PlannedAction>> {
36 ctx.plan_action("apt update");
37 ctx.plan_action("apt install -y cockpit cockpit-networkmanager");
38 ctx.plan_action(format!(
39 "write {} with MY_HOSTNAME",
40 ctx.paths.minimal_env_file().display()
41 ));
42 Ok(ctx.planned.clone())
43 }
44 fn apply(&self, ctx: &mut HostContext) -> Result<()> {
45 fs::ensure_dir(ctx, &ctx.paths.active_setup.clone())?;
46 if ctx.is_dry_run() || crate::context::is_root() {
47 apt::apt_update(ctx)?;
48 apt::apt_install(ctx, &["cockpit", "cockpit-networkmanager"])?;
49 } else {
50 ctx.log("Not root; skipping cockpit apt install");
51 }
52
53 let active = ctx.paths.minimal_env_file();
54 if ctx.is_dry_run() {
55 ctx.plan_action(format!("write {}", active.display()));
56 return Ok(());
57 }
58
59 let map = if active.exists() {
60 envfile::load(&active)?
61 } else {
62 let template = embed::get_str("config/minimal_setup_vars.env")
63 .ok_or_else(|| HortoError::EmbedMissing("config/minimal_setup_vars.env".into()))?;
64 envfile::parse(&template)
65 };
66
67 let hostname = ctx.prompt(
68 "Device hostname",
69 map.get("MY_HOSTNAME")
70 .map_or("Horto-OS_xxx", String::as_str),
71 );
72 if hostname.is_empty() {
73 return Err(HortoError::msg("MY_HOSTNAME is empty"));
74 }
75 let mut out = BTreeMap::new();
76 envfile::set_key(&mut out, "MY_HOSTNAME", hostname);
77 envfile::write(&active, &out)?;
78 ctx.log(format!(
79 "Loaded minimal deployment variables from {}",
80 active.display()
81 ));
82 ctx.log("Manual network configuration remains your responsibility in minimal mode.");
83 Ok(())
84 }
85}