Clap: how to make an arg required conditionality?

Hi there community!

Having some issue with Clap, i'm trying to make a certain arg1 required if another arg2 has a certain value (using enum for values), and tried to use required_if_eq attribute for that arg, and it doesn't work, arg1 still can be passed with any value that is specified to arg2,

This is a code sandbox in rust playground, if you want to take a look.

You need to make arg1 optional:

#[derive(clap::Parser, Debug)]
struct Cli {
	#[arg(long , required_if_eq("arg2","val2"))]
-   arg1: bool,
+	arg1: Option<bool>,
	#[arg(long,value_enum)]
	arg2: ValueType,
}

Playground.

That helped a bit but it still not what i'm trying to achieve exactly.

I want the arg1 to be passed if and only if the value of arg2 is val2, meaning if arg2 has value of val3 (for example), arg1 it shouldn't even be specified in the command.

Doesn't that make arg1 superfluous? I.e. if arg2 equals ValueType::Val2, won't arg1 always be true and false otherwise?

It doesn't - what I think @Bylka is after is something where if arg2 is ValueType::Val2, arg1 must be either Some(true) or Some(false), while if it's anything else, arg1 must be None.

I'm just not sure how best to declare this to clap.

Probably. I'd much rather make sure though, as OP treated arg1 as a flag (automatically implied for bool arguments), which means it would always be true if arg2 equals val2 when used together with required_if_eq. Might be the playground is not what OP is actually after.

I'm pretty sure this is custom validation land. I tried combining required_if with conflicts_with but alas, conflicts_with takes precedence.

1 Like

A shot in the dark. Do you maybe want something like this:

use clap::{Parser, Subcommand};

#[derive(Subcommand, Clone, Debug, PartialEq)]
pub enum ValueType {
    Val1 {
        #[arg(long)]
        arg1: bool,
    },
    Val2,
    Val3,
}

#[derive(clap::Parser, Debug)]
struct Cli {
    #[command(subcommand)]
    cmd: ValueType,
}

fn main() {
    assert!(Cli::try_parse_from(&["progname", "val1"]).is_ok());
    assert!(Cli::try_parse_from(&["progname", "val1", "--arg1"]).is_ok());
    assert!(Cli::try_parse_from(&["progname", "val2"]).is_ok());
    assert!(Cli::try_parse_from(&["progname", "val2", "--arg1"]).is_err());
    assert!(Cli::try_parse_from(&["progname", "val3"]).is_ok());
    assert!(Cli::try_parse_from(&["progname", "val3", "--arg1"]).is_err());
}

?

Actually this is what mostly i want, since that arg1 is only attached to a special value that arg2 can take

This code do this trick, but eventually will make the ValueType a subcommand while it is an arg (not the best ux u can offer to the user).

Hi again, it is me.

So i kinda found away of achieving what i want from the case, thanks for @jofas for suggesting, custom validation land.

For that i have made this code sample in rust playground for anyone wants to achieve a similar thing, and i had put some points to consider while testing.

Thanks for everyone that helped with this.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.