From 56aabe1511ab2745ad9e9859c1dad2738ff5f2cc Mon Sep 17 00:00:00 2001 From: Russell Date: Fri, 12 Jul 2024 13:44:29 -0700 Subject: [PATCH] refactor read options --- src/bin/hq.rs | 137 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 50 deletions(-) diff --git a/src/bin/hq.rs b/src/bin/hq.rs index b15ffca..dab22bf 100644 --- a/src/bin/hq.rs +++ b/src/bin/hq.rs @@ -5,17 +5,18 @@ use std::{ }; use clap::{Parser, Subcommand}; -use hq_rs::{parse_filter, query, write}; #[derive(Parser)] #[command(version, about)] struct Args { - #[clap(short, long, value_name = "FILE", help = "HCL file to read from")] - file: Option, - + // the `Read` options are duplicated here because when no command is given + // then the `read` command is the default and its options come from the root #[arg(value_name = "filter", help = "HCL filter expression")] filter: Option, + #[clap(short, long, value_name = "FILE", help = "HCL file to read from")] + file: Option, + #[command(subcommand)] command: Option, } @@ -23,69 +24,105 @@ struct Args { #[derive(Subcommand)] enum Command { #[command(about = "Read value from HCL (default)")] - Read, + Read { + #[arg(value_name = "filter", help = "HCL filter expression")] + filter: Option, + + #[clap(short, long, value_name = "FILE", help = "HCL file to read from")] + file: Option, + }, #[command(about = "Write value into HCL")] Write { + #[arg(value_name = "filter", help = "HCL filter expression")] + filter: Option, + + #[clap(short, long, value_name = "FILE", help = "HCL file to read from")] + file: Option, + #[arg(required = true, help = "Value to write into HCL")] value: String, }, } -impl Default for Command { - fn default() -> Self { - Self::Read - } -} - fn main() -> Result<(), Box> { let args = Args::parse(); - // Read the HCL from either a file or stdin - let buf = if let Some(file_path) = args.file { - fs::read_to_string(file_path)? - } else { - let mut stdin = io::stdin(); - let mut buf = String::new(); - stdin.read_to_string(&mut buf)?; - buf - }; - match args.command { - None | Some(Command::Read) => { - let body: hcl::Body = hcl::from_str(&buf)?; - - if let Some(filter) = args.filter { - let mut fields = parse_filter(&filter)?; - let query_results = query(&mut fields, &body); - for query_result in query_results { - let s = query_result.to_string()?; - print!("{s}"); - io::stdout().flush()?; - if !s.ends_with('\n') { - println!(); - } - } - } else { - println!("HCL from stdin contained:"); - println!(" * {} top-level attribute(s)", body.attributes().count()); - println!(" * {} top-level block(s)", body.blocks().count()); - } + None => { + read(args.filter, args.file)?; + } + Some(Command::Read { filter, file }) => { + read(filter, file)?; } - Some(Command::Write { value }) => { - let mut body: hcl_edit::structure::Body = buf.parse()?; + Some(Command::Write { + filter, + file, + value, + }) => { + write(filter, file, value)?; + } + } - let expr: hcl_edit::expr::Expression = value.parse()?; - if let Some(filter) = args.filter { - let fields = parse_filter(&filter)?; - write(fields, &mut body, &expr)?; - print!("{body}"); - io::stdout().flush()?; - } else { - print!("{expr}"); + Ok(()) +} + +fn read_stdin() -> Result> { + let mut stdin = io::stdin(); + let mut buf = String::new(); + stdin.read_to_string(&mut buf)?; + Ok(buf) +} + +fn read(filter: Option, file: Option) -> Result<(), Box> { + let contents = match file { + Some(file) => fs::read_to_string(file)?, + None => read_stdin()?, + }; + let body: hcl::Body = hcl::from_str(&contents)?; + match filter { + Some(filter) => { + let mut fields = hq_rs::parse_filter(&filter)?; + let query_results = hq_rs::query(&mut fields, &body); + for query_result in query_results { + let s = query_result.to_string()?; + print!("{s}"); io::stdout().flush()?; + if !s.ends_with('\n') { + println!(); + } } } + None => { + println!("HCL from stdin contained:"); + println!(" * {} top-level attribute(s)", body.attributes().count()); + println!(" * {} top-level block(s)", body.blocks().count()); + } } + Ok(()) +} +fn write( + filter: Option, + file: Option, + value: String, +) -> Result<(), Box> { + let contents = match file { + Some(file) => fs::read_to_string(file)?, + None => read_stdin()?, + }; + let mut body: hcl_edit::structure::Body = contents.parse()?; + let expr: hcl_edit::expr::Expression = value.parse()?; + match filter { + Some(filter) => { + let fields = hq_rs::parse_filter(&filter)?; + hq_rs::write(fields, &mut body, &expr)?; + print!("{body}"); + io::stdout().flush()?; + } + None => { + print!("{expr}"); + io::stdout().flush()?; + } + } Ok(()) }