Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

Ignore and save in vector unknow args #111

Open
epage opened this issue Dec 6, 2021 · 13 comments
Open

Ignore and save in vector unknow args #111

epage opened this issue Dec 6, 2021 · 13 comments

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by forkbomb9
Wednesday Jan 23, 2019 at 23:53 GMT
Originally opened as clap-rs/clap#1404


Affected Version of clap

  • 2.32.0

Bug or Feature Request Summary

It would be great to have a way to save unknow args into a Vec<> or slice. For example, an Arg::with_name() option, e.g. Arg::with_name('unknow').unknow_args() or something like this.
Maybe it could be that instead of calling get_matches() on the arg list, add a get_know_matches() that returns a tuple, the first element being what would be get_matches() and the second a vector of the unknow args... Something like Python's argparse:

args, unknown = parser.parse_known_args()
let (matches, unknow_matches) = App::new("myprog")
    .version("0.1")
    .author("You <you@example.com>")
    .about("Something about your program")
    .arg(Arg::with_name("debug")
        .short("d")
        .multiple(true)
        .help("Turn debugging information on"))
     .arg(Arg::with_name("quiet")
         .short("q")
         .long("shut-up")
         .help("Shut up"))
      .get_know_matches();

And then, if you call myprog -d --something, you have in matches the normal clap behaviour, and in unknow_matches a vector containg '--something'

I don't know if I'm explaining it well, as English is not my primary language.
EDIT: Save unknow in vector or slice instead of ignoring them

The reason for this is that i'm building a program that has "subargs" (e.g. myprogram -Xh is the message help for myprogram -X, but not the same help as myprogram -Yh or myprogram -h.) I can build this by adding -X and -Y arguments, and run another function based on which arg was used, but clap needs to know all arguments, and that's why this would be nice.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by forkbomb9
Sunday Feb 03, 2019 at 20:36 GMT


I found this: clap-rs/clap#1361 It's exactly what I was looking for... maybe we should focus on that issue.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by zkat
Sunday Dec 15, 2019 at 04:57 GMT


I could still quite use this: I want to be able to pass-through the args to a specific subcommand to a child process, ignoring all the direct args to the subcommand itself.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by cecton
Thursday Jan 30, 2020 at 14:32 GMT


It would be useful for me too

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by cecton
Thursday Jan 30, 2020 at 14:58 GMT


I just found out how to do it! I used: AppSettings::TrailingVarArg, AppSettings::AllowLeadingHyphen

I did it with structopt but you can translate to the clap equivalent.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Urhengulas
Monday Mar 29, 2021 at 20:00 GMT


Hi @CreepySkeleton, @pksunkara,

I'd be interested in implementing this, if there is some guidance in how to approach this best. My idea would be to do it very similar to AppSettings::TrailingVarArg and put all the "ignored arguments" into the final trailing positional argument.

What do you think?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Monday Mar 29, 2021 at 20:47 GMT


I don't think anything needs implementation here. As @cecton says, you can use those app settings to allow the end users to add extra arguments.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Urhengulas
Tuesday Mar 30, 2021 at 13:30 GMT


I don't think anything needs implementation here. As @cecton says, you can use those app settings to allow the end users to add extra arguments.

Hi @pksunkara, I've tried that, but this only ignores arguments "at the end", not "in the middle". Let me outline my situation:

What I want

Let's assume I have following app:

use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(short = "-L", long, parse(from_os_str))]
    library_path: Vec<PathBuf>,

    #[structopt(short, long, parse(from_os_str))]
    output: PathBuf,

    #[structopt(short = "T", long)]
    script: Vec<String>,
}

fn main() {
    let opt: Opt = Opt::from_args();
    dbg!(opt);
}

Therefore my cli can be invoked like this:

$ cli -T memory.x -o odir/ -L ldir/ -T memory2.x
[src/main.rs:29] opt = Opt {
    library_path: [
        "ldir/",
    ],
    output: "odir/",
    script: [
        "memory2.x",
        "memory.x",
    ],
}

