From 95c9cda01f0db5f9608aeec851030ffbf2973df4 Mon Sep 17 00:00:00 2001 From: w3irdrobot <3712883+w3irdrobot@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:03:03 -0400 Subject: [PATCH] Add output flag to send output to file (#404) --- crates/web5_cli/src/dids/create.rs | 38 +++++++++++++----------------- crates/web5_cli/src/dids/mod.rs | 12 +++++----- crates/web5_cli/src/main.rs | 22 +++++++++++++---- crates/web5_cli/src/pds/create.rs | 4 ++-- crates/web5_cli/src/pds/mod.rs | 4 ++-- crates/web5_cli/src/vcs.rs | 14 +++++------ 6 files changed, 52 insertions(+), 42 deletions(-) diff --git a/crates/web5_cli/src/dids/create.rs b/crates/web5_cli/src/dids/create.rs index d2b0453d..987cb1be 100644 --- a/crates/web5_cli/src/dids/create.rs +++ b/crates/web5_cli/src/dids/create.rs @@ -1,6 +1,8 @@ +use crate::utils::warn_if_not_root; use clap::Subcommand; use std::sync::Arc; use url::Url; +use web5::dids::data_model::service::Service; use web5::{ crypto::key_managers::in_memory_key_manager::InMemoryKeyManager, dids::{ @@ -12,8 +14,6 @@ use web5::{ portable_did::PortableDid, }, }; -use web5::dids::data_model::service::Service; -use crate::utils::warn_if_not_root; #[derive(Subcommand, Debug)] pub enum Commands { @@ -27,10 +27,7 @@ pub enum Commands { domain: String, #[arg(long)] service_endpoint: Option, - #[arg( - long = "service-endpoint-type", - default_value = "LinkedDomains" - )] + #[arg(long = "service-endpoint-type", default_value = "LinkedDomains")] service_endpoint_type: String, #[arg(long)] no_indent: bool, @@ -40,10 +37,7 @@ pub enum Commands { Dht { #[arg(long)] service_endpoint: Option, - #[arg( - long = "service-endpoint-type", - default_value = "LinkedDomains" - )] + #[arg(long = "service-endpoint-type", default_value = "LinkedDomains")] service_endpoint_type: String, #[arg(long)] no_publish: bool, @@ -54,7 +48,12 @@ pub enum Commands { }, } -fn print_portable_did(portable_did: PortableDid, no_indent: &bool, json_escape: &bool) { +fn print_portable_did( + mut sink: impl std::io::Write, + portable_did: PortableDid, + no_indent: &bool, + json_escape: &bool, +) { let mut output_str = match no_indent { true => serde_json::to_string(&portable_did).unwrap(), false => serde_json::to_string_pretty(&portable_did).unwrap(), @@ -64,11 +63,11 @@ fn print_portable_did(portable_did: PortableDid, no_indent: &bool, json_escape: output_str = output_str.replace('"', "\\\""); } - println!("{}", output_str); + writeln!(sink, "{}", output_str).unwrap(); } impl Commands { - pub async fn command(&self) { + pub async fn command(&self, sink: impl std::io::Write) { match self { Commands::Jwk { no_indent, @@ -86,7 +85,7 @@ impl Commands { let portable_did = bearer_did.to_portable_did(key_manager).unwrap(); - print_portable_did(portable_did, no_indent, json_escape); + print_portable_did(sink, portable_did, no_indent, json_escape); } Commands::Web { domain, @@ -129,12 +128,11 @@ impl Commands { did_web_create_options.service = Some(vec![service]); } - let bearer_did = DidWeb::create(domain, Some(did_web_create_options)) - .unwrap(); + let bearer_did = DidWeb::create(domain, Some(did_web_create_options)).unwrap(); let portable_did = bearer_did.to_portable_did(key_manager).unwrap(); - print_portable_did(portable_did, no_indent, json_escape); + print_portable_did(sink, portable_did, no_indent, json_escape); } Commands::Dht { service_endpoint, @@ -163,13 +161,11 @@ impl Commands { did_dht_create_options.service = Some(vec![service]); } - let bearer_did = DidDht::create(Some(did_dht_create_options)) - .await - .unwrap(); + let bearer_did = DidDht::create(Some(did_dht_create_options)).await.unwrap(); let portable_did = bearer_did.to_portable_did(key_manager).unwrap(); - print_portable_did(portable_did, no_indent, json_escape); + print_portable_did(sink, portable_did, no_indent, json_escape); } } } diff --git a/crates/web5_cli/src/dids/mod.rs b/crates/web5_cli/src/dids/mod.rs index 47dae9e5..53c76504 100644 --- a/crates/web5_cli/src/dids/mod.rs +++ b/crates/web5_cli/src/dids/mod.rs @@ -17,21 +17,21 @@ pub enum Commands { } impl Commands { - pub async fn command(&self) { + pub async fn command(&self, mut sink: impl std::io::Write) { match self { Commands::Resolve { uri } => { let resolution_result = ResolutionResult::resolve(uri).await; match &resolution_result.resolution_metadata.error { - Some(e) => println!("{:?} {}", e, e), + Some(e) => eprintln!("{:?} {}", e, e), None => match &resolution_result.document { - None => println!( + None => eprintln!( "{:?} {}", ResolutionMetadataError::InternalError, ResolutionMetadataError::InternalError ), Some(document) => match serde_json::to_string_pretty(&document) { - Ok(s) => println!("{}", s), - Err(_) => println!( + Ok(s) => writeln!(sink, "{}", s).unwrap(), + Err(_) => eprintln!( "{:?} {}", ResolutionMetadataError::InternalError, ResolutionMetadataError::InternalError @@ -40,7 +40,7 @@ impl Commands { }, } } - Commands::Create { did_create_command } => did_create_command.command().await, + Commands::Create { did_create_command } => did_create_command.command(sink).await, } } } diff --git a/crates/web5_cli/src/main.rs b/crates/web5_cli/src/main.rs index 8959a130..bac6c9e4 100644 --- a/crates/web5_cli/src/main.rs +++ b/crates/web5_cli/src/main.rs @@ -4,6 +4,8 @@ mod test; mod utils; mod vcs; +use std::fs::File; + use clap::{Parser, Subcommand}; #[derive(Parser, Debug)] @@ -14,6 +16,9 @@ use clap::{Parser, Subcommand}; struct Cli { #[command(subcommand)] command: Commands, + /// A file to output command output to. + #[arg(long, global = true)] + output: Option, } #[derive(Subcommand, Debug)] @@ -37,9 +42,18 @@ enum Commands { async fn main() { let cli = Cli::parse(); - match cli.command { - Commands::Did { did_command } => did_command.command().await, - Commands::Vc { vc_command } => vc_command.command().await, - Commands::Pd { pd_command } => pd_command.command().await, + if let Some(path) = cli.output { + let file = File::create(path).unwrap(); + command(cli.command, file).await; + } else { + command(cli.command, std::io::stdout()).await; + } +} + +async fn command(command: Commands, sink: impl std::io::Write) { + match command { + Commands::Did { did_command } => did_command.command(sink).await, + Commands::Vc { vc_command } => vc_command.command(sink).await, + Commands::Pd { pd_command } => pd_command.command(sink).await, } } diff --git a/crates/web5_cli/src/pds/create.rs b/crates/web5_cli/src/pds/create.rs index 6e47ccb3..0aa4f3ab 100644 --- a/crates/web5_cli/src/pds/create.rs +++ b/crates/web5_cli/src/pds/create.rs @@ -229,6 +229,6 @@ fn str_to_option_string(value: &str) -> Option { (!value.is_empty()).then(|| value.to_string()) } -pub fn run_create_command(args: CreatePresentationDefinition) { - println!("{}", args.get_output()); +pub fn run_create_command(args: CreatePresentationDefinition, mut sink: impl std::io::Write) { + writeln!(sink, "{}", args.get_output()).unwrap(); } diff --git a/crates/web5_cli/src/pds/mod.rs b/crates/web5_cli/src/pds/mod.rs index 18cc83f2..b5cf1de0 100644 --- a/crates/web5_cli/src/pds/mod.rs +++ b/crates/web5_cli/src/pds/mod.rs @@ -37,9 +37,9 @@ pub enum Commands { } impl Commands { - pub async fn command(self) { + pub async fn command(self, sink: impl std::io::Write) { match self { - Commands::Create(args) => create::run_create_command(args), + Commands::Create(args) => create::run_create_command(args, sink), }; } } diff --git a/crates/web5_cli/src/vcs.rs b/crates/web5_cli/src/vcs.rs index 1e6c0d44..68c114e8 100644 --- a/crates/web5_cli/src/vcs.rs +++ b/crates/web5_cli/src/vcs.rs @@ -94,7 +94,7 @@ pub enum Commands { } impl Commands { - pub async fn command(self) { + pub async fn command(self, mut sink: impl std::io::Write) { match self { Commands::Create { credential_subject_id, @@ -189,12 +189,12 @@ impl Commands { output_str = output_str.replace('"', "\\\""); } - println!("{}", output_str); + writeln!(sink, "{}", output_str).unwrap(); if let Some(portable_did) = portable_did { let bearer_did = BearerDid::from_portable_did(portable_did).unwrap(); let vc_jwt = vc.sign(&bearer_did, None).unwrap(); - println!("\n{}", vc_jwt); + writeln!(sink, "\n{}", vc_jwt).unwrap(); } } Commands::Verify { @@ -203,11 +203,11 @@ impl Commands { json_escape, } => match VerifiableCredential::from_vc_jwt(&vc_jwt, true).await { Err(e) => { - println!("\n❌ Verfication failed\n"); - println!("{:?} {}", e, e); + eprintln!("\n❌ Verfication failed\n"); + eprintln!("{:?} {}", e, e); } Ok(vc) => { - println!("\n✅ Verfied\n"); + writeln!(sink, "\n✅ Verfied\n").unwrap(); let mut output_str = match no_indent { true => serde_json::to_string(&vc).unwrap(), @@ -218,7 +218,7 @@ impl Commands { output_str = output_str.replace('"', "\\\""); } - println!("{}", output_str); + writeln!(sink, "{}", output_str).unwrap(); } }, }