From 65d845394685b0f947c1921262e53cc2a62ee21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20F=C3=A4rber?= <01mf02@gmail.com> Date: Thu, 7 Nov 2024 10:27:07 +0100 Subject: [PATCH 1/3] Support `--args`. --- jaq/src/main.rs | 33 ++++++++++++++++++++++----------- jaq/tests/golden.rs | 7 +++++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/jaq/src/main.rs b/jaq/src/main.rs index 02afdaa32..d591f663d 100644 --- a/jaq/src/main.rs +++ b/jaq/src/main.rs @@ -109,8 +109,12 @@ struct Cli { #[arg(long, value_name = "FILE")] run_tests: Option, - /// Filter to execute, followed by list of input files + /// Consume remaining arguments as positional string values + #[arg(long, allow_hyphen_values = true, num_args = 0..)] args: Vec, + + /// Filter to execute, followed by list of input files + rest: Vec, } #[derive(Clone, ValueEnum)] @@ -171,15 +175,16 @@ fn real_main(cli: &Cli) -> Result { let (vars, mut ctx): (Vec, Vec) = binds(cli)?.into_iter().unzip(); - let mut args = cli.args.iter(); + let mut rest = cli.rest.iter(); + let file = match &cli.from_file { Some(path) => Some(( path.as_path().display().to_string(), std::fs::read_to_string(path)?, )), - None => args.next().cloned().map(|code| ("".into(), code)), + None => rest.next().cloned().map(|code| ("".into(), code)), }; - let files: Vec<_> = args.collect(); + let files: Vec<_> = rest.collect(); let (vals, filter) = match file { None => (Vec::new(), Filter::default()), @@ -259,19 +264,25 @@ fn binds(cli: &Cli) -> Result, Error> { json_array(path).map_err(|e| Error::Io(Some(path.to_string()), e)) })?; - var_val.push(("ARGS".to_string(), args_named(&var_val))); + let positional = cli.args.iter().filter(|arg| *arg != "--").cloned(); + let positional: Vec<_> = positional.map(Val::from).collect(); + + var_val.push(("ARGS".to_string(), args(&positional, &var_val))); let env = std::env::vars().map(|(k, v)| (k.into(), Val::from(v))); var_val.push(("ENV".to_string(), Val::obj(env.collect()))); Ok(var_val) } -fn args_named(var_val: &[(String, Val)]) -> Val { - let named = var_val - .iter() - .map(|(var, val)| (var.clone().into(), val.clone())); - let args = std::iter::once(("named".to_string().into(), Val::obj(named.collect()))); - Val::obj(args.collect()) +fn args(positional: &[Val], named: &[(String, Val)]) -> Val { + let key = |k: &str| k.to_string().into(); + let positional = positional.iter().cloned(); + let named = named.iter().map(|(var, val)| (key(var), val.clone())); + let obj = [ + (key("positional"), positional.collect()), + (key("named"), Val::obj(named.collect())), + ]; + Val::obj(obj.into_iter().collect()) } fn parse( diff --git a/jaq/tests/golden.rs b/jaq/tests/golden.rs index 6cbf50be3..e59edc3cf 100644 --- a/jaq/tests/golden.rs +++ b/jaq/tests/golden.rs @@ -43,6 +43,13 @@ test!( "\"yb\"" ); +test!( + args, + &["-c", "$ARGS", "--arg", "x", "y", "--args", "a", "--", "--test"], + "0", + r#"{"positional":["a","--test"],"named":{"x":"y"}}"# +); + test!( compact, &["-c", "."], From 3e238ed4420c4e3e89ea164a5ecae021b0839820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20F=C3=A4rber?= <01mf02@gmail.com> Date: Thu, 7 Nov 2024 17:21:10 +0100 Subject: [PATCH 2/3] Filter out only the first `--` after `--args` to improve compatibility. --- jaq/src/main.rs | 6 ++++-- jaq/tests/golden.rs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jaq/src/main.rs b/jaq/src/main.rs index d591f663d..19e0fc626 100644 --- a/jaq/src/main.rs +++ b/jaq/src/main.rs @@ -264,8 +264,10 @@ fn binds(cli: &Cli) -> Result, Error> { json_array(path).map_err(|e| Error::Io(Some(path.to_string()), e)) })?; - let positional = cli.args.iter().filter(|arg| *arg != "--").cloned(); - let positional: Vec<_> = positional.map(Val::from).collect(); + let mut first = true; + let positional = cli.args.iter(); + let positional = positional.filter(|arg| *arg != "--" || !core::mem::take(&mut first)); + let positional: Vec<_> = positional.cloned().map(Val::from).collect(); var_val.push(("ARGS".to_string(), args(&positional, &var_val))); let env = std::env::vars().map(|(k, v)| (k.into(), Val::from(v))); diff --git a/jaq/tests/golden.rs b/jaq/tests/golden.rs index e59edc3cf..039dfd27e 100644 --- a/jaq/tests/golden.rs +++ b/jaq/tests/golden.rs @@ -45,9 +45,9 @@ test!( test!( args, - &["-c", "$ARGS", "--arg", "x", "y", "--args", "a", "--", "--test"], + &["-c", "$ARGS", "--arg", "x", "y", "--args", "a", "--", "--test", "--"], "0", - r#"{"positional":["a","--test"],"named":{"x":"y"}}"# + r#"{"positional":["a","--test","--"],"named":{"x":"y"}}"# ); test!( From d625f05e08d511c5ef6294852b7b9e1b5cf8fafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20F=C3=A4rber?= <01mf02@gmail.com> Date: Fri, 8 Nov 2024 10:52:57 +0100 Subject: [PATCH 3/3] Document `--` behaviour for `--args`. --- jaq/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jaq/src/main.rs b/jaq/src/main.rs index 19e0fc626..2fa847c38 100644 --- a/jaq/src/main.rs +++ b/jaq/src/main.rs @@ -110,6 +110,8 @@ struct Cli { run_tests: Option, /// Consume remaining arguments as positional string values + /// + /// This ignores the first occurrence of `--` after `--args`. #[arg(long, allow_hyphen_values = true, num_args = 0..)] args: Vec,