But now I also want to allow the user to add arbitrary arguments at all positions, like this (which is the short form of this):

$ cli \
    --eh-frame-hdr \
    -flavor gnu \
    -L ldir1/ \
    file.o \
    -o odir/ \
    --gc-sections \
    -L ldir2/ \
    -L ldir3/ \
    -Tmemory.x \
    -Bdynamic

In my software I only care about -L, -T, -o, but all the other arguments should be accepted anyways, since I want to pass them through to another cli. Tbh, I don't necessarily need to capture them, but could also drop them, since currently I obtain all arguments to be passed further with fn std::env::args().

Therfore I'd like aboves invocation to result in sth like this:

[src/main.rs:29] opt = Opt {
    library_path: [
        "ldir1/",
        "ldir2/",
        "ldir3/",
    ],
    output: "dir/",
    script: [
        "memory.x",
    ],
    # `_rest` is nice to have, but actually not needed in my case
    _rest: [
        "--eh-frame-hdr",
        "-flavor",
        "gnu",
        "file.o",
        "--gc-sections",
        "-Bdynamic",
    ]
}

Why &[AppSettings::TrailingVarArg, AppSettings::AllowLeadingHyphen] doesn't work

I've tried the solution suggested above, but this didn't work for me for two reasons:

  1. It only accepts arguments added at the end, but not in the middle of the argument list
    • gets accept: cli -T memory.x -o odir/ -L ldir/ -T memory2.x -Bdynamic
    • get rejected: cli -T memory.x -Bdynamic -o odir/ -L ldir/ -T memory2.x
  2. Needed arguments after the first unknown argument don't get captured anymore
    • If I invoke the cli like this: cli -T memory.x -o odir/ -L ldir/ -T memory2.x -Bdynamic -T memory3.x, the last -T memory3.x gets not added to script, but rather _rest.

After having written all of this down it sounds like a AppSettings::IgnoreAdditionalArgs. What do you think?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Tuesday Mar 30, 2021 at 13:43 GMT


You are welcome to try implementing it but I think this would need a complete parsing logic refactor since we need to design the new logic from ground up.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Urhengulas
Tuesday Mar 30, 2021 at 15:03 GMT


You are welcome to try implementing it but I think this would need a complete parsing logic refactor since we need to design the new logic from ground up.

@pksunkara I am not familiar with the clap parsing logic, but that is what I feared.. Do you know some workaround or other crate which could help in my case by any chance?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Tuesday Mar 30, 2021 at 15:35 GMT


Implementing #1880 might help you with this. You can try researching that direction.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by cecton
Tuesday Mar 30, 2021 at 16:52 GMT


@pksunkara I am not familiar with the clap parsing logic, but that is what I feared.. Do you know some workaround or other crate which could help in my case by any chance?

You can ssk the user to provide the parameters for the inner process separately:

./my_program --my-argument --my-other-argument -- --inner-process-argument1 --inner-process-argument2

That's what -- is usually for in Unix-like command lines.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Urhengulas
Wednesday Mar 31, 2021 at 11:15 GMT


You can ssk the user to provide the parameters for the inner process separately:

./my_program --my-argument --my-other-argument -- --inner-process-argument1 --inner-process-argument2

That's what -- is usually for in Unix-like command lines.

@cecton Thank you for the tip. The problem is that I want to provide compatibility with another cli, ld to be precise (man page), and allow the user to invoke it just like they would invoke ld. Therefore I can't enforce additional usage rules.

But I only want to capture some of the arguments to do some preprocessing and then hand over all the arguments to ld.


The approach I am trying to go for now, is to preprocess the args to only include the ones i am interested in and then parse this with StructOpt::from_iter<I: IntoIterator>(iter: I).

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Urhengulas
Wednesday Mar 31, 2021 at 14:30 GMT


Implementing #1880 might help you with this. You can try researching that direction.

This feature actually looks like a possible solution for me!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant