TeXitoi / structopt

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

Document external_subcommand #480

Closed tanj closed 3 years ago

tanj commented 3 years ago

I'm trying to solve a problem in pyflow where we have a subcommand that is supposed to execute a python script. I'm trying to solve a bug where you can't pass command line options to the script we are trying to run. It looks like I should use external_subcommand to do that, but I'm not seeing a way to document the supported "external" commands.

Ideally they should show up in the list of subcommands. Is there a way to do this?

TeXitoi commented 3 years ago

Sorry, but I can't help you with such a bug report. You need to be more precise: what did you try? Why it doesn't work? What do you expect?

Ideally, a minimal compiling program that do about what you want, with the explanation of what doesn't work, will allow me to understand your problem, and probably help you fixing it.

tanj commented 3 years ago
// main.rs
use structopt::StructOpt;

#[derive(Debug, PartialEq, StructOpt)]
#[structopt(name = "clitest", about = "demonstration for bug report")]
struct Opt {
    #[structopt(subcommand)]
    sub: Subcommands,
}

#[derive(Debug, PartialEq, StructOpt)]
enum Subcommands {
    /// Add subcommand
    Add,

    // `external_subcommand` tells structopt to put
    // all the extra arguments into this Vec
    /// Document for external sub commands:
    /// run  <SCRIPT> [script options]  Run the script with it's options
    #[structopt(external_subcommand)]
    Other(Vec<String>),
}

fn main() {
    let _opt = Opt::from_args();
}

Output of program.

$ ./target/debug/cli-so.exe --help
clitest 0.1.0
demonstration for bug report

USAGE:
    cli-so.exe <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    add     Add subcommand
    help    Prints this message or the help of the given subcommand(s)

I would expect it would be possible to add documentation for the external_subcommand to have it print with the help message. Ideally it would be listed with the existing SUBCOMMANDS: list

tanj commented 3 years ago

I found a way to work around this.

Adding a trailing space to the structopt name allows the documentation to be displayed and the option to never be picked up on the command line.

// main.rs
use structopt::StructOpt;

#[derive(Debug, PartialEq, StructOpt)]
#[structopt(name = "clitest", about = "demonstration for bug report")]
struct Opt {
    #[structopt(subcommand)]
    sub: Subcommands,
}

#[derive(Debug, PartialEq, StructOpt)]
enum Subcommands {
    /// Add subcommand
    Add,
    /// Fake script documentation
    #[structopt(name = "script ")]
    Script,

    // `external_subcommand` tells structopt to put
    // all the extra arguments into this Vec
    /// Document for external sub commands:
    /// run  <SCRIPT> [script options]  Run the script with it's options
    #[structopt(external_subcommand)]
    Other(Vec<String>),
}

fn main() {
    let _opt = Opt::from_args();
    eprintln!("opts: {:?}", opt);
}

Help output becomes:

$ ./target/debug/cli-so.exe --help
clitest 0.1.0
demonstration for bug report

USAGE:
    cli-so.exe <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    add        Add subcommand
    help       Prints this message or the help of the given subcommand(s)
    script     Fake script documentation

output with my external script command

 % ./target/debug/cli-so.exe script --other --args and values
opts: Opt { sub: External(["script", "--other", "--args", "and", "values"]) }
TeXitoi commented 3 years ago

I'm not sure I understand exactly what you want, but I'll do that:

use structopt::StructOpt;

#[derive(Debug, PartialEq, StructOpt)]
#[structopt(name = "clitest", about = "demonstration for bug report")]
struct Opt {
    #[structopt(subcommand)]
    sub: Subcommands,
}

#[derive(Debug, PartialEq, StructOpt)]
enum Subcommands {
    /// Add subcommand
    Add,

    /// Document for external sub commands:
    /// run  <SCRIPT> [script options]  Run the script with it's options
    #[structopt(setting = structopt::clap::AppSettings::TrailingVarArg)]
    Run { args: Vec<String> },
}

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

Closing as I can't do more, feel free to reopen and explaining what's wrong if there is still a problem.