repo: refactor help output handling

Currently we have the behavior:
* `repo`: Equivalent to `repo help` -- only shows common subcommands
  (with short description), and then exits 0.
* `repo --help`: Shows repo's core options, lists all commands (no
  specific info), and then exits 0.

The first case is not behaving well:
* If you run `repo` without a specific subcommand, that's an error,
  so we should be exiting 1 instead.
* Showing only subcommands and no actual option summary makes it seem
  like repo itself doesn't take any options.  This confuses users.

Let's rework things a bit.  Now we have the behavior:
* `repo`: Shows repo's core options, lists all commands (no specific
  info), and then exits 1.
* `repo --help`: Shows repo's core options, shows common subcommands
  (with short description), and then exits 0.
* `repo --help-all`: Shows repo's core options, shows all subcommands
  (with short description), and then exits 0.

Basically we swap the behavior of `repo` and `repo --help`, and fix
the exit status when the subcommand is missing.

The addition of --help-all is mostly for the man pages.  We were
relying on `repo help --all` to generate the repo(1) man page, but
that too omitted the core repo options.  Now the man page includes
all the core repo options and provides a summary of all commands.

Change-Id: I1f99b99d5b8af2591f96a078d0647a3d76d6b0fc
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/312908
Reviewed-by: Xin Li <delphij@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
This commit is contained in:
Mike Frysinger 2021-07-26 23:46:32 -04:00
parent a024bd33b8
commit 56345c345b
5 changed files with 81 additions and 19 deletions

30
main.py
View File

@ -95,6 +95,8 @@ global_options = optparse.OptionParser(
add_help_option=False) add_help_option=False)
global_options.add_option('-h', '--help', action='store_true', global_options.add_option('-h', '--help', action='store_true',
help='show this help message and exit') help='show this help message and exit')
global_options.add_option('--help-all', action='store_true',
help='show this help message with all subcommands and exit')
global_options.add_option('-p', '--paginate', global_options.add_option('-p', '--paginate',
dest='pager', action='store_true', dest='pager', action='store_true',
help='display command output in the pager') help='display command output in the pager')
@ -128,6 +130,23 @@ class _Repo(object):
self.repodir = repodir self.repodir = repodir
self.commands = all_commands self.commands = all_commands
def _PrintHelp(self, short: bool = False, all_commands: bool = False):
"""Show --help screen."""
global_options.print_help()
print()
if short:
commands = ' '.join(sorted(self.commands))
wrapped_commands = textwrap.wrap(commands, width=77)
print('Available commands:\n %s' % ('\n '.join(wrapped_commands),))
print('\nRun `repo help <command>` for command-specific details.')
print('Bug reports:', Wrapper().BUG_URL)
else:
cmd = self.commands['help']()
if all_commands:
cmd.PrintAllCommandsBody()
else:
cmd.PrintCommonCommandsBody()
def _ParseArgs(self, argv): def _ParseArgs(self, argv):
"""Parse the main `repo` command line options.""" """Parse the main `repo` command line options."""
for i, arg in enumerate(argv): for i, arg in enumerate(argv):
@ -177,19 +196,16 @@ class _Repo(object):
SetTrace() SetTrace()
# Handle options that terminate quickly first. # Handle options that terminate quickly first.
if gopts.help: if gopts.help or gopts.help_all:
global_options.print_help() self._PrintHelp(short=False, all_commands=gopts.help_all)
commands = ' '.join(sorted(self.commands))
wrapped_commands = textwrap.wrap(commands, width=77)
print('\nAvailable commands:\n %s' % ('\n '.join(wrapped_commands),))
print('\nRun `repo help <command>` for command-specific details.')
return 0 return 0
elif gopts.show_version: elif gopts.show_version:
# Always allow global --version regardless of subcommand validity. # Always allow global --version regardless of subcommand validity.
name = 'version' name = 'version'
elif not name: elif not name:
# No subcommand specified, so show the help/subcommand. # No subcommand specified, so show the help/subcommand.
name = 'help' self._PrintHelp(short=True)
return 1
SetDefaultColoring(gopts.color) SetDefaultColoring(gopts.color)

View File

@ -36,6 +36,9 @@ output manifest in JSON format (experimental)
\fB\-\-pretty\fR \fB\-\-pretty\fR
format output for humans to read format output for humans to read
.TP .TP
\fB\-\-no\-local\-manifests\fR
ignore local manifests
.TP
\fB\-o\fR \-|NAME.xml, \fB\-\-output\-file\fR=\fI\,\-\/\fR|NAME.xml \fB\-o\fR \-|NAME.xml, \fB\-\-output\-file\fR=\fI\,\-\/\fR|NAME.xml
file to save the manifest to file to save the manifest to
.SS Logging options: .SS Logging options:
@ -95,7 +98,7 @@ include*)>
.IP .IP
<!ELEMENT notice (#PCDATA)> <!ELEMENT notice (#PCDATA)>
.IP .IP
<!ELEMENT remote EMPTY> <!ELEMENT remote (annotation*)>
<!ATTLIST remote name ID #REQUIRED> <!ATTLIST remote name ID #REQUIRED>
<!ATTLIST remote alias CDATA #IMPLIED> <!ATTLIST remote alias CDATA #IMPLIED>
<!ATTLIST remote fetch CDATA #REQUIRED> <!ATTLIST remote fetch CDATA #REQUIRED>
@ -393,13 +396,13 @@ Same syntax as the corresponding element of `project`.
.PP .PP
Element annotation Element annotation
.PP .PP
Zero or more annotation elements may be specified as children of a project Zero or more annotation elements may be specified as children of a project or
element. Each element describes a name\-value pair that will be exported into remote element. Each element describes a name\-value pair. For projects, this
each project's environment during a 'forall' command, prefixed with REPO__. In name\-value pair will be exported into each project's environment during a
addition, there is an optional attribute "keep" which accepts the case \&'forall' command, prefixed with `REPO__`. In addition, there is an optional
insensitive values "true" (default) or "false". This attribute determines attribute "keep" which accepts the case insensitive values "true" (default) or
whether or not the annotation will be kept when exported with the manifest "false". This attribute determines whether or not the annotation will be kept
subcommand. when exported with the manifest subcommand.
.PP .PP
Element copyfile Element copyfile
.PP .PP

View File

@ -2,9 +2,44 @@
.TH REPO "1" "July 2021" "repo" "Repo Manual" .TH REPO "1" "July 2021" "repo" "Repo Manual"
.SH NAME .SH NAME
repo \- repository management tool built on top of git repo \- repository management tool built on top of git
.SH DESCRIPTION .SH SYNOPSIS
usage: repo COMMAND [ARGS] .B repo
The complete list of recognized repo commands are: [\fI\,-p|--paginate|--no-pager\/\fR] \fI\,COMMAND \/\fR[\fI\,ARGS\/\fR]
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
show this help message and exit
.TP
\fB\-\-help\-all\fR
show this help message with all subcommands and exit
.TP
\fB\-p\fR, \fB\-\-paginate\fR
display command output in the pager
.TP
\fB\-\-no\-pager\fR
disable the pager
.TP
\fB\-\-color\fR=\fI\,COLOR\/\fR
control color usage: auto, always, never
.TP
\fB\-\-trace\fR
trace git command execution (REPO_TRACE=1)
.TP
\fB\-\-trace\-python\fR
trace python command execution
.TP
\fB\-\-time\fR
time repo command execution
.TP
\fB\-\-version\fR
display this version of repo
.TP
\fB\-\-event\-log\fR=\fI\,EVENT_LOG\/\fR
filename of event log to append timeline to
.TP
\fB\-\-git\-trace2\-event\-log\fR=\fI\,GIT_TRACE2_EVENT_LOG\/\fR
directory to write git trace2 event log to
.SS "The complete list of recognized repo commands are:"
.TP .TP
abandon abandon
Permanently abandon a development branch Permanently abandon a development branch
@ -91,3 +126,4 @@ version
Display the version of repo Display the version of repo
.PP .PP
See 'repo help <command>' for more information on a specific command. See 'repo help <command>' for more information on a specific command.
Bug reports: https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue

View File

@ -59,7 +59,7 @@ def main(argv):
cmdlist.append(['help2man', '-N', '-n', 'repository management tool built on top of git', cmdlist.append(['help2man', '-N', '-n', 'repository management tool built on top of git',
'-S', 'repo', '-m', 'Repo Manual', f'--version-string={version}', '-S', 'repo', '-m', 'Repo Manual', f'--version-string={version}',
'-o', MANDIR.joinpath('repo.1'), TOPDIR.joinpath('repo'), '-o', MANDIR.joinpath('repo.1'), TOPDIR.joinpath('repo'),
'-h', 'help --all']) '-h', '--help-all'])
with tempfile.TemporaryDirectory() as tempdir: with tempfile.TemporaryDirectory() as tempdir:
repo_dir = Path(tempdir) / '.repo' repo_dir = Path(tempdir) / '.repo'

View File

@ -50,14 +50,21 @@ Displays detailed usage information about a command.
def _PrintAllCommands(self): def _PrintAllCommands(self):
print('usage: repo COMMAND [ARGS]') print('usage: repo COMMAND [ARGS]')
self.PrintAllCommandsBody()
def PrintAllCommandsBody(self):
print('The complete list of recognized repo commands are:') print('The complete list of recognized repo commands are:')
commandNames = list(sorted(all_commands)) commandNames = list(sorted(all_commands))
self._PrintCommands(commandNames) self._PrintCommands(commandNames)
print("See 'repo help <command>' for more information on a " print("See 'repo help <command>' for more information on a "
'specific command.') 'specific command.')
print('Bug reports:', Wrapper().BUG_URL)
def _PrintCommonCommands(self): def _PrintCommonCommands(self):
print('usage: repo COMMAND [ARGS]') print('usage: repo COMMAND [ARGS]')
self.PrintCommonCommandsBody()
def PrintCommonCommandsBody(self):
print('The most commonly used repo commands are:') print('The most commonly used repo commands are:')
def gitc_supported(cmd): def gitc_supported(cmd):