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

generate_help for a subcommand doesn't include the bin_name #4685

Closed
not-my-profile opened this issue Jan 30, 2023 · 5 comments
Closed

generate_help for a subcommand doesn't include the bin_name #4685

not-my-profile opened this issue Jan 30, 2023 · 5 comments
Labels
C-bug Category: Updating dependencies

Comments

@not-my-profile
Copy link
Contributor

not-my-profile commented Jan 30, 2023

use clap::CommandFactory;
use clap::Parser;

#[derive(clap::Parser, Debug)]
#[command(bin_name = "main-command")]
struct Args {
    #[command(subcommand)]
    cmd: Command,
}

#[derive(Debug, clap::Subcommand)]
enum Command {
    Subcommand,
}

fn main() {
    println!(
        "### generate_help reports:\n{}",
        Args::command()
            .get_subcommands()
            .next()
            .unwrap()
            .clone()
            .render_help()
    );
    println!("### Args::parse() prints:\n");
    let args = Args::parse();
}

When running the above code with cargo run help subcommand, you get the following output:

### generate_help reports:
Usage: subcommand

Options:
  -h, --help  Print help

### Args::parse() prints:

Usage: main-command subcommand

Options:
  -h, --help  Print help

Notice how the Usage: line generated by generate_help does not include the name (bin_name) of the main command (main-command).

I would expect the output of generate_help to match the output of the actual help clap prints when parsing arguments.

Versions

  • rustc 1.65.0 (897e37553 2022-11-02)
  • clap v4.1.4

Debug Output

Debug output
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/foo help subcommand`
[      clap::builder::command] 	Command::_build: name="subcommand"
[      clap::builder::command] 	Command::_propagate:subcommand
[      clap::builder::command] 	Command::_check_help_and_version:subcommand 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:subcommand
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[          clap::output::help] 	write_help
[ clap::output::help_template] 	HelpTemplate::new cmd=subcommand, use_long=false
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_templated_help
[ clap::output::help_template] 	HelpTemplate::write_before_help
[         clap::output::usage] 	Usage::create_usage_no_title
[         clap::output::usage] 	Usage::create_help_usage; incl_reqs=true
[         clap::output::usage] 	Usage::needs_options_tag
[         clap::output::usage] 	Usage::needs_options_tag:iter: f=help
[         clap::output::usage] 	Usage::needs_options_tag:iter Option is built-in
[         clap::output::usage] 	Usage::needs_options_tag: [OPTIONS] not required
[         clap::output::usage] 	Usage::get_args: incls=[]
[         clap::output::usage] 	Usage::get_args: unrolled_reqs=[]
[         clap::output::usage] 	Usage::get_args: ret_val=[]
[         clap::output::usage] 	Usage::create_help_usage: usage=subcommand
[ clap::output::help_template] 	HelpTemplate::write_all_args
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_args Options
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_args: arg="help" longest=6
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::spec_vals: a=--help
[ clap::output::help_template] 	HelpTemplate::spec_vals: a=--help
[ clap::output::help_template] 	HelpTemplate::short
[ clap::output::help_template] 	HelpTemplate::long
[ clap::output::help_template] 	HelpTemplate::align_to_about: arg=help, next_line_help=false, longest=6
[ clap::output::help_template] 	HelpTemplate::align_to_about: positional=false arg_len=6, spaces=2
[ clap::output::help_template] 	HelpTemplate::help
[ clap::output::help_template] 	HelpTemplate::help: help_width=14, spaces=10, avail=86
[ clap::output::help_template] 	HelpTemplate::write_after_help
### generate_help reports:
Usage: subcommand

Options:
  -h, --help  Print help

### Args::parse() prints:

[      clap::builder::command] 	Command::_do_parse
[      clap::builder::command] 	Command::_build: name="foo"
[      clap::builder::command] 	Command::_propagate:foo
[      clap::builder::command] 	Command::_check_help_and_version:foo 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:foo
[clap::builder::debug_asserts] 	Command::_debug_asserts
[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("help")' ([104, 101, 108, 112])
[        clap::parser::parser] 	Parser::possible_subcommand: arg=Ok("help")
[        clap::parser::parser] 	Parser::get_matches_with: sc=Some("help")
[        clap::parser::parser] 	Parser::parse_help_subcommand
[         clap::output::usage] 	Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[         clap::output::usage] 	Usage::get_required_usage_from: unrolled_reqs=[]
[         clap::output::usage] 	Usage::get_required_usage_from: ret_val=[]
[      clap::builder::command] 	Command::_build_subcommand Setting bin_name of subcommand to "main-command subcommand"
[      clap::builder::command] 	Command::_build_subcommand Setting display_name of subcommand to "foo-subcommand"
[      clap::builder::command] 	Command::_build: name="subcommand"
[      clap::builder::command] 	Command::_propagate:subcommand
[      clap::builder::command] 	Command::_check_help_and_version:subcommand 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:subcommand
[clap::builder::debug_asserts] 	Command::_debug_asserts
[clap::builder::debug_asserts] 	Arg::_debug_asserts:help
[clap::builder::debug_asserts] 	Command::_verify_positionals
[      clap::builder::command] 	Command::long_help_exists: false
[      clap::builder::command] 	Command::write_help_err: foo-subcommand, use_long=false
[      clap::builder::command] 	Command::long_help_exists: false
[          clap::output::help] 	write_help
[ clap::output::help_template] 	HelpTemplate::new cmd=subcommand, use_long=false
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_templated_help
[ clap::output::help_template] 	HelpTemplate::write_before_help
[         clap::output::usage] 	Usage::create_usage_no_title
[         clap::output::usage] 	Usage::create_help_usage; incl_reqs=true
[         clap::output::usage] 	Usage::needs_options_tag
[         clap::output::usage] 	Usage::needs_options_tag:iter: f=help
[         clap::output::usage] 	Usage::needs_options_tag:iter Option is built-in
[         clap::output::usage] 	Usage::needs_options_tag: [OPTIONS] not required
[         clap::output::usage] 	Usage::get_args: incls=[]
[         clap::output::usage] 	Usage::get_args: unrolled_reqs=[]
[         clap::output::usage] 	Usage::get_args: ret_val=[]
[         clap::output::usage] 	Usage::create_help_usage: usage=main-command subcommand
[ clap::output::help_template] 	HelpTemplate::write_all_args
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_args Options
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::write_args: arg="help" longest=6
[ clap::output::help_template] 	should_show_arg: use_long=false, arg=help
[ clap::output::help_template] 	HelpTemplate::spec_vals: a=--help
[ clap::output::help_template] 	HelpTemplate::spec_vals: a=--help
[ clap::output::help_template] 	HelpTemplate::short
[ clap::output::help_template] 	HelpTemplate::long
[ clap::output::help_template] 	HelpTemplate::align_to_about: arg=help, next_line_help=false, longest=6
[ clap::output::help_template] 	HelpTemplate::align_to_about: positional=false arg_len=6, spaces=2
[ clap::output::help_template] 	HelpTemplate::help
[ clap::output::help_template] 	HelpTemplate::help: help_width=14, spaces=10, avail=86
[ clap::output::help_template] 	HelpTemplate::write_after_help
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
[      clap::builder::command] 	Command::color: Color setting...
[      clap::builder::command] 	Auto
Usage: main-command subcommand

Options:
  -h, --help  Print help
@epage
Copy link
Member

epage commented Jan 30, 2023

You need to call cmd.build() first. The usage is the most obvious problem; without build a lot of other things might be incorrect

@epage
Copy link
Member

epage commented Jan 30, 2023

To clarify,

let mut cmd = Args::command();
cmd.build();
...

We call build for the individual subcommand but you need to call build on the top-level command.

We should be at least calling this out in the docs. We might want to change the implicit build to an assert to make this more obvious.

@epage
Copy link
Member

epage commented Jan 31, 2023

I'm assuming that has resolved things for you. If not, let us know!

@epage epage closed this as not planned Won't fix, can't repro, duplicate, stale Jan 31, 2023
@not-my-profile
Copy link
Contributor Author

Yes, thanks! This indeed worked :)

I think ideally such methods would only be callable after invoking build, using the builder pattern, i.e. build would return another type where the methods are available ... in order to get the build-time safety Rust is famous for. But I assume this would be a bit cumbersome to implement since it would be a breaking change?

@epage
Copy link
Member

epage commented Feb 1, 2023

That is being tracked in #2911 which is complicated by the lazy building that clap does.

Techassi added a commit to stackabletech/stackable-cockpit that referenced this issue Oct 4, 2023
The command requires a call to the `build` function. See
clap-rs/clap#4685
github-merge-queue bot pushed a commit to stackabletech/stackable-cockpit that referenced this issue Oct 5, 2023
* Add cache subcommand documentation

* Add completions subcommand docs

* Update gen-docs xtask

* Update command pages

* Update stacklet xref

* Add conditions hint

* Update Cockpit start page

* Generate usage docs into antora partial

* Re-add correct long help texts

The command requires a call to the `build` function. See
clap-rs/clap#4685
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Updating dependencies
Projects
None yet
Development

No branches or pull requests

2 participants