From fe7e902a183cc32e739126ed157d6718a06c03f3 Mon Sep 17 00:00:00 2001 From: Jon Lamb Date: Mon, 16 Oct 2023 04:06:13 -0700 Subject: [PATCH] Add --field-name opts to CLI --- host_tools/air-gradient-cli/Cargo.toml | 2 +- .../src/command/device/info.rs | 31 ++++++++++++----- .../air-gradient-cli/src/device_util.rs | 33 +++++++++++++++++++ host_tools/air-gradient-cli/src/opts.rs | 17 +++++++++- 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/host_tools/air-gradient-cli/Cargo.toml b/host_tools/air-gradient-cli/Cargo.toml index d1acebe..3397065 100644 --- a/host_tools/air-gradient-cli/Cargo.toml +++ b/host_tools/air-gradient-cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "air-gradient-cli" authors = ["Jon Lamb"] -version = "0.4.0" +version = "0.4.1" edition = "2021" [[bin]] diff --git a/host_tools/air-gradient-cli/src/command/device/info.rs b/host_tools/air-gradient-cli/src/command/device/info.rs index e45a4a9..1993a65 100644 --- a/host_tools/air-gradient-cli/src/command/device/info.rs +++ b/host_tools/air-gradient-cli/src/command/device/info.rs @@ -1,7 +1,7 @@ use crate::{ device_util::{self, DeviceInfo}, interruptor::Interruptor, - opts::{CommonDeviceOpts, Format}, + opts::{DeviceInfo as DeviceInfoOps, Format}, }; use anyhow::Result; use std::net; @@ -12,12 +12,15 @@ use tokio::{ use tracing::debug; use wire_protocols::device::Command; -pub async fn info(cmd: CommonDeviceOpts, _intr: Interruptor) -> Result<()> { - if cmd.format.is_text() { - println!("Requesting device info from {}:{}", cmd.address, cmd.port); +pub async fn info(cmd: DeviceInfoOps, _intr: Interruptor) -> Result<()> { + if cmd.common.format.is_text() && cmd.common.verbose { + println!( + "Requesting device info from {}:{}", + cmd.common.address, cmd.common.port + ); } - let s = net::TcpStream::connect((cmd.address.as_str(), cmd.port))?; + let s = net::TcpStream::connect((cmd.common.address.as_str(), cmd.common.port))?; s.set_nonblocking(true)?; let mut stream = TcpStream::from_std(s)?; @@ -25,7 +28,7 @@ pub async fn info(cmd: CommonDeviceOpts, _intr: Interruptor) -> Result<()> { device_util::write_command(Command::Info, &mut stream).await?; let status = device_util::read_status(&mut stream).await?; - if cmd.format.is_text() { + if cmd.common.format.is_text() && cmd.common.verbose { println!("Status: {status}"); } @@ -35,8 +38,20 @@ pub async fn info(cmd: CommonDeviceOpts, _intr: Interruptor) -> Result<()> { let _info_len = buf_stream.read_line(&mut info_str).await?; let info = DeviceInfo::from_json(&info_str)?; - match cmd.format { - Format::Text => println!("{info:#?}"), + match cmd.common.format { + Format::Text => { + if cmd.field_names.is_empty() { + println!("{info:#?}") + } else { + let map = info.into_field_names_and_values(); + for field in cmd.field_names.into_iter() { + if let Some(v) = map.get(&field) { + println!("{v}"); + } + } + } + } + // TODO - handle field_names opts Format::Json => println!("{}", serde_json::to_string_pretty(&info)?), } diff --git a/host_tools/air-gradient-cli/src/device_util.rs b/host_tools/air-gradient-cli/src/device_util.rs index 221d8a6..60a45a8 100644 --- a/host_tools/air-gradient-cli/src/device_util.rs +++ b/host_tools/air-gradient-cli/src/device_util.rs @@ -28,6 +28,32 @@ impl DeviceInfo { pub fn from_json(s: &str) -> serde_json::Result { serde_json::from_str(s) } + + // TODO - use serde_transcode to do this instead of manually + pub fn into_field_names_and_values(self) -> serde_json::Map { + vec![ + ("protocol_version".to_owned(), self.protocol_version.into()), + ("firmware_version".to_owned(), self.firmware_version.into()), + ("device_id".to_owned(), self.device_id.into()), + ( + "device_serial_number".to_owned(), + self.device_serial_number.into(), + ), + ( + "mac_address".to_owned(), + fmt_mac_addr(&self.mac_address).into(), + ), + ( + "active_boot_slot".to_owned(), + self.active_boot_slot.to_string().into(), + ), + ("reset_reason".to_owned(), self.reset_reason.into()), + ("built_time_utc".to_owned(), self.built_time_utc.into()), + ("git_commit".to_owned(), self.git_commit.into()), + ] + .into_iter() + .collect() + } } pub async fn write_command(cmd: Command, s: &mut TcpStream) -> Result<()> { @@ -44,3 +70,10 @@ pub async fn read_status(s: &mut TcpStream) -> Result { bail!("Err status code = {sc}"); } } + +fn fmt_mac_addr(bytes: &[u8; 6]) -> String { + format!( + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] + ) +} diff --git a/host_tools/air-gradient-cli/src/opts.rs b/host_tools/air-gradient-cli/src/opts.rs index 99f9466..ff77cfe 100644 --- a/host_tools/air-gradient-cli/src/opts.rs +++ b/host_tools/air-gradient-cli/src/opts.rs @@ -71,7 +71,7 @@ pub struct InfluxRelay { #[derive(Parser, Debug, Clone)] pub enum Device { /// Request and print device info - Info(CommonDeviceOpts), + Info(DeviceInfo), /// Reboot a device Reboot(CommonDeviceOpts), @@ -94,8 +94,23 @@ pub struct DeviceUpdate { pub agp_images_cpio_file: PathBuf, } +#[derive(Parser, Debug, Clone)] +pub struct DeviceInfo { + #[clap(flatten)] + pub common: CommonDeviceOpts, + + /// Print the given field name rather than the entire info object. + /// Can be supplied multiple times. + #[arg(long = "field-name", short = 'F')] + pub field_names: Vec, +} + #[derive(Parser, Debug, Clone)] pub struct CommonDeviceOpts { + /// Verbose + #[arg(long, short = 'v')] + pub verbose: bool, + /// Address #[arg(long, short = 'a')] pub address: String,