Fix redundant help information being displayed for multi-commands.

Review Request #12179 — Created March 19, 2022 and submitted — Latest diff uploaded

Information

RBTools
release-3.x

Reviewers

Multi-commands (such as rbt review) had an issue where usage and help
output would be displayed multiple times. On Python 2.7, we'd get a
usage + help block, followed by a usage block, followed by another
usage + help block. On newer versions, we'd just get two usage + help
blocks.

The reason this was happening has to do with how we handle help in
RBTools. We have our own custom --help handler that's invoked before
any commands are set up, which allows us to do rbt --help,
rbt <command> --help, or rbt --help <command>, along with supporting
passing --help to any third-party rbt-* scripts.

When handling help for internal commands, we locate the right command
class, check if it's a multi-command or a standard command, and attempt
to get the right help information. For multi-commands, we do an explicit
parse of the options, which will funnel the --help to the right
subcommand if needed.

This is where the problem was found. This test parse will see the
--help and will result in ArgumentParser.print_help() being called,
resulting in one usage + help block.

Then, on Python 2.7, the argument parser notes that we haven't passed
any required arguments for the subparser and triggers
ArgumentParser.error(), which prints a second usage block.

We then return formatted help, which includes the final usage + help
block. This gets printed to the console.

Solving this requires babysitting argparse a bit more.

We no longer leave invocation to chance. Instead, we first check if
there's a multi-command class, and then grab the first positional
argument. If it matches a known subcommand, we pull out the class and
build a new, fixed set of command line arguments that will generate new
help output.

This gives us full control of how help output is generated. We no longer
need to stub argparse when invoking --help on a subcommand, and
we're far less sensitive to Python version differences or the position
of help or -h/--help.

Tested the following on Python 2.7 and 3.8:

  • rbt help
  • rbt help <command>
  • rbt help <multi-command>
  • rbt help <multi-command> <subcommand>
  • rbt --help
  • rbt --help <command>
  • rbt --help <multi-command>
  • rbt --help <multi-command> <subcommand>
  • rbt <command> --help
  • rbt <multi-command> --help
  • rbt <multi-command> --help <subcommand>
  • rbt <multi-command> <subcommand> --help

Commits

Files