StructOpt: How to use subcommand enum's fields in clap::arg attribute methods?

1.2k Views Asked by At

I have the following setup:

use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct CliArgs {
    #[structopt(short, long)]
    aisle: Option<String>,

    #[structopt(short, long)]
    shelf: Option<String>,

    #[structopt(subcommand)]
    operation: Option<Ops>,
}

#[derive(Debug, StructOpt)]
enum Ops {
    Add {
        isbn: Option<String>,
        pin: Option<String>
    },
    Remove {
        isbn: Option<String>,
    },
    Status,
}

In this scenario, I'd like a condition where either aisle and shelf are together specified or isbn alone is specified. I found both raw clap methods required_unless and conflicts_with, and their variants required_unless_all and conflicts_with_all together could be of use.

Maybe using them like such:

...
    #[structopt(short, long, required_unless = "isbn", conflicts_with = "isbn")]
    aisle: Option<String>,

    #[structopt(short, long, required_unless = "isbn", conflicts_with = "isbn")]
    shelf: Option<String>,
...

and

...
    Add {
        #[structopt(required_unless_all = &["aisle", "shelf"], conflicts_with_all = &["aisle", "shelf"])]
        isbn: Option<String>,
        pin: Option<String>
    }
...

But it results in the following

~❯ RUST_BACKTRACE=full cargo run -q -- --aisle A1 --shelf X3 add 2441 
error: The following required arguments were not provided:
    <pin>

Which is right because passed pin is used as isbn instead.

~❯ RUST_BACKTRACE=full cargo run -q -- add A1/X3 2441 
error: The following required arguments were not provided:
    --aisle <aisle>
    --shelf <shelf>
~❯ RUST_BACKTRACE=full cargo run -q -- --aisle B1 --shelf Y3 add A1/X3 2441 
<It works>
~❯ RUST_BACKTRACE=full cargo run -q -- add 
error: The following required arguments were not provided:
    <isbn>
    <pin>

Which doesn't work for obvious reasons. I think the main issue with my problem is that the fields can't reference each other if put under a sub-command. Am I doing something wrong with the current approach? Would there be a better alternative to clap::arg methods in this case? Or is there a way of communicating between sub-commands?

0

There are 0 best solutions below