-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Partially parse args, capturing unknown args into a vec, rather than error #1404
Comments
I found this: #1361 It's exactly what I was looking for... maybe we should focus on that issue. |
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. |
It would be useful for me too |
I just found out how to do it! I used: I did it with structopt but you can translate to the clap equivalent. |
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 What do you think? |
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 wantLet'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 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
|
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? |
Implementing #1880 might help you with this. You can try researching that direction. |
You can ssk the user to provide the parameters for the inner process separately:
That's what |
@cecton Thank you for the tip. The problem is that I want to provide compatibility with another cli, But I only want to capture some of the arguments to do some preprocessing and then hand over all the arguments to 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 |
This feature actually looks like a possible solution for me! |
This would also cover the pre-parsing use case in #1880 by defining a subset of arguments and using that to parse |
As mentioned in #1880, IgnoreErrors might help with some use cases |
We need to decide
Examples include We add a We add a We add a Earlier, someone brought up a
|
Has any progress been made on this issue? In As seen in that example and mentioned above |
No, no progress at this time. See the 4.x milestone for our current focus areas. |
@epage that's unfortunate, it doesn't seem part of One workaround I assume is to just get all arguments into a |
Earlier, I had posted some API design questions that first need to be resolved. Someone creating a proposal for that would be the first step. We do have |
@epage unfortunately I have a harder time than expected implementing this. Here's what I'm trying so far: https://github.com/MarijnS95/android-ndk-rs/compare/broken-trailing-args The main problem is that as soon as I add $ cargo r --release -p cargo-apk -- apk -- doc --no-deps
Finished release [optimized] target(s) in 0.03s
Running `target/release/cargo-apk apk -- doc --no-deps`
[cargo-apk/src/main.rs:104] &cargo_args = [
"--no-deps",
]
error: The following required argument was not provided: quiet
Usage: cargo-apk [OPTIONS]
For more information try '--help' EDIT: It seems that the error only continues to the next missing field ( And there are probably more things in that implementation that I can cleanup/optimize. Suggestions welcome! EDIT2: I've taken the easy route and added a |
… with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment)
To answer my own questions, I feel like treating unknown args as positionals with a setting, like what @MarijnS95 did for cargo-apk with the former The main question left for me is more about mapping this to the use case to make sure people are getting what they want. If an end-user has a bug like Is this just a given that people have to live with or is there something that can be done to improve this situation? |
I guess another question is if this new setting should capture |
Hmm, I guess another question is what to do about unknown short arguments.
|
@epage For the record, as per my message above, I have not fully been able to get this workaround to work. As for the rest, all valid questions(especially whether an argument following a flag is a positional or captured value) though I am unsure how to deal with |
I was more referring to a new setting that would apply to a multi-value positional. A question earlier was where to store the unknown arguments and a positional was a great alternative. |
@epage Sure 🙂 - just curious if you can help me out with the issue in #1404 (comment) or if I should create a new issue for that as to not derail this (much) further (it does feel of similar nature though, wrt bailing out on the first unknown argument because at that point the parser has no idea if the rest should be positionals or values for flags). Though I still intend on deferring to rust-mobile/ndk#363 because this all seems too finicky/complex. |
Sorry, I had missed that. The challenge with So long as you are using |
… with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment)
… with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment)
For completeness I got inspired by https://github.com/sonos/dinghy/blob/87463fec2df24bc01c98817b26f8b04c4ec007fa/cargo-dinghy/src/cli.rs#L108-L154 (which more so seems like an incomplete implementation of |
… with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment)
…`cargo` (#363) * cargo-apk: Reimplement "default" subcommand trailing args for `cargo` with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment) * cargo-apk: Separate unrecognized `cargo` arguments from cargo-apk `Args` With some custom logic, and assuming (validated with an `assert!`) our `Args` struct doesn't have any positionals, we can implement argument separation ourselves: this allows the user to mix and match `cargo <subcommand>` arguments with arguments recognized by `cargo-apk`, and expect `cargo-apk` to set up the environment as expected (as it did previously) by taking these arguments into account while disregarding _only_ unknown arguments. * Add `args: Args` back to `Ndk` subcommand to see them in `-h` Mixed `cargo-apk` and `cargo` args will still be split out from `cargo_args`, and they'll be appended to existing values for `args`.
…`cargo` (#363) * cargo-apk: Reimplement "default" subcommand trailing args for `cargo` with `--` separator `clap` [does not currently support] parsing unknown arguments into a side `Vec`, which is exactly what `cargo apk --` needs to parse a few known `cargo` arguments (such as `--target` and `-p`) but forward the rest verbatim to the underlying `cargo` subcommand. `allow_hyphen_values = true` could partially help us out with this, but it parses all remaining arguments into that `Vec` upon encountering the first unknown flag/arg, resulting in all known flags after that to also be treated as "unknown" instead of filling up our `args: Args` struct. Since [a workaround for this isn't currently functioning], introduce pure trailing args with an additional `--` separator to make it clear which arguments go to `cargo-apk` (and are almost all, except `--device`, forwarded to `cargo`) and which are only passed to `cargo <subcommand>`. [does not currently support]: clap-rs/clap#1404 [a workaround for this isn't currently functioning]: clap-rs/clap#1404 (comment) * cargo-apk: Separate unrecognized `cargo` arguments from cargo-apk `Args` With some custom logic, and assuming (validated with an `assert!`) our `Args` struct doesn't have any positionals, we can implement argument separation ourselves: this allows the user to mix and match `cargo <subcommand>` arguments with arguments recognized by `cargo-apk`, and expect `cargo-apk` to set up the environment as expected (as it did previously) by taking these arguments into account while disregarding _only_ unknown arguments. * Add `args: Args` back to `Ndk` subcommand to see them in `-h` Mixed `cargo-apk` and `cargo` args will still be split out from `cargo_args`, and they'll be appended to existing values for `args`.
Unfortunately this part of that workaround happens to to not be fully solid, as Likewise when values for an array (i.e. I am not sure if |
Maintainer's notes
Workaround
Command::ignore_errors
Affected Version of clap
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 aget_know_matches()
that returns a tuple, the first element being what would beget_matches()
and the second a vector of the unknow args... Something like Python'sargparse
:And then, if you call
myprog -d --something
, you have inmatches
the normal clap behaviour, and inunknow_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 formyprogram -X
, but not the same help asmyprogram -Yh
ormyprogram -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.The text was updated successfully, but these errors were encountered: