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

Optional, nested flatten gets ignored (nested ArgGroups are unsupported) #4697

Open
2 tasks done
Tracked by #3165
jeertmans opened this issue Feb 8, 2023 · 2 comments
Open
2 tasks done
Tracked by #3165
Labels
A-derive Area: #[derive]` macro API A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-hard Call for participation: Experience needed to fix: Hard / a lot

Comments

@jeertmans
Copy link

jeertmans commented Feb 8, 2023

Please complete the following tasks

Rust Version

rustc 1.67.0-nightly (e631891f7 2022-11-13)

Clap Version

4.1.4

Minimal reproducible code

Link to the Rust Playground

/// Command that defaults to `Main` if no
/// subcommand is provided.
#[derive(Debug, Parser)]
#[clap(args_conflicts_with_subcommands = true)]
#[clap(subcommand_negates_reqs = true)]
struct MainCommand {
    /// Arguments for main command
    #[clap(flatten)]
    args: Option<Main>,
    /* comment above and uncomment next: */
    //#[clap(flatten)]
    //args: Option<LoginArgs>,

    /// Subcommand
    #[command(subcommand)]
    command: Option<Command>,
}

#[derive(Args, Clone, Debug)]
struct Main {
    #[clap(flatten)]
    login_args: LoginArgs,
    
    #[clap(long)]
    flag_main: bool,
}

#[derive(Clone, Debug, Subcommand)]
enum Command {
    Subcmd(SecondaryCommand),
}

#[derive(Args, Clone, Debug)]
struct SecondaryCommand {
    #[clap(flatten)]
    login_args: LoginArgs,
    
    #[clap(long)]
    flag_sub: bool,
}

#[derive(Args, Clone, Debug)]
struct LoginArgs {
    #[clap(short, required = true)]
    username: Option<String>,
}

fn main() {
    assert!(MainCommand::try_parse_from(["playground"]).is_err());
    
    let m = MainCommand::parse_from(["playground", "-u", "jeertmans"]);

    // When we use args: Option<Main>,
    // args is None, and should be Some
    // 
    // If we use args: Option<LoginArgs>,
    // args is Some as expected
    println!("Calling main:\n{:#?}\n", m);

    assert!(MainCommand::try_parse_from(["playground", "subcmd"]).is_err());
    
    let m = MainCommand::parse_from(["playground", "subcmd", "-u", "jeertmans"]);

    // Here, args is None as expected
    println!("Calling sub:\n{:#?}\n", m);
}

See #5435 for another variant of this problem

Steps to reproduce the bug with the above code

Simply run the code twice: first, with args: Option<Main>, and, second, with args: Option<LoginArgs>. Using the playground should be fine for testing.

Comments in the main() function explain what is expected.

The fact that args contains nested flatten seems to be the problem (?).

Actual Behaviour

Even if the arguments defined in Main are all valid, i.e., all required arguments are specified, the args field is None.

Expected Behaviour

I'd like the args field to be Some in the first case, when args: Option<Main>.

Additional Context

I am aware of #3123 and #4350, but I am not sure whether what I observe it normal or not.

