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

Exclusive can not be used with required #3595

Closed
2 tasks done
FineFindus opened this issue Mar 31, 2022 · 1 comment · Fixed by #3690
Closed
2 tasks done

Exclusive can not be used with required #3595

FineFindus opened this issue Mar 31, 2022 · 1 comment · Fixed by #3690
Labels
A-validators Area: ArgMatches validation logi C-bug Category: Updating dependencies E-medium Call for participation: Experience needed to fix: Medium / intermediate
Milestone

Comments

@FineFindus
Copy link

Please complete the following tasks

Rust Version

rustc 1.58.1 (db9d1b20b 2022-01-20)

Clap Version

3.1.6

Minimal reproducible code

use clap::{Arg, Command};

fn main() {
    Command::new("bug")
        .arg(
            Arg::new("test")
                .long("test")
                .exclusive(true)
        )
        .arg(Arg::new("input").takes_value(true).required(true))
        .get_matches();
}

Steps to reproduce the bug with the above code

cargo run -- --test

Actual Behaviour

According to the documentation of required(), it should be overridden by conflicting rules. This should include exclusive, since it states that it conflicts with all other arguments.

Expected Behaviour

When not specifying the input argument the following error occurs:

error: The following required arguments were not provided:
    <input>

USAGE:
    bug --test <input>

For more information try --help

When specifying the required argument

cargo run -- required --test

the program will still throw an error because the exclusive argument is not exlusive.

error: The argument '--test' cannot be used with one or more of the other specified arguments

USAGE:
    bug [OPTIONS] <input>

For more information try --help

Additional Context

No response

Debug Output

Finished dev [unoptimized + debuginfo] target(s) in 0.06s
 Running `target/debug/bug --test`

[ clap::build::command] App::_do_parse
[ clap::build::command] App::_build
[ clap::build::command] App::_propagate:bug
[ clap::build::command] App::_check_help_and_version: bug
[ clap::build::command] App::_check_help_and_version: Removing generated version
[ clap::build::command] App::_propagate_global_args:bug
[ clap::build::command] App::_derive_display_order:bug
[ clap::build::debug_asserts] Command::_debug_asserts
[ clap::build::debug_asserts] Arg::_debug_asserts:help
[ clap::build::debug_asserts] Arg::_debug_asserts:test
[ clap::build::debug_asserts] Arg::_debug_asserts:input
[ clap::build::debug_asserts] Command::_verify_positionals
[ clap::parse::parser] Parser::get_matches_with
[ clap::parse::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("--test")' ([45, 45, 116, 101, 115, 116])
[ clap::parse::parser] Parser::get_matches_with: Positional counter...1
[ clap::parse::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parse::parser] Parser::possible_subcommand: arg=RawOsStr("--test")
[ clap::parse::parser] Parser::get_matches_with: sc=None
[ clap::parse::parser] Parser::parse_long_arg
[ clap::parse::parser] Parser::parse_long_arg: cur_idx:=1
[ clap::parse::parser] Parser::parse_long_arg: Does it contain '='...
[ clap::parse::parser] No
[ clap::parse::parser] Parser::parse_long_arg: Found valid opt or flag '--test'
[ clap::parse::parser] Parser::check_for_help_and_version_str
[ clap::parse::parser] Parser::check_for_help_and_version_str: Checking if --RawOsStr("test") is help or version...
[ clap::parse::parser] Neither
[ clap::parse::parser] Parser::parse_long_arg: Presence validated
[ clap::parse::parser] Parser::parse_flag
[ clap::parse::parser] Parser::remove_overrides: id=test
[ clap::parse::arg_matcher] ArgMatcher::inc_occurrence_of_arg: id=test
[ clap::build::command] App::groups_for_arg: id=test
[ clap::parse::parser] Parser::get_matches_with: After parse_long_arg ValuesDone
[ clap::parse::validator] Validator::validate
[ clap::parse::parser] Parser::add_defaults
[ clap::parse::parser] Parser::add_defaults:iter:input:
[ clap::parse::parser] Parser::add_value: doesn't have conditional defaults
[ clap::parse::parser] Parser::add_value:iter:input: doesn't have default vals
[ clap::parse::parser] Parser::add_value:iter:input: doesn't have default missing vals
[ clap::parse::validator] Validator::validate_conflicts
[ clap::parse::validator] Validator::validate_exclusive
[ clap::parse::validator] Validator::validate_exclusive:iter:test
[ clap::parse::validator] Validator::validate_conflicts::iter: id=test
[ clap::parse::validator] Conflicts::gather_conflicts
[ clap::parse::validator] Validator::validate_required: required=ChildGraph([Child { id: input, children: [] }])
[ clap::parse::validator] Validator::gather_requires
[ clap::parse::validator] Validator::gather_requires:iter:test
[ clap::parse::validator] Validator::validate_required:iter:aog=input
[ clap::parse::validator] Validator::validate_required:iter: This is an arg
[ clap::parse::validator] Validator::is_missing_required_ok: input
[ clap::parse::validator] Validator::validate_arg_conflicts: a="input"
[ clap::parse::validator] Validator::missing_required_error; incl=[]
[ clap::parse::validator] Validator::missing_required_error: reqs=ChildGraph([Child { id: input, children: [] }])
[ clap::output::usage] Usage::get_required_usage_from: incls=[], matcher=true, incl_last=true
[ clap::output::usage] Usage::get_required_usage_from: unrolled_reqs={input}
[ clap::output::usage] Usage::get_required_usage_from:iter:input
[ clap::output::usage] Usage::get_required_usage_from: ret_val=[""]
[ clap::parse::validator] Validator::missing_required_error: req_args=[
"",
]
[ clap::output::usage] Usage::create_usage_with_title
[ clap::output::usage] Usage::create_usage_no_title
[ clap::output::usage] Usage::create_smart_usage
[ clap::output::usage] Usage::get_required_usage_from: incls=[test], matcher=false, incl_last=true
[ clap::output::usage] Usage::get_required_usage_from: unrolled_reqs={input}
[ clap::output::usage] Usage::get_required_usage_from:iter:test
[ clap::output::usage] Usage::get_required_usage_from:iter:input
[ clap::output::usage] Usage::get_required_usage_from: ret_val=["--test", ""]
[ clap::build::command] App::color: Color setting...
[ clap::build::command] Auto
error: The following required arguments were not provided:

USAGE:
bug --test

For more information try --help

@FineFindus FineFindus added the C-bug Category: Updating dependencies label Mar 31, 2022
@epage epage added E-medium Call for participation: Experience needed to fix: Medium / intermediate A-validators Area: ArgMatches validation logi labels Mar 31, 2022
@epage
Copy link
Member

epage commented Mar 31, 2022

Thanks for reporting this! You are correct that exclusive is a form of a conflict and conflicts should override required.

@epage epage added this to the 3.x milestone Apr 29, 2022
epage added a commit to epage/clap that referenced this issue May 4, 2022
`Arg::exclusive` is just another way of defining conflicts, so a
present-exclusive arg should override required like other conflicts.

Instead of going through the message of enumerating all other arguments
as exclusive, I shortcutted it and special case exclusive in the
required check like we do with conflicts.  The big downside is the
implicit coupling between the code paths rather than having a consistent
abstraction for covering conflicts.

Fixes clap-rs#3595
epage added a commit to epage/clap that referenced this issue May 4, 2022
`Arg::exclusive` is just another way of defining conflicts, so a
present-exclusive arg should override required like other conflicts.

Instead of going through the message of enumerating all other arguments
as exclusive, I shortcutted it and special case exclusive in the
required check like we do with conflicts.  The big downside is the
implicit coupling between the code paths rather than having a consistent
abstraction for covering conflicts.

This isn't a breaking change because if someone defined an exclusive arg
as a sibling to a required arg, the exclusive arg could never be used,
it always errored, and so no valid application can be written with it.

Fixes clap-rs#3595
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-validators Area: ArgMatches validation logi C-bug Category: Updating dependencies E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants