Fix redundant help information being displayed for multi-commands.

Review Request #12179 — Created March 18, 2022 and submitted

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
Summary ID
Fix redundant help information being displayed for multi-commands.
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`.
7bb6bbf19cb1b5c1bf006e86be22b1c8aa1ed226
chipx86
david
  1. Ship It!
  2. 
      
chipx86
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to release-3.x (36db3d0)
Loading...