Debug Output

    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/claptest`
[      clap::builder::command] 	Command::_do_parse
[      clap::builder::command] 	Command::_build: name="claptest"
[      clap::builder::command] 	Command::_propagate:claptest
[      clap::builder::command] 	Command::_check_help_and_version:claptest expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_check_help_and_version: Building help subcommand
[      clap::builder::command] 	Command::_propagate_global_args:claptest
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_main
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::add_defaults
[        clap::parser::parser] 	Parser::add_defaults:iter:username:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:username: doesn't have default vals
[        clap::parser::parser] 	Parser::add_defaults:iter:flag_main:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: has default vals
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: wasn't used
[        clap::parser::parser] 	Parser::react action=SetTrue, identifier=None, source=DefaultValue
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="flag_main", source=DefaultValue
[        clap::parser::parser] 	Parser::push_arg_values: ["false"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=1
[        clap::parser::parser] 	Parser::add_defaults:iter:help:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:help: doesn't have default vals
[     clap::parser::validator] 	Validator::validate
[     clap::parser::validator] 	Validator::validate_conflicts
[     clap::parser::validator] 	Validator::validate_exclusive
[     clap::parser::validator] 	Validator::validate_required: required=ChildGraph([Child { id: "username", children: [] }])
[     clap::parser::validator] 	Validator::gather_requires
[     clap::parser::validator] 	Validator::validate_required: is_exclusive_present=false
[     clap::parser::validator] 	Validator::validate_required:iter:aog="username"
[     clap::parser::validator] 	Validator::validate_required:iter: This is an arg
[     clap::parser::validator] 	Validator::is_missing_required_ok: username
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="username"
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="username", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="LoginArgs"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="LoginArgs", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator] 	Validator::validate_required:iter: Missing "username"
[     clap::parser::validator] 	Validator::missing_required_error; incl=["username"]
[     clap::parser::validator] 	Validator::missing_required_error: reqs=ChildGraph([Child { id: "username", children: [] }])
[         clap::output::usage] 	Usage::get_required_usage_from: incls=["username"], matcher=true, incl_last=true
[         clap::output::usage] 	Usage::get_required_usage_from: unrolled_reqs=["username"]
[         clap::output::usage] 	Usage::get_required_usage_from:iter:"username" arg is_present=false
[         clap::output::usage] 	Usage::get_required_usage_from:iter:"username" arg is_present=false
[         clap::output::usage] 	Usage::get_required_usage_from: ret_val=[StyledStr { pieces: [(Some(Literal), "-"), (Some(Literal), "u"), (Some(Placeholder), " "), (Some(Placeholder), "<USERNAME>")] }]
[     clap::parser::validator] 	Validator::missing_required_error: req_args=[
    "-u <USERNAME>",
]
[         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_args: incls=["username"]
[         clap::output::usage] 	Usage::get_args: unrolled_reqs=["username"]
[         clap::output::usage] 	Usage::get_args: ret_val=[StyledStr { pieces: [(Some(Literal), "-"), (Some(Literal), "u"), (Some(Placeholder), " "), (Some(Placeholder), "<USERNAME>")] }]
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
[      clap::builder::command] 	Command::_do_parse
[      clap::builder::command] 	Command::_build: name="claptest"
[      clap::builder::command] 	Command::_propagate:claptest
[      clap::builder::command] 	Command::_check_help_and_version:claptest expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_check_help_and_version: Building help subcommand
[      clap::builder::command] 	Command::_propagate_global_args:claptest
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_main
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("-u")' ([45, 117])
[        clap::parser::parser] 	Parser::possible_subcommand: arg=Ok("-u")
[        clap::parser::parser] 	Parser::get_matches_with: sc=None
[        clap::parser::parser] 	Parser::parse_short_arg: short_arg=ShortFlags { inner: RawOsStr("u"), utf8_prefix: CharIndices { front_offset: 0, iter: Chars(['u']) }, invalid_suffix: None }
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u: Found valid opt or flag
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u: val=RawOsStr("") (bytes), val=[] (ascii), short_arg=ShortFlags { inner: RawOsStr("u"), utf8_prefix: CharIndices { front_offset: 1, iter: Chars([]) }, invalid_suffix: None }
[        clap::parser::parser] 	Parser::parse_opt_value; arg=username, val=None, has_eq=false
[        clap::parser::parser] 	Parser::parse_opt_value; arg.settings=ArgFlags(REQUIRED)
[        clap::parser::parser] 	Parser::parse_opt_value; Checking for val...
[        clap::parser::parser] 	Parser::parse_opt_value: More arg vals required...
[        clap::parser::parser] 	Parser::get_matches_with: After parse_short_arg Opt("username")
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("jeertmans")' ([106, 101, 101, 114, 116, 109, 97, 110, 115])
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: o=username, pending=1
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: expected=1, actual=1
[        clap::parser::parser] 	Parser::resolve_pending: id="username"
[        clap::parser::parser] 	Parser::react action=Set, identifier=Some(Short), source=CommandLine
[        clap::parser::parser] 	Parser::react: cur_idx:=1
[        clap::parser::parser] 	Parser::remove_overrides: id="username"
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="username", source=CommandLine
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="LoginArgs", source=CommandLine
[        clap::parser::parser] 	Parser::push_arg_values: ["jeertmans"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=2
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: o=username, pending=0
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: expected=1, actual=0
[        clap::parser::parser] 	Parser::react not enough values passed in, leaving it to the validator to complain
[        clap::parser::parser] 	Parser::add_defaults
[        clap::parser::parser] 	Parser::add_defaults:iter:username:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:username: doesn't have default vals
[        clap::parser::parser] 	Parser::add_defaults:iter:flag_main:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: has default vals
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: wasn't used
[        clap::parser::parser] 	Parser::react action=SetTrue, identifier=None, source=DefaultValue
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="flag_main", source=DefaultValue
[        clap::parser::parser] 	Parser::push_arg_values: ["false"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=3
[        clap::parser::parser] 	Parser::add_defaults:iter:help:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:help: doesn't have default vals
[     clap::parser::validator] 	Validator::validate
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="username", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="LoginArgs", conflicts=[]
[     clap::parser::validator] 	Validator::validate_conflicts
[     clap::parser::validator] 	Validator::validate_exclusive
[     clap::parser::validator] 	Validator::validate_conflicts::iter: id="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator] 	Validator::validate_required: required=ChildGraph([Child { id: "username", children: [] }])
[     clap::parser::validator] 	Validator::gather_requires
[     clap::parser::validator] 	Validator::gather_requires:iter:"username"
[     clap::parser::validator] 	Validator::gather_requires:iter:"LoginArgs"
[     clap::parser::validator] 	Validator::gather_requires:iter:"LoginArgs":group
[     clap::parser::validator] 	Validator::validate_required: is_exclusive_present=false
[   clap::parser::arg_matcher] 	ArgMatcher::get_global_values: global_arg_vec=[]
Calling main:
MainCommand {
    args: None,
    command: None,
}

[      clap::builder::command] 	Command::_do_parse
[      clap::builder::command] 	Command::_build: name="claptest"
[      clap::builder::command] 	Command::_propagate:claptest
[      clap::builder::command] 	Command::_check_help_and_version:claptest expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_check_help_and_version: Building help subcommand
[      clap::builder::command] 	Command::_propagate_global_args:claptest
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_main
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("subcmd")' ([115, 117, 98, 99, 109, 100])
[        clap::parser::parser] 	Parser::possible_subcommand: arg=Ok("subcmd")
[        clap::parser::parser] 	Parser::get_matches_with: sc=Some("subcmd")
[        clap::parser::parser] 	Parser::parse_subcommand
[      clap::builder::command] 	Command::_build_subcommand Setting bin_name of subcmd to "playground subcmd"
[      clap::builder::command] 	Command::_build_subcommand Setting display_name of subcmd to "claptest-subcmd"
[      clap::builder::command] 	Command::_build: name="subcmd"
[      clap::builder::command] 	Command::_propagate:subcmd
[      clap::builder::command] 	Command::_check_help_and_version:subcmd expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_propagate_global_args:subcmd
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_sub
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::parse_subcommand: About to parse sc=subcmd
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::add_defaults
[        clap::parser::parser] 	Parser::add_defaults:iter:username:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:username: doesn't have default vals
[        clap::parser::parser] 	Parser::add_defaults:iter:flag_sub:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_sub: has default vals
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_sub: wasn't used
[        clap::parser::parser] 	Parser::react action=SetTrue, identifier=None, source=DefaultValue
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="flag_sub", source=DefaultValue
[        clap::parser::parser] 	Parser::push_arg_values: ["false"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=1
[        clap::parser::parser] 	Parser::add_defaults:iter:help:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:help: doesn't have default vals
[     clap::parser::validator] 	Validator::validate
[     clap::parser::validator] 	Validator::validate_conflicts
[     clap::parser::validator] 	Validator::validate_exclusive
[     clap::parser::validator] 	Validator::validate_required: required=ChildGraph([Child { id: "username", children: [] }])
[     clap::parser::validator] 	Validator::gather_requires
[     clap::parser::validator] 	Validator::validate_required: is_exclusive_present=false
[     clap::parser::validator] 	Validator::validate_required:iter:aog="username"
[     clap::parser::validator] 	Validator::validate_required:iter: This is an arg
[     clap::parser::validator] 	Validator::is_missing_required_ok: username
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="username"
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="username", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="LoginArgs"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="LoginArgs", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator] 	Validator::validate_required:iter: Missing "username"
[     clap::parser::validator] 	Validator::missing_required_error; incl=["username"]
[     clap::parser::validator] 	Validator::missing_required_error: reqs=ChildGraph([Child { id: "username", children: [] }])
[         clap::output::usage] 	Usage::get_required_usage_from: incls=["username"], matcher=true, incl_last=true
[         clap::output::usage] 	Usage::get_required_usage_from: unrolled_reqs=["username"]
[         clap::output::usage] 	Usage::get_required_usage_from:iter:"username" arg is_present=false
[         clap::output::usage] 	Usage::get_required_usage_from:iter:"username" arg is_present=false
[         clap::output::usage] 	Usage::get_required_usage_from: ret_val=[StyledStr { pieces: [(Some(Literal), "-"), (Some(Literal), "u"), (Some(Placeholder), " "), (Some(Placeholder), "<USERNAME>")] }]
[     clap::parser::validator] 	Validator::missing_required_error: req_args=[
    "-u <USERNAME>",
]
[         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_args: incls=["username"]
[         clap::output::usage] 	Usage::get_args: unrolled_reqs=["username"]
[         clap::output::usage] 	Usage::get_args: ret_val=[StyledStr { pieces: [(Some(Literal), "-"), (Some(Literal), "u"), (Some(Placeholder), " "), (Some(Placeholder), "<USERNAME>")] }]
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
[      clap::builder::command] 	Command::_do_parse
[      clap::builder::command] 	Command::_build: name="claptest"
[      clap::builder::command] 	Command::_propagate:claptest
[      clap::builder::command] 	Command::_check_help_and_version:claptest expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_check_help_and_version: Building help subcommand
[      clap::builder::command] 	Command::_propagate_global_args:claptest
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_main
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("subcmd")' ([115, 117, 98, 99, 109, 100])
[        clap::parser::parser] 	Parser::possible_subcommand: arg=Ok("subcmd")
[        clap::parser::parser] 	Parser::get_matches_with: sc=Some("subcmd")
[        clap::parser::parser] 	Parser::parse_subcommand
[      clap::builder::command] 	Command::_build_subcommand Setting bin_name of subcmd to "playground subcmd"
[      clap::builder::command] 	Command::_build_subcommand Setting display_name of subcmd to "claptest-subcmd"
[      clap::builder::command] 	Command::_build: name="subcmd"
[      clap::builder::command] 	Command::_propagate:subcmd
[      clap::builder::command] 	Command::_check_help_and_version:subcmd expand_help_tree=false
[      clap::builder::command] 	Command::long_help_exists
[      clap::builder::command] 	Command::_check_help_and_version: Building default --help
[      clap::builder::command] 	Command::_propagate_global_args:subcmd
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:username
[clap::builder::debug_asserts] 	Arg::_debug_asserts:flag_sub
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[        clap::parser::parser] 	Parser::parse_subcommand: About to parse sc=subcmd
[        clap::parser::parser] 	Parser::get_matches_with
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("-u")' ([45, 117])
[        clap::parser::parser] 	Parser::possible_subcommand: arg=Ok("-u")
[        clap::parser::parser] 	Parser::get_matches_with: sc=None
[        clap::parser::parser] 	Parser::parse_short_arg: short_arg=ShortFlags { inner: RawOsStr("u"), utf8_prefix: CharIndices { front_offset: 0, iter: Chars(['u']) }, invalid_suffix: None }
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u: Found valid opt or flag
[        clap::parser::parser] 	Parser::parse_short_arg:iter:u: val=RawOsStr("") (bytes), val=[] (ascii), short_arg=ShortFlags { inner: RawOsStr("u"), utf8_prefix: CharIndices { front_offset: 1, iter: Chars([]) }, invalid_suffix: None }
[        clap::parser::parser] 	Parser::parse_opt_value; arg=username, val=None, has_eq=false
[        clap::parser::parser] 	Parser::parse_opt_value; arg.settings=ArgFlags(REQUIRED)
[        clap::parser::parser] 	Parser::parse_opt_value; Checking for val...
[        clap::parser::parser] 	Parser::parse_opt_value: More arg vals required...
[        clap::parser::parser] 	Parser::get_matches_with: After parse_short_arg Opt("username")
[        clap::parser::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("jeertmans")' ([106, 101, 101, 114, 116, 109, 97, 110, 115])
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: o=username, pending=1
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: expected=1, actual=1
[        clap::parser::parser] 	Parser::resolve_pending: id="username"
[        clap::parser::parser] 	Parser::react action=Set, identifier=Some(Short), source=CommandLine
[        clap::parser::parser] 	Parser::react: cur_idx:=1
[        clap::parser::parser] 	Parser::remove_overrides: id="username"
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="username", source=CommandLine
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="LoginArgs", source=CommandLine
[        clap::parser::parser] 	Parser::push_arg_values: ["jeertmans"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=2
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: o=username, pending=0
[   clap::parser::arg_matcher] 	ArgMatcher::needs_more_vals: expected=1, actual=0
[        clap::parser::parser] 	Parser::react not enough values passed in, leaving it to the validator to complain
[        clap::parser::parser] 	Parser::add_defaults
[        clap::parser::parser] 	Parser::add_defaults:iter:username:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:username: doesn't have default vals
[        clap::parser::parser] 	Parser::add_defaults:iter:flag_sub:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_sub: has default vals
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_sub: wasn't used
[        clap::parser::parser] 	Parser::react action=SetTrue, identifier=None, source=DefaultValue
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="flag_sub", source=DefaultValue
[        clap::parser::parser] 	Parser::push_arg_values: ["false"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=3
[        clap::parser::parser] 	Parser::add_defaults:iter:help:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:help: doesn't have default vals
[     clap::parser::validator] 	Validator::validate
[      clap::builder::command] 	Command::groups_for_arg: id="username"
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="username", conflicts=[]
[     clap::parser::validator] 	Conflicts::gather_direct_conflicts id="LoginArgs", conflicts=[]
[     clap::parser::validator] 	Validator::validate_conflicts
[     clap::parser::validator] 	Validator::validate_exclusive
[     clap::parser::validator] 	Validator::validate_conflicts::iter: id="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: arg="username"
[     clap::parser::validator] 	Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator] 	Validator::validate_required: required=ChildGraph([Child { id: "username", children: [] }])
[     clap::parser::validator] 	Validator::gather_requires
[     clap::parser::validator] 	Validator::gather_requires:iter:"username"
[     clap::parser::validator] 	Validator::gather_requires:iter:"LoginArgs"
[     clap::parser::validator] 	Validator::gather_requires:iter:"LoginArgs":group
[     clap::parser::validator] 	Validator::validate_required: is_exclusive_present=false
[        clap::parser::parser] 	Parser::add_defaults
[        clap::parser::parser] 	Parser::add_defaults:iter:username:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:username: doesn't have default vals
[        clap::parser::parser] 	Parser::add_defaults:iter:flag_main:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: has default vals
[        clap::parser::parser] 	Parser::add_default_value:iter:flag_main: wasn't used
[        clap::parser::parser] 	Parser::react action=SetTrue, identifier=None, source=DefaultValue
[   clap::parser::arg_matcher] 	ArgMatcher::start_custom_arg: id="flag_main", source=DefaultValue
[        clap::parser::parser] 	Parser::push_arg_values: ["false"]
[        clap::parser::parser] 	Parser::add_single_val_to_arg: cur_idx:=1
[        clap::parser::parser] 	Parser::add_defaults:iter:help:
[        clap::parser::parser] 	Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser] 	Parser::add_default_value:iter:help: doesn't have default vals
[     clap::parser::validator] 	Validator::validate
[     clap::parser::validator] 	Validator::validate_conflicts
[     clap::parser::validator] 	Validator::validate_exclusive
[   clap::parser::arg_matcher] 	ArgMatcher::get_global_values: global_arg_vec=[]
Calling sub:
MainCommand {
    args: None,
    command: Some(
        Subcmd(
            SecondaryCommand {
                login_args: LoginArgs {
                    username: Some(
                        "jeertmans",
                    ),
                },
                flag_sub: false,
            },
        ),
    ),
}
@jeertmans jeertmans added the C-bug Category: Updating dependencies label Feb 8, 2023
@epage epage changed the title bug(derive): option of nested flatten does not work as expected Option of nested flatten does not work as expected Feb 8, 2023
@epage epage added E-hard Call for participation: Experience needed to fix: Hard / a lot A-parsing Area: Parser's logic and needs it changed somehow. labels Feb 8, 2023
@epage
Copy link
Member

epage commented Feb 8, 2023

This was previously a task list item in #3165, so I've updated it to point to this issue

@epage epage added C-enhancement Category: Raise on the bar on expectations A-derive Area: #[derive]` macro API and removed C-bug Category: Updating dependencies labels Feb 8, 2023
@epage epage changed the title Option of nested flatten does not work as expected Optional, nested flatten gets ignored (nested ArgGroups are unsupported) Feb 8, 2023
@jeertmans
Copy link
Author

Thanks for the update! I don't think I know Clap well enough to help with #3165, but I hope someone will :D

indygreg added a commit to indygreg/apple-platform-rs that referenced this issue Nov 16, 2023
…ning ones

The multiple levels of nesting combined with Option<T> were conspiring
to prevent CLI arguments from getting processed. I believe this is
clap-rs/clap#4697 but am not 100% sure.

We mitigate the problem by moving the session initialization fields
into the main key struct so we have a single level of argument nesting.

As part of this we remote `--remote-signer` and instead infer remote
signing from presence of a session initialization argument.

We also make the server URL optional to prevent the struct from having
any populated fields by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-derive Area: #[derive]` macro API A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-hard Call for participation: Experience needed to fix: Hard / a lot
Projects
None yet
Development

No branches or pull requests

2 participants