From 14cd0990b603d6bd76c1a9da92357a60b3ef452c Mon Sep 17 00:00:00 2001 From: blob42 Date: Thu, 15 Feb 2024 01:17:04 +0100 Subject: [PATCH] yarg cmd execution prototype - handle multiple yarg command son columns --- TODO.md | 18 ++++++++----- src/lib.rs | 2 +- src/main.rs | 47 +++++++++++++++++++++++++++++++-- tests/cli.rs | 51 +++++++++++++++++------------------- tests/inputs/input2_spaces | 2 ++ tests/outputs/output2_spaces | 2 ++ 6 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 tests/inputs/input2_spaces create mode 100644 tests/outputs/output2_spaces diff --git a/TODO.md b/TODO.md index 43e40d9..bfdbe0b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,12 @@ - 1.  parse cli parameters - 2.  read from stdin - 3.  split stdin into columns - 3.  map (execute) commands to fields - - [ ] execute a command on first text column - 4. print resulting concatenated columns + -  parse cli parameters + -  read from stdin + -  split stdin into columns + - handle different separator types + - handle commands with args + - detect if cmd has more than one arg + -  map (execute) commands to fields + - [ ] execute a command on first text column + - print resulting concatenated columns + + - delimiter: use regex or literal char/str + diff --git a/src/lib.rs b/src/lib.rs index d6cbb9f..ea7135f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ impl Deref for Columns { } -// build Columns from &str +// build Columns from &str impl TryFrom<&str> for Columns { type Error = anyhow::Error; diff --git a/src/main.rs b/src/main.rs index 33d1eb1..d6175db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use yargs::{DEFAULT_SEP_PATTERN, stdin}; use yargs::parse::InputText; use anyhow::Result; use std::io::{BufRead, Read, BufReader, stdin, Write}; +use std::os; use std::process::{self, Command, Stdio}; @@ -30,7 +31,7 @@ use std::process::{self, Command, Stdio}; #[command(author="blob42")] #[command(version="0.1")] struct Cli { - /// Regex used to to split input into columns + /// Regex used for splitting the input into columns #[arg(default_value=DEFAULT_SEP_PATTERN)] #[arg(short)] delimiter: String, @@ -110,7 +111,49 @@ fn main() -> Result<()> { } else { // Handle yargs // For each columns of text, execute the arg command on - // the columns lines (xargs) + // the column lines + + // naive implementation + // TODO: map input columns into output processed commands + for (i, yarg) in cli.yargs.into_iter().enumerate() { + + // let yarg_cmd = &yarg.split_whitespace().nth(0).unwrap_or(&yarg); + // dbg!(yarg_cmd); + // let yarg_args: Vec<&str> = yarg.split_whitespace().skip(1).collect(); + // dbg!(yarg_args); + + // for each yarg split into cmd, args + let mut yarg_cmd = Command::new(&yarg.split_whitespace().nth(0).unwrap_or(&yarg)) + .args(yarg.split_whitespace().skip(1)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect(&format!("Failed to exec {yarg}")); + + let mut yarg_stdin = yarg_cmd.stdin.take().expect("failed to open stdin"); + let _columns = columns.clone(); + // yarg_stdin.write_all(columns[i].join("\n").as_bytes())?; + + // TODO!: use https://crates.io/crates/subprocess to spawn shell + // expl: using a long `awk ..` will fail if args are split on space the cmd needs to be + // passed as is to a subshell + std::thread::spawn(move || { + yarg_stdin.write_all(_columns[i].join("\n").as_bytes()).expect("Failed to write to stdin"); + }); + + // gather output from child + let output = yarg_cmd.wait_with_output() + .expect(format!("failed to read stdout for {}", yarg).as_str()); + + + // TODO: gather output into column similar to input print into column format + println!("{}", String::from_utf8_lossy(&output.stdout)); + + } + + + + process::exit(0); // we know we have at least one elm let yarg = cli.yargs.first().unwrap(); diff --git a/tests/cli.rs b/tests/cli.rs index c3ba37b..0ddd006 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -22,7 +22,7 @@ fn run_command(test_file: &str, cmd: &mut Command) -> AssertResult // empty stdin should return an empty line #[test] -fn pass(){ +fn no_stdin_no_args(){ let mut cmd = Command::cargo_bin("yargs").unwrap(); let assert = cmd .write_stdin("") @@ -30,13 +30,11 @@ fn pass(){ assert.stdout(""); } - - -#[test] // input with many columns // no positional arguments // behaves like cat -fn pass_columns_no_args() -> TestResult { +#[test] +fn stdin_no_args() -> TestResult { let input = Path::new("tests/inputs/input1"); let mut cmd = Command::cargo_bin("yargs").unwrap(); @@ -48,39 +46,38 @@ fn pass_columns_no_args() -> TestResult { } -#[test] -// should if more yargs provided than detected columns -fn fail_yargs_mismatch1() -> TestResult { - let input = Path::new("tests/inputs/input1"); - - let mut cmd = Command::cargo_bin("yargs").unwrap(); - - let assert = cmd - .args(["one", "two"]) - .pipe_stdin(input)? - .assert(); - assert.failure(); - Ok(()) -} - // n args <= n cols #[test] fn cli_pass2() { let mut cmd = Command::cargo_bin("yargs").unwrap(); - cmd.args(["-d", r"\s"]) - .args(["1", "2", "3", "4", "5", "6"]); + cmd.args(["-d", r"\s+"]) + .args(vec!["true"; 6]); run_command("tests/inputs/input1", &mut cmd).unwrap() .success(); } -#[test] -#[should_panic] -// more arguments passed than columns +// should fail if more yargs provided than detected columns +// the input text has 7 columns, we pass 8 yargs // delimiter: space +#[test] fn cli_fail1() { let mut cmd = Command::cargo_bin("yargs").unwrap(); - cmd.args(["-d", r"\s"]) - .args(["1", "2", "3", "4", "5", "6", "7", "8"]); + cmd.args(["-d", r"\s+"]) + .args(vec!["arg"; 8]); run_command("tests/inputs/input1", &mut cmd).unwrap() .failure(); } + +// should execute yarg corresponding to column +// first yarg transforms col to uppercase +// second yarg reverses the text +#[test] +fn cli_exec_yarg() { + let mut cmd = Command::cargo_bin("yargs").unwrap(); + cmd.args(["-d", r"\s+"]) + .args(["tr '[:lower:]' '[:upper:]'", "rev"]); + run_command("tests/inputs/input2_spaces", &mut cmd).unwrap() + .success() + .stdout(read_to_string(Path::new("tests/outputs/output2_spaces")).unwrap()); + +} diff --git a/tests/inputs/input2_spaces b/tests/inputs/input2_spaces new file mode 100644 index 0000000..9591e43 --- /dev/null +++ b/tests/inputs/input2_spaces @@ -0,0 +1,2 @@ +file1 300 +file2 400 diff --git a/tests/outputs/output2_spaces b/tests/outputs/output2_spaces new file mode 100644 index 0000000..64e4742 --- /dev/null +++ b/tests/outputs/output2_spaces @@ -0,0 +1,2 @@ +FILE1 003 +FILE2 004