From e725d5e4f2784d5322353d63911c95d6ffa3dbab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20K=C3=B6hl?= Date: Fri, 29 Nov 2024 12:53:16 +0100 Subject: [PATCH] add `--json` command line option --- Cargo.lock | 5 ++- crates/rugpi-common/src/system/info.rs | 60 ++++++++++++++++++++++++++ crates/rugpi-common/src/system/mod.rs | 1 + crates/rugpi-ctrl/Cargo.toml | 1 + crates/rugpi-ctrl/src/cli.rs | 34 +++++++++------ 5 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 crates/rugpi-common/src/system/info.rs diff --git a/Cargo.lock b/Cargo.lock index c7f8912..f96aece 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1109,6 +1109,7 @@ dependencies = [ "nix", "rugpi-common", "serde", + "serde_json", "sha2", "tempfile", "toml 0.7.8", @@ -1228,9 +1229,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", diff --git a/crates/rugpi-common/src/system/info.rs b/crates/rugpi-common/src/system/info.rs new file mode 100644 index 0000000..e27a07f --- /dev/null +++ b/crates/rugpi-common/src/system/info.rs @@ -0,0 +1,60 @@ +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; + +use super::System; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SystemInfo { + boot_flow: String, + slots: IndexMap, + boot_groups: IndexMap, + default_boot_group: Option, + active_boot_group: Option, +} + +impl SystemInfo { + pub fn from(system: &System) -> Self { + let boot_flow = system.boot_flow().name().to_owned(); + let slots = system + .slots() + .iter() + .map(|(_, slot)| { + ( + slot.name().to_owned(), + SlotInfo { + active: slot.active(), + }, + ) + }) + .collect(); + let active_boot_group = system + .active_boot_entry() + .map(|idx| system.boot_entries()[idx].name().to_owned()); + let default_boot_group = Some( + system.boot_entries()[system.boot_flow().get_default(system).unwrap()] + .name() + .to_owned(), + ); + let boot_groups = system + .boot_entries() + .iter() + .map(|(_, group)| (group.name().to_owned(), BootGroupInfo {})) + .collect(); + Self { + boot_flow, + slots, + boot_groups, + active_boot_group, + default_boot_group, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SlotInfo { + active: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BootGroupInfo {} diff --git a/crates/rugpi-common/src/system/mod.rs b/crates/rugpi-common/src/system/mod.rs index 8c280c2..f158264 100644 --- a/crates/rugpi-common/src/system/mod.rs +++ b/crates/rugpi-common/src/system/mod.rs @@ -12,6 +12,7 @@ use crate::{disk::blkdev::BlockDevice, Anyhow}; pub mod boot_entries; pub mod boot_flows; pub mod config; +pub mod info; pub mod partitions; pub mod paths; pub mod root; diff --git a/crates/rugpi-ctrl/Cargo.toml b/crates/rugpi-ctrl/Cargo.toml index 7cdf50c..27c4516 100644 --- a/crates/rugpi-ctrl/Cargo.toml +++ b/crates/rugpi-ctrl/Cargo.toml @@ -22,6 +22,7 @@ sha2 = "0.10.8" hex = "0.4.3" tracing.workspace = true indexmap = "2.5.0" +serde_json = "1.0.133" [lints] workspace = true diff --git a/crates/rugpi-ctrl/src/cli.rs b/crates/rugpi-ctrl/src/cli.rs index 4bc7afc..2cbee93 100644 --- a/crates/rugpi-ctrl/src/cli.rs +++ b/crates/rugpi-ctrl/src/cli.rs @@ -14,6 +14,7 @@ use rugpi_common::{ stream_hasher::StreamHasher, system::{ boot_entries::{BootEntry, BootEntryIdx}, + info::SystemInfo, slots::SlotKind, System, }, @@ -142,17 +143,22 @@ pub fn main() -> Anyhow<()> { } } Command::System(sys_cmd) => match sys_cmd { - SystemCommand::Info => { - println!("Boot Flow: {}", system.boot_flow().name()); - let hot = system.active_boot_entry().unwrap(); - let default = system.boot_flow().get_default(&system)?; - let spare = system.spare_entry()?.unwrap().0; - let cold = if hot == default { spare } else { default }; - let entries = system.boot_entries(); - println!("Hot: {}", entries[hot].name()); - println!("Cold: {}", entries[cold].name()); - println!("Default: {}", entries[default].name()); - println!("Spare: {}", entries[spare].name()); + SystemCommand::Info { json } => { + if *json { + let info = SystemInfo::from(&system); + serde_json::to_writer_pretty(std::io::stdout(), &info)?; + } else { + println!("Boot Flow: {}", system.boot_flow().name()); + let hot = system.active_boot_entry().unwrap(); + let default = system.boot_flow().get_default(&system)?; + let spare = system.spare_entry()?.unwrap().0; + let cold = if hot == default { spare } else { default }; + let entries = system.boot_entries(); + println!("Hot: {}", entries[hot].name()); + println!("Cold: {}", entries[cold].name()); + println!("Default: {}", entries[default].name()); + println!("Spare: {}", entries[spare].name()); + } } SystemCommand::Commit => { if system.needs_commit()? { @@ -397,7 +403,11 @@ pub enum UpdateRebootType { #[derive(Debug, Parser)] pub enum SystemCommand { - Info, + Info { + /// Output system information as JSON. + #[clap(long)] + json: bool, + }, /// Make the hot system the default. Commit, /// Reboot the system.