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

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

Open
ehuss opened this issue Oct 8, 2019 · 5 comments
Open

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

ehuss opened this issue Oct 8, 2019 · 5 comments
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies E-hard Call for participation: Experience needed to fix: Hard / a lot S-waiting-on-mentor Status: Needs elaboration on the details before doing a 'Call for participation'

Comments

@ehuss
Copy link

ehuss commented Oct 8, 2019

Rust Version

rustc 1.38.0 (625451e37 2019-09-23)

Affected Version of clap

2.33.0 and 3.0.0-beta.1 (b881913)

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]

@CreepySkeleton CreepySkeleton added this to the 3.1 milestone Feb 1, 2020
@CreepySkeleton CreepySkeleton added C: subcommands E-hard Call for participation: Experience needed to fix: Hard / a lot E-help-wanted Call for participation: Help is requested to fix this issue. C-bug Category: Updating dependencies labels Feb 1, 2020
@yaahc
Copy link

yaahc commented Feb 4, 2020

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.

@pksunkara
Copy link
Member

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

@kamilogorek
Copy link
Contributor

Hey, is this change still in the v3 roadmap?

@pksunkara
Copy link
Member

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

@pksunkara pksunkara removed the W: 3.x label Aug 13, 2021
@epage epage added A-parsing Area: Parser's logic and needs it changed somehow. and removed C: subcommands E-help-wanted Call for participation: Help is requested to fix this issue. labels Dec 8, 2021
@epage epage removed this from the 3.1 milestone Dec 9, 2021
@epage epage added the S-waiting-on-mentor Status: Needs elaboration on the details before doing a 'Call for participation' label Dec 9, 2021
@epage
Copy link
Member

epage commented Nov 8, 2022

#3938 is a related issue for how to deal with global args appearing before and after a subcommand

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies E-hard Call for participation: Experience needed to fix: Hard / a lot S-waiting-on-mentor Status: Needs elaboration on the details before doing a 'Call for participation'
Projects
None yet
Development

No branches or pull requests

6 participants