Skip to content

Panic with nested subcommands and tuple struct variants #76

Description

@Globidev

Consider the following derived options:

#[derive(StructOpt, Debug)]
pub enum Options {
    #[structopt(name = "daemon")]
    Damon(DaemonCommand)
}

#[derive(StructOpt, Debug)]
pub enum DaemonCommand {
    #[structopt(name = "start")]
    Start,
    #[structopt(name = "stop")]
    Stop,
}

Running an incomplete ./app daemon will result in a panic

Traceback details
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /checkout/src/libcore/option.rs:335:21
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at /checkout/src/libstd/sys_common/backtrace.rs:68
             at /checkout/src/libstd/sys_common/backtrace.rs:57
   2: std::panicking::default_hook::{{closure}}
             at /checkout/src/libstd/panicking.rs:381
   3: std::panicking::default_hook
             at /checkout/src/libstd/panicking.rs:397
   4: std::panicking::rust_panic_with_hook
             at /checkout/src/libstd/panicking.rs:577
   5: std::panicking::begin_panic
             at /checkout/src/libstd/panicking.rs:538
   6: std::panicking::begin_panic_fmt
             at /checkout/src/libstd/panicking.rs:522
   7: rust_begin_unwind
             at /checkout/src/libstd/panicking.rs:498
   8: core::panicking::panic_fmt
             at /checkout/src/libcore/panicking.rs:71
   9: core::panicking::panic
             at /checkout/src/libcore/panicking.rs:51
  10: >::unwrap
             at /checkout/src/libcore/macros.rs:20
  11: ::from_clap
             at src/cli/mod.rs:31
  12: botd::cli::Options::from_subcommand
             at src/cli/mod.rs:21
  13: ::from_clap
             at src/cli/mod.rs:21
  14: structopt::StructOpt::from_args
             at /home/guillaume/.cargo/registry/src/github.com-1ecc6299db9ec823/structopt-0.2.3/src/lib.rs:368
  15: botd::main
             at src/main.rs:35
  16: std::rt::lang_start::{{closure}}
             at /checkout/src/libstd/rt.rs:74
  17: std::panicking::try::do_call
             at /checkout/src/libstd/rt.rs:59
             at /checkout/src/libstd/panicking.rs:480
  18: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:101
  19: std::rt::lang_start_internal
             at /checkout/src/libstd/panicking.rs:459
             at /checkout/src/libstd/panic.rs:365
             at /checkout/src/libstd/rt.rs:58
  20: std::rt::lang_start
             at /checkout/src/libstd/rt.rs:74
  21: main
  22: __libc_start_main
  23: _start

However, using a struct with a named field instead of a tuple struct for the subcommand doesn't result in a panic:

pub enum Options {
    #[structopt(name = "daemon")]
    Daemon {
        #[structopt(subcommand)]
        cmd: DaemonCommand
    },
}

This time, running the incomplete ./app daemon will correctly display the subcommand usage

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis is a BUG. The fix may be released in a patch version even if considered breaking

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions