From bb5ea5c67ff27153538b164fdb504790397fce4a Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 17 Sep 2024 18:02:06 -0500 Subject: [PATCH] move parsing into cmdrun instead of in main --- src/cmdrun.rs | 106 +++++++++++++++++++++++++------------------------- src/main.rs | 55 +++++--------------------- 2 files changed, 63 insertions(+), 98 deletions(-) diff --git a/src/cmdrun.rs b/src/cmdrun.rs index 5e0d776..8086911 100644 --- a/src/cmdrun.rs +++ b/src/cmdrun.rs @@ -16,6 +16,8 @@ use mdbook::book::Book; use mdbook::book::Chapter; use mdbook::preprocess::{Preprocessor, PreprocessorContext}; +use clap::value_parser; + use crate::utils::map_chapter; pub struct CmdRun; @@ -159,62 +161,24 @@ impl CmdRun { // This method is public for unit tests pub fn run_cmdrun(command: String, working_dir: &str, inline: bool) -> Result { - let (command, correct_exit_code): (String, Option) = if let Some(first_word) = - command.split_whitespace().next() - { - if first_word.starts_with('-') { - if first_word.starts_with("--") { - // double-tick long form - match first_word { - "--strict" => ( - command - .split_whitespace() - .skip(1) - .collect::>() - .join(" "), - Some(0), - ), - "--expect-return-code" => { - if let Some(second_word) = command.split_whitespace().nth(1) { - ( - command - .split_whitespace() - .skip(2) - .collect::>() - .join(" "), - Some(second_word.parse()?), - ) - } else { - // no second word after return code, print error - return Ok(format!("**cmdrun error**: No return code after '--expect-return-code' for command {command}.")); - } - } - some_other_word => { - // unrecognized flag, print error - return Ok(format!("**cmdrun error**: Unrecognized cmdrun flag {some_other_word} in 'cmdrun {command}'")); - } - } - } else { - // single-tick short form - let (_, exit_code) = first_word.rsplit_once('-').unwrap_or(("", "0")); - ( - command - .split_whitespace() - .skip(1) - .collect::>() - .join(" "), - Some(exit_code.parse()?), - ) - } - } else { - (command, None) - } + let parser = make_cmdrun_parser(); + let matches = parser.try_get_matches_from(command.split_whitespace())?; + + let cmd : Vec<_> = matches + .try_get_many::("cmd") + .expect("able to parse a command and not get Err") + .expect("able to parse a command and not get None") + .map(|s| s.as_str()) + .collect(); + let correct_exit_code = if matches.get_flag("strict") { + Some(&0) } else { - (command, None) + matches.try_get_one("expect-return-code")? }; let output = Command::new(LAUNCH_SHELL_COMMAND) - .args([LAUNCH_SHELL_FLAG, &command]) + .args([LAUNCH_SHELL_FLAG]) + .args(cmd) .current_dir(working_dir) .output() .with_context(|| "Fail to run shell")?; @@ -223,7 +187,7 @@ impl CmdRun { match (output.status.code(), correct_exit_code) { (None, _) => Ok(format!("'{command}' was ended before completing.")), (Some(code), Some(correct_code)) => { - if code != correct_code { + if code != *correct_code { Ok( format!( "**cmdrun error**: '{command}' returned exit code {code} instead of {correct_code}.\n{0}\n{1}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr)) @@ -241,3 +205,39 @@ impl CmdRun { } } } + + +fn make_cmdrun_parser() -> clap::Command { + clap::Command::new("cmdrun") + .about("test run a command before putting it in a book") + .arg( + clap::Arg::new("expect-return-code") + .help("require the specific return code N") + .long("expect-return-code") + .conflicts_with("strict") +// .conflicts_with("exit-code-short") + .num_args(1) + .value_name("N") + .value_parser(value_parser!(i32)) + ).arg( + clap::Arg::new("strict") + .help("require command to return the successful exit code 0") + .long("strict") + .conflicts_with("expect-return-code") +// .conflicts_with("exit-code-short") + .action(clap::ArgAction::SetTrue) +// ).arg( +// Arg::new("exit-code-short") +// .help("require the specific exit code N") +// .conflicts_with("expect-return-code") +// .conflicts_with("strict") +// .value_name("-N") +// .allow_negative_numbers(true) +// .value_parser(..=0) + ).arg( + clap::Arg::new("cmd") + .help("command whose output will be injected into book") + .num_args(1..) + .trailing_var_arg(true) + ) +} diff --git a/src/main.rs b/src/main.rs index 3c93209..0d59110 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use clap::{Arg, ArgMatches, Command, value_parser}; +use clap::{Arg, ArgMatches, Command}; use mdbook::errors::Error; use mdbook::preprocess::CmdPreprocessor; use mdbook::preprocess::Preprocessor; @@ -16,14 +16,13 @@ fn main() { if let Some(sub_args) = matches.subcommand_matches("supports") { handle_supports(sub_args); } else if let Some(sub_args) = matches.subcommand_matches("cmdrun") { - let cmd = sub_args.try_get_many::("cmd"); - let correct_exit_code = if sub_args.get_flag("strict") { - Ok(Some(&0)) - } else { - sub_args.try_get_one("expect-return-code") - }; - println!("{:?} {:?}", correct_exit_code, cmd) - //CmdRun::run_cmdrun(sub_args, ".", false); + let text : String = sub_args + .try_get_many::("text") + .expect("able to parse a command and not get Err") + .expect("able to parse a command and not get None") + .map(|s| s.as_str()) + .collect(); + println!("{}", CmdRun::run_cmdrun(text, ".", false).unwrap()); } else if let Err(e) = handle_preprocessing() { eprintln!("{e}"); process::exit(1); @@ -33,41 +32,6 @@ fn main() { } } -fn make_cmdrun_parser() -> Command { - Command::new("cmdrun") - .about("test run a command before putting it in a book") - .arg( - Arg::new("expect-return-code") - .help("require the specific return code N") - .long("expect-return-code") - .conflicts_with("strict") -// .conflicts_with("exit-code-short") - .num_args(1) - .value_name("N") - .value_parser(value_parser!(i32)) - ).arg( - Arg::new("strict") - .help("require command to return the successful exit code 0") - .long("strict") - .conflicts_with("expect-return-code") -// .conflicts_with("exit-code-short") - .action(clap::ArgAction::SetTrue) -// ).arg( -// Arg::new("exit-code-short") -// .help("require the specific exit code N") -// .conflicts_with("expect-return-code") -// .conflicts_with("strict") -// .value_name("-N") -// .allow_negative_numbers(true) -// .value_parser(..=0) - ).arg( - Arg::new("cmd") - .help("command whose output will be injected into book") - .num_args(1..) - .trailing_var_arg(true) - ) -} - fn make_app() -> Command { Command::new("mdbook-cmdrun") .about("mdbook preprocessor to run arbitrary commands and replace the stdout of these commands inside the markdown file.") @@ -76,7 +40,8 @@ fn make_app() -> Command { .arg(Arg::new("renderer").required(true)) .about("Check whether a renderer is supported by this preprocessor"), ).subcommand( - make_cmdrun_parser() + Command::new("cmdrun") + .arg(Arg::new("text").num_args(1..).trailing_var_arg(true)) ) }