nolandda
nolandda

Reputation: 2274

How to create a StructOpt command where all subcomands are optional

I want to arrange subcommands like:

I'm unable to achieve the simple mycmd status because StructOpt believes I am missing a required subcommand (sub-subcommand?) and prints the usage. The docs indicate that I need to use the Option<> trait somehow, but I cannot figure out how in this case.

I have something very like the following:

main.rs

use structopt::StructOpt;
// ... other use cmds ...
#[derive(Debug, StructOpt)]
#[structopt(
    name = "mycmd",
    about = "A utility to do stuff."
)]
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
#[structopt(setting = structopt::clap::AppSettings::SubcommandRequired)]
struct Opts {
    #[structopt(short = "v", parse(from_occurrences))]
    /// Increase message verbosity
    verbosity: usize,
    #[structopt(subcommand)]
    cmd: Tool,
}

#[derive(Debug, StructOpt)]
enum Tool {
    #[structopt(name = "dofoo")]
    DoFoo(dofoo::Command),
    #[structopt(name = "status")]
    Status(status::Command),
}

status.rs

use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "status", about = "Get the status of stuff.")]
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
#[structopt(max_term_width = 80)]
pub enum Command {
    #[structopt(name = "full")]
    /// Print full (i.e. verbose) status
    Full {},
    #[structopt(name = "dump")]
    /// Creates a zipped dump of the full system status to a file
    Dump {
        #[structopt(short = "o", long = "out", value_name = "FILE", parse(from_os_str))]
        /// Filename of the output file.
        out_fname: PathBuf,
    },
}

impl Command {
    pub fn execute(self) -> Result<()> {
        match self {
            Command::Full {} => cmd_do_verbose_print(),
            Command::Dump { out_fname } => cmd_do_file_dump(out_fname),
            // TODO: Bad. This is dead code.
            _ => cmd_do_print(),
        }
    }
}

Upvotes: 1

Views: 837

Answers (1)

Masklinn
Masklinn

Reputation: 42492

The docs indicate that I need to use the Option<> trait somehow, but I cannot figure out how in this case.

Option is not a trait, and there's an example right there in the documentation's index at "optional subcommand".

It's just doing the same thing as your Opts but making the [structopt(subcommand)] member an Option<T> instead of a T:

    #[derive(Debug, StructOpt)]
    pub struct Command {
        #[structopt(subcommand)]
        cmd: Option<Cmd>,
    }
    #[derive(Debug, StructOpt)]
    pub enum Cmd {
        /// Print full (i.e. verbose) status
        Full {},
    ...

I have something very like the following:

An actual runnable reproduction case is useful when you have an issue...

Upvotes: 0

Related Questions