TeXitoi / structopt

Parse command line arguments by defining a struct.
Other
2.71k stars 151 forks source link

feature: support collection of the rest of flags and options #455

Closed efikarl closed 3 years ago

efikarl commented 3 years ago

For example, I'd like to create a cmd wapper of "ipmitool":

/// Hosts management tool and ipmitool wrapper
struct Opts {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    ipmitool_args: Vec<String>,
}

I don't know if there is a way to collect all other arguments into ipmitool_args. And for example when I:

❯ ipmi.exe -b    
error: Found argument '-b' which wasn't expected, or isn't valid in this context

USAGE:
    ipmi.exe [OPTIONS] [ipmitool-args]... [SUBCOMMAND]

For more information try --help
❯

There would be a error about -b. But if there is a magical methods like accept_rest_flags_and_options

#[derive(StructOpt, Debug)]
/// Hosts management tool and ipmitool wrapper
struct Opts {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    #[structopt(accept_rest_flags_and_options)]
    ipmitool_args: Vec<String>,
}

That would be great for this case.

BR, Karl

CreepySkeleton commented 3 years ago

The closest you can get is cargo-like style:

#[derive(StructOpt, Debug)]
/// Hosts management tool and ipmitool wrapper
struct Opts {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    #[structopt(setting = ArgSettings::Last)]
    ipmitool_args: Vec<String>,
}

Invoke as

ipmi.exe -I -- -b
efikarl commented 3 years ago

The closest you can get is cargo-like style:

#[derive(StructOpt, Debug)]
/// Hosts management tool and ipmitool wrapper
struct Opts {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    #[structopt(setting = ArgSettings::Last)]
    ipmitool_args: Vec<String>,
}

Invoke as

ipmi.exe -I -- -b

Thank you very much.

efikarl commented 3 years ago

Sorry, when I add #[structopt(setting = ArgSettings::Last)]:

error[E0433]: failed to resolve: use of undeclared type `AppSettings`
  --> src\main.rs:37:27
   |
37 |     #[structopt(setting = AppSettings::Last)]
   |                           ^^^^^^^^^^^ use of undeclared type `AppSettings`

error[E0599]: no method named `setting` found for struct `Arg<'_, '_>` in the current scope
  --> src\main.rs:37:17
   |
37 |     #[structopt(setting = AppSettings::Last)]
   |                 ^^^^^^^ method not found in `Arg<'_, '_>`

error: aborting due to 2 previous errors

Crate info: name = "structopt" version = "0.3.21"

TeXitoi commented 3 years ago

structopt::clap::AppSettings::Last

efikarl commented 3 years ago

structopt::clap::AppSettings::Last

No Last in clap::AppSettings when I use structopt::clap::AppSettings::Last;.

Then I use use structopt::clap::ArgSettings;

use structopt::clap::ArgSettings;
#[derive(StructOpt, Debug)]
/// Hosts management tool and ipmitool wrapper
struct Opts {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    #[structopt(setting = ArgSettings::Last)]
    ipmitool_args: Vec<String>,
}

And the result is:

error[E0599]: no method named `setting` found for struct `Arg<'_, '_>` in the current scope
  --> src\main.rs:38:17
   |
38 |     #[structopt(setting = ArgSettings::Last)]
   |                 ^^^^^^^ method not found in `Arg<'_, '_>`

error: aborting due to previous error

So, my question is: is setting supported by structopt now?

TeXitoi commented 3 years ago

There is no such things as "structopt supports", it supports everything clap propose. The method is not setting on Arg, but set

use structopt::clap::ArgSettings;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
/// Hosts management tool and ipmitool wrapper
struct Opt {
    #[structopt(subcommand)]
    cmd: Option<Command>,

    /// Override inteface <lanplus>
    #[structopt(short = "I")]
    interface: Option<String>,

    /// The ipmitool args to process
    #[structopt(set = ArgSettings::Last)]
    ipmitool_args: Vec<String>,
}

#[derive(StructOpt, Debug)]
enum Command {
    Run,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}
TeXitoi commented 3 years ago

Also, you don't really need this ArgSettings::Last, as, if you have only one positional argument as here, it will have the same behavior without this option.

efikarl commented 3 years ago

@TeXitoi @CreepySkeleton Thank you all, it works now.

CreepySkeleton commented 3 years ago

Also, you don't really need this ArgSettings::Last, as, if you have only one positional argument as here, it will have the same behavior without this option.

True, but it won't process -b flag-like extra args. Cargo-like style is the safest option.