diff --git a/Cargo.lock b/Cargo.lock index 8510092..cf442cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,7 +566,7 @@ dependencies = [ [[package]] name = "dmtrctl" -version = "2.0.1" +version = "2.1.0" dependencies = [ "base64 0.22.1", "clap", diff --git a/Cargo.toml b/Cargo.toml index 4aa1471..df7206b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dmtrctl" -version = "2.0.2" +version = "2.1.0" edition = "2021" repository = "https://github.com/demeter-run/cli" license = "Apache-2.0" diff --git a/src/ports/format.rs b/src/ports/format.rs index 9fd4556..35cfbd2 100644 --- a/src/ports/format.rs +++ b/src/ports/format.rs @@ -3,6 +3,31 @@ use comfy_table::presets::UTF8_FULL; use comfy_table::{ContentArrangement, Table}; use dmtri::demeter::ops::v1alpha::Resource; use miette::IntoDiagnostic; +use serde::Serialize; + +#[derive(clap::ValueEnum, Clone, Default, Debug, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum OutputFormat { + #[default] + Table, + Json, +} + +impl OutputFormat { + pub fn pretty_print(&self, resources: Vec) { + match self { + OutputFormat::Table => pretty_print_resource_table(resources), + OutputFormat::Json => pretty_print_resource_json(resources), + } + } + + pub fn pretty_print_single(&self, resource: &Resource) { + match self { + OutputFormat::Table => pretty_print_resource_detail_table(resource), + OutputFormat::Json => pretty_print_resource_detail_json(resource), + } + } +} pub fn pretty_print_resource_table(resources: Vec) { let mut table = Table::new(); @@ -26,17 +51,78 @@ pub fn pretty_print_resource_table(resources: Vec) { println!("{table}"); } -pub fn pretty_print_resouce_detail_table(resources: Vec) -> miette::Result<()> { - let mut table = Table::new(); +pub fn pretty_print_resource_json(resources: Vec) { + let mut collector = vec![]; + for resource in resources { + collector.push(serde_json::Map::from_iter(vec![ + ("id".to_string(), serde_json::Value::from(resource.id)), + ("name".to_string(), serde_json::Value::from(resource.name)), + ("kind".to_string(), serde_json::Value::from(resource.kind)), + ( + "created_at".to_string(), + serde_json::Value::from(resource.created_at), + ), + ( + "spec".to_string(), + serde_json::from_str::(&resource.spec).unwrap(), + ), + ( + "annotations".to_string(), + serde_json::from_str::( + &resource.annotations.unwrap_or_default(), + ) + .unwrap(), + ), + ])) + } + println!("{}", serde_json::to_string_pretty(&collector).unwrap()); +} + +pub fn pretty_print_resource_detail_json(resource: &Resource) { + println!( + "{}", + serde_json::to_string_pretty( + &(serde_json::Map::from_iter(vec![ + ( + "id".to_string(), + serde_json::Value::from(resource.id.clone()) + ), + ( + "name".to_string(), + serde_json::Value::from(resource.name.clone()) + ), + ( + "kind".to_string(), + serde_json::Value::from(resource.kind.clone()) + ), + ( + "created_at".to_string(), + serde_json::Value::from(resource.created_at.clone()), + ), + ( + "spec".to_string(), + serde_json::from_str::(&resource.spec).unwrap(), + ), + ( + "annotations".to_string(), + serde_json::from_str::( + &resource.annotations.clone().unwrap_or_default(), + ) + .unwrap(), + ), + ])) + ) + .unwrap() + ); +} - let Some(first_resource) = resources.first() else { - return Ok(()); - }; +pub fn pretty_print_resource_detail_table(resource: &Resource) { + let mut table = Table::new(); let annotations = serde_json::from_str::( - &first_resource.annotations.clone().unwrap_or_default(), + &resource.annotations.clone().unwrap_or_default(), ) - .into_diagnostic()?; + .unwrap(); let mut annotations_headers: Vec = annotations .as_array() .unwrap() @@ -53,29 +139,25 @@ pub fn pretty_print_resouce_detail_table(resources: Vec) -> miette::Re .set_content_arrangement(ContentArrangement::Dynamic) .set_header(headers); - for resource in resources { - let mut values: Vec = vec![resource.name]; - - if let Some(annotations) = resource.annotations { - let annotations: serde_json::Value = - serde_json::from_str(&annotations).into_diagnostic()?; - - for value in annotations.as_array().unwrap().iter() { - values.push( - value - .get("value") - .unwrap() - .as_str() - .unwrap_or_default() - .into(), - ); - } - } + let mut values: Vec = vec![resource.name.clone()]; + + if let Some(annotations) = &resource.annotations { + let annotations: serde_json::Value = + serde_json::from_str(annotations).into_diagnostic().unwrap(); - table.add_row(values); + for value in annotations.as_array().unwrap().iter() { + values.push( + value + .get("value") + .unwrap() + .as_str() + .unwrap_or_default() + .into(), + ); + } } - println!("{table}"); + table.add_row(values); - Ok(()) + println!("{table}"); } diff --git a/src/ports/list.rs b/src/ports/list.rs index 20fac9a..b49a8d2 100644 --- a/src/ports/list.rs +++ b/src/ports/list.rs @@ -2,15 +2,18 @@ use clap::Parser; use crate::{ context::extract_context_data, - rpc::{self}, + rpc, }; -use super::format::pretty_print_resource_table; +use super::format::OutputFormat; #[derive(Parser)] -pub struct Args {} +pub struct Args { + #[clap(short, long, default_value_t, value_enum)] + pub output: OutputFormat, +} -pub async fn run(cli: &crate::Cli) -> miette::Result<()> { +pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { let _ctx = cli .context .as_ref() @@ -24,7 +27,6 @@ pub async fn run(cli: &crate::Cli) -> miette::Result<()> { return Ok(()); } - pretty_print_resource_table(response); - + args.output.pretty_print(response); Ok(()) } diff --git a/src/ports/mod.rs b/src/ports/mod.rs index c0b1751..97d74ab 100644 --- a/src/ports/mod.rs +++ b/src/ports/mod.rs @@ -32,7 +32,7 @@ pub enum Commands { pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { match args.command { - Commands::List(_) => list::run(cli).await, + Commands::List(x) => list::run(x, cli).await, Commands::Show(x) => show::run(x, cli).await, Commands::Create(x) => create::run(x, cli).await, Commands::Delete(x) => delete::run(x, cli).await, diff --git a/src/ports/show.rs b/src/ports/show.rs index 35c2abe..c2cefee 100644 --- a/src/ports/show.rs +++ b/src/ports/show.rs @@ -2,12 +2,15 @@ use clap::Parser; use crate::{context::extract_context_data, rpc}; -use super::format::pretty_print_resouce_detail_table; +use super::format::OutputFormat; #[derive(Parser)] pub struct Args { /// the resource uuid id: String, + + #[clap(short, long, default_value_t, value_enum)] + pub output: OutputFormat, } pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { @@ -24,6 +27,7 @@ pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { return Ok(()); } - pretty_print_resouce_detail_table(resouces)?; + let response = resouces.first().unwrap(); + args.output.pretty_print_single(response); Ok(()) }