Skip to content
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

subcommands are all or nothing, allow hybrid #20

Closed
m4b opened this issue Jul 31, 2017 · 1 comment
Closed

subcommands are all or nothing, allow hybrid #20

m4b opened this issue Jul 31, 2017 · 1 comment
Labels

Comments

@m4b
Copy link

m4b commented Jul 31, 2017

Basically, I want to be able to integrate subcommands into an existing CLI framework, without forcing the original commands to now be under a subcommand.

Afaics (please correct me if I'm wrong, or add an appropriate example), structopt forces the user to either use regular command line with no subcommands, or all only subcommands.

E.g. something like this (do not take this as a suggestion for syntax, or a functioning example, etc.):

#[derive(StructOpt, Debug)]
#[structopt(name = "derp")]
enum Fetch {
    #[structopt(name = "fetch")]
    /// fetch branches from remote repository
    Fetch {
        #[structopt(long = "dry-run")]
        dry_run: bool,
        #[structopt(long = "all")]
        all: bool,
        #[structopt(default_value = "origin")]
        repository: String
    },
}

#[derive(StructOpt, Debug)]
#[structopt(name = "derp", about = "merp a lerp")]
struct Args {
    /// The specific function address to disassemble
    #[structopt(short = "a", long = "address", help = "Disassemble the function at the given address")]
    address_filter: Option<String>,
    /// The binary to disassemble
    #[structopt(help = "The binary to disassemble")]
    binary: String,
    fetch: Fetch
}

which would work via the following invocations:

derp fetch --all <repo>
derp --address <binary>
derp <binary>

E.g., I can add subcommands in gradually to an existing framework; or, perhaps subcommands are rarely used, but a good separation of tasks in the tool when they are used, so an explicit subcommand is nice, but otherwise the other command line arguments without any subcommand also work.

Another way of putting it, is basically how cargo works right now; it technically has a mixture of subcommands and "raw" non-subcommand commands, like --color or --explain.

So is something like this possible?

@TeXitoi
Copy link
Owner

TeXitoi commented Jul 31, 2017

Use an option on the subcommand:

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
enum SubCommand {
    #[structopt(name = "fetch")]
    /// fetch branches from remote repository
    Fetch {
        #[structopt(long = "dry-run")]
        dry_run: bool,
        #[structopt(long = "all")]
        all: bool,
        #[structopt(default_value = "origin")]
        repository: String
    },
}

#[derive(StructOpt, Debug)]
struct Opt {
    /// Disassemble the function at the given address
    #[structopt(short = "a", long = "address")]
    address_filter: Option<String>,
    /// The binary to disassemble
    binary: Option<String>,
    #[structopt(subcommand)]
    subcommand: Option<SubCommand>,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}
$ ./target/debug/test-rs -h
test-rs 0.0.1
Guillaume Pinot <[email protected]>


USAGE:
    test-rs [OPTIONS] [binary] [SUBCOMMAND]

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

OPTIONS:
    -a, --address <address_filter>    Disassemble the function at the given address

ARGS:
    <binary>    The binary to disassemble

SUBCOMMANDS:
    fetch    fetch branches from remote repository
    help     Prints this message or the help of the given subcommand(s)
$ ./target/debug/test-rs 
Opt { address_filter: None, binary: None, subcommand: None }
$ ./target/debug/test-rs fetch --all repo
Opt { address_filter: None, binary: None, subcommand: Some(Fetch { dry_run: false, all: true, repository: "repo" }) }
$ ./target/debug/test-rs --address binary
Opt { address_filter: Some("binary"), binary: None, subcommand: None }
$ ./target/debug/test-rs binary
Opt { address_filter: None, binary: Some("binary"), subcommand: None }

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

No branches or pull requests

2 participants