简体   繁体   中英

Dynamically generating arguments Clap

I'm trying to figure out how to dynamically generating arguments from input arguments with Clap.

What I'm trying to emulate with Clap is the following python code:

parser = argparse.ArgumentParser()
parser.add_argument("-i", type=str, nargs="*")
(input_args, additional_args) = parser.parse_known_args()
for arg in input_args:
  parser.add_argument(f'--{arg}-bar', required=true, type=str)

additional_config = parser.parse_args(additional_args)

So that you can do the following in your command:

./foo.py -i foo bar baz --foo-bar foo --bar-bar bar --baz-bar bar

and have the additional arguments be dynamically generated from the first arguments. Not sure if it's possible to do in Clap but I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].

So here is my naive attempt of trying to do this.

use clap::{Arg, App};

fn main() {
  let mut app = App::new("foo")
               .arg(Arg::new("input")
               .short('i')
               .value_name("INPUT")
               .multiple(true)
               .required(true));
  let matches = app.get_matches_mut();
  let input: Vec<_> = matches.values_of("input").unwrap().collect()
  for i in input {
    app.arg(Arg::new(&*format!("{}-bar", i)).required(true))
  }
}

Which does not obviously having the compiler scream at you for both !format lifetime and app.arg I'm mostly interesting in solving how I could generate new arguments to the app which then could be matched against again. I'm quite new to rust so it's quite possible this is not possible with Clap.

[1] https://github.com/clap-rs/clap

I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].

Dynamically generating argument means that, you can .arg with runtime values and it'll work fine (aka the entire CLI doesn't need to be fully defined at compile-time, this distinction doesn't exist in Python as everything is done at runtime).

What you're doing here is significantly more complicated (and specialised, and odd) as you're passing through unknown parameters then re-parsing them.

Now first of all, you literally can't reuse App in clap: most of its methods (very much including get_matches ) take self and therefore "consume" the App and return something else, either the original App or a result. Although you can clone the original App before you get_matches it I guess.

But I don't think that's useful here: though I have not tried it should be possible do do what you want using TrailingVarArg : this would collect all trailing arguments into a single positional arg slice ( you will probably need AllowLeadingHyphen as well ), then you can create a second App with dynamically generated parameters in order to parse that sub-set of arguments ( get_matches_from will parse from an iterator rather than the env args , this is useful for testing... or for this exact sort of situations).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM