Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

global opts that take a value cannot be mixed with subcommand #128

Open
epage opened this issue Dec 6, 2021 · 4 comments
Open

global opts that take a value cannot be mixed with subcommand #128

epage opened this issue Dec 6, 2021 · 4 comments

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by ehuss
Tuesday Oct 08, 2019 at 18:28 GMT
Originally opened as clap-rs/clap#1570


Rust Version

rustc 1.38.0 (625451e37 2019-09-23)

Affected Version of clap

2.33.0 and 3.0.0-beta.1 (b8819130de876c4abbd451c34df89161a98d23ef)

Expected Behavior Summary

When a global option that takes a value is used both before and after a subcommand, I would expect that values_of would return all the values.

Actual Behavior Summary

It only returns the values from the subcommand. Flags before the subcommand are ignored.

Note: For global flags that do not take a value, occurrences_of correctly returns the count of all occurrences both before and after.

Sample Code or Link to Sample Code

use clap::{App, Arg};

fn main() {
    let matches = App::new("myapp")
        .arg(
            Arg::with_name("global-opt")
                .short('A')
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommand(App::new("test"))
        .get_matches_from(vec!["myapp", "-Aone", "test", "-Atwo"]);

    let gs = matches.values_of("global-opt").unwrap().collect::<Vec<_>>();
    // I would expect this to be ["one", "two"]
    assert_eq!(gs, vec!["two"]);
}

Debug output

Debug Output

DEBUG:clap:App::_do_parse;
DEBUG:clap:App::_build;
DEBUG:clap:App::_derive_display_order:myapp
DEBUG:clap:App::_derive_display_order:test
DEBUG:clap:App::_create_help_and_version;
DEBUG:clap:App::_create_help_and_version: Building --help
DEBUG:clap:App::_create_help_and_version: Building --version
DEBUG:clap:App::_create_help_and_version: Building help
DEBUG:clap:App::_arg_debug_asserts:global-opt
DEBUG:clap:App::_arg_debug_asserts:help
DEBUG:clap:App::_arg_debug_asserts:version
DEBUG:clap:App::_app_debug_asserts;
DEBUG:clap:Parser::get_matches_with;
DEBUG:clap:Parser::_build;
DEBUG:clap:Parser::_verify_positionals;
DEBUG:clap:Parser::get_matches_with: Begin parsing '"-Aone"' ([45, 65, 111, 110, 101])
DEBUG:clap:Parser::is_new_arg:"-Aone":NotFound
DEBUG:clap:Parser::is_new_arg: arg_allows_tac=false
DEBUG:clap:Parser::is_new_arg: - found
DEBUG:clap:Parser::is_new_arg: starts_new_arg=true
DEBUG:clap:Parser::possible_subcommand: arg="-Aone"
DEBUG:clap:Parser::get_matches_with: possible_sc=false, sc=None
DEBUG:clap:Parser::parse_short_arg: full_arg="-Aone"
DEBUG:clap:Parser::parse_short_arg:iter:A
DEBUG:clap:Parser::parse_short_arg:iter:A: Found valid opt or flag
DEBUG:clap:Parser::parse_short_arg:iter:A: p[0]=[], p[1]=[111, 110, 101]
DEBUG:clap:Parser::parse_short_arg:iter:A: val=[111, 110, 101] (bytes), val="one" (ascii)
DEBUG:clap:Parser::parse_opt; opt=global-opt, val=Some("one")
DEBUG:clap:Parser::parse_opt; opt.settings=ArgFlags(MULTIPLE_OCC | TAKES_VAL | DELIM_NOT_SET | MULTIPLE_VALS)
DEBUG:clap:Parser::parse_opt; Checking for val...Found - "one", len: 3
DEBUG:clap:Parser::parse_opt: "one" contains '='...false
DEBUG:clap:Parser::add_val_to_arg; arg=global-opt, val="one"
DEBUG:clap:Parser::add_val_to_arg; trailing_vals=false, DontDelimTrailingVals=false
DEBUG:clap:Parser::add_single_val_to_arg;
DEBUG:clap:Parser::add_single_val_to_arg: adding val..."one"
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:ArgMatcher::needs_more_vals: o=global-opt
DEBUG:clap:ArgMatcher::needs_more_vals: num_vals...1
DEBUG:clap:ArgMatcher::inc_occurrence_of: arg=4551335407501243259
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:ArgMatcher::needs_more_vals: o=global-opt
DEBUG:clap:ArgMatcher::needs_more_vals: num_vals...1
DEBUG:clap:Parser::parse_opt: More arg vals not required...
DEBUG:clap:Parser:get_matches_with: After parse_short_arg ValuesDone
DEBUG:clap:Parser::get_matches_with: Begin parsing '"test"' ([116, 101, 115, 116])
DEBUG:clap:Parser::is_new_arg:"test":ValuesDone
DEBUG:clap:Parser::possible_subcommand: arg="test"
DEBUG:clap:Parser::get_matches_with: possible_sc=true, sc=Some("test")
DEBUG:clap:Parser::parse_subcommand;
DEBUG:clap:Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
DEBUG:clap:Usage::get_required_usage_from: ret_val=[]
DEBUG:clap:App::_propagate:myapp
DEBUG:clap:App::_build;
DEBUG:clap:App::_derive_display_order:test
DEBUG:clap:App::_create_help_and_version;
DEBUG:clap:App::_create_help_and_version: Building --help
DEBUG:clap:App::_create_help_and_version: Building --version
DEBUG:clap:App::_arg_debug_asserts:global-opt
DEBUG:clap:App::_arg_debug_asserts:help
DEBUG:clap:App::_arg_debug_asserts:version
DEBUG:clap:App::_app_debug_asserts;
DEBUG:clap:Parser::parse_subcommand: About to parse sc=test
DEBUG:clap:Parser::get_matches_with;
DEBUG:clap:Parser::_build;
DEBUG:clap:Parser::_verify_positionals;
DEBUG:clap:Parser::get_matches_with: Begin parsing '"-Atwo"' ([45, 65, 116, 119, 111])
DEBUG:clap:Parser::is_new_arg:"-Atwo":NotFound
DEBUG:clap:Parser::is_new_arg: arg_allows_tac=false
DEBUG:clap:Parser::is_new_arg: - found
DEBUG:clap:Parser::is_new_arg: starts_new_arg=true
DEBUG:clap:Parser::possible_subcommand: arg="-Atwo"
DEBUG:clap:Parser::get_matches_with: possible_sc=false, sc=None
DEBUG:clap:Parser::parse_short_arg: full_arg="-Atwo"
DEBUG:clap:Parser::parse_short_arg:iter:A
DEBUG:clap:Parser::parse_short_arg:iter:A: Found valid opt or flag
DEBUG:clap:Parser::parse_short_arg:iter:A: p[0]=[], p[1]=[116, 119, 111]
DEBUG:clap:Parser::parse_short_arg:iter:A: val=[116, 119, 111] (bytes), val="two" (ascii)
DEBUG:clap:Parser::parse_opt; opt=global-opt, val=Some("two")
DEBUG:clap:Parser::parse_opt; opt.settings=ArgFlags(MULTIPLE_OCC | TAKES_VAL | DELIM_NOT_SET | MULTIPLE_VALS)
DEBUG:clap:Parser::parse_opt; Checking for val...Found - "two", len: 3
DEBUG:clap:Parser::parse_opt: "two" contains '='...false
DEBUG:clap:Parser::add_val_to_arg; arg=global-opt, val="two"
DEBUG:clap:Parser::add_val_to_arg; trailing_vals=false, DontDelimTrailingVals=false
DEBUG:clap:Parser::add_single_val_to_arg;
DEBUG:clap:Parser::add_single_val_to_arg: adding val..."two"
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:ArgMatcher::needs_more_vals: o=global-opt
DEBUG:clap:ArgMatcher::needs_more_vals: num_vals...1
DEBUG:clap:ArgMatcher::inc_occurrence_of: arg=4551335407501243259
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:ArgMatcher::needs_more_vals: o=global-opt
DEBUG:clap:ArgMatcher::needs_more_vals: num_vals...1
DEBUG:clap:Parser::parse_opt: More arg vals not required...
DEBUG:clap:Parser:get_matches_with: After parse_short_arg ValuesDone
DEBUG:clap:Parser::remove_overrides;
DEBUG:clap:Parser::remove_overrides:iter:4551335407501243259;
DEBUG:clap:Validator::validate;
DEBUG:clap:Parser::add_defaults;
DEBUG:clap:Parser::add_defaults:iter:global-opt: doesn't have conditional defaults
DEBUG:clap:Parser::add_defaults:iter:global-opt: doesn't have default vals
DEBUG:clap:Validator::validate_conflicts;
DEBUG:clap:Validator::gather_conflicts;
DEBUG:clap:Validator::gather_conflicts:iter:4551335407501243259;
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:Validator::validate_required: required=ChildGraph([]);
DEBUG:clap:Validator::gather_requirements;
DEBUG:clap:Validator::gather_requirements:iter:4551335407501243259;
DEBUG:clap:Validator::validate_required_unless;
DEBUG:clap:Validator::validate_matched_args;
DEBUG:clap:Validator::validate_matched_args:iter:4551335407501243259: vals=[
    "two",
]
DEBUG:clap:Validator::validate_arg_num_vals;
DEBUG:clap:Validator::validate_arg_num_vals: num_vals set...1
DEBUG:clap:Validator::validate_arg_values: arg="global-opt"
DEBUG:clap:Validator::validate_arg_requires:global-opt;
DEBUG:clap:Validator::validate_arg_num_occurs: global-opt=1;
DEBUG:clap:Parser::remove_overrides;
DEBUG:clap:Parser::remove_overrides:iter:4551335407501243259;
DEBUG:clap:Validator::validate;
DEBUG:clap:Parser::add_defaults;
DEBUG:clap:Parser::add_defaults:iter:global-opt: doesn't have conditional defaults
DEBUG:clap:Parser::add_defaults:iter:global-opt: doesn't have default vals
DEBUG:clap:Validator::validate_conflicts;
DEBUG:clap:Validator::gather_conflicts;
DEBUG:clap:Validator::gather_conflicts:iter:4551335407501243259;
DEBUG:clap:Parser::groups_for_arg: name=4551335407501243259
DEBUG:clap:Validator::validate_required: required=ChildGraph([]);
DEBUG:clap:Validator::gather_requirements;
DEBUG:clap:Validator::gather_requirements:iter:4551335407501243259;
DEBUG:clap:Validator::validate_required_unless;
DEBUG:clap:Validator::validate_matched_args;
DEBUG:clap:Validator::validate_matched_args:iter:4551335407501243259: vals=[
    "one",
]
DEBUG:clap:Validator::validate_arg_num_vals;
DEBUG:clap:Validator::validate_arg_num_vals: num_vals set...1
DEBUG:clap:Validator::validate_arg_values: arg="global-opt"
DEBUG:clap:Validator::validate_arg_requires:global-opt;
DEBUG:clap:Validator::validate_arg_num_occurs: global-opt=1;
DEBUG:clap:ArgMatcher::get_global_values: global_arg_vec=[4551335407501243259]

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by yaahc
Tuesday Feb 04, 2020 at 23:56 GMT


not sure if this is the same issue or a different issue but I'm seeing something similar where a global arg isn't propogating to the ArgMatches.subcommand() matches properly

use clap::{App, Arg};

fn main() {
    let matches = App::new("myapp")
        .subcommand(
            App::new("test")
                .arg(
                    Arg::with_name("global-opt")
                        .number_of_values(1)
                        .short('A')
                        .global(true),
                )
                .subcommand(App::new("testt")),
        )
        .get_matches_from(vec!["myapp", "test", "testt", "-Aone"]);

    let gs = matches.value_of("global-opt");
    assert_eq!(gs, Some("one"));
}

The assert_eq here fails.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Wednesday Feb 05, 2020 at 07:54 GMT


It is the same issue. Thanks for the reports guys. Unfortunately we won't get to fix this until 3.0 is out.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by kamilogorek
Wednesday Apr 21, 2021 at 13:16 GMT


Hey, is this change still in the v3 roadmap?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Wednesday Apr 21, 2021 at 14:37 GMT


If you look at the milestone. It's not scheduled for v3 release. But afterwards.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant