commands: add per-command help

This is a baby step on issue #107 (Improve `west --help` formatting).

Add per-command help output to each command. While we're here, rename
'init' to 'post-init' to avoid a name clash with the init command
handled by the bootstrapper.

The "commands:" help output now looks like this in west -h:

positional arguments:
  <command>
    build               compile a Zephyr application
    flash               flash and run a binary on a board
    debug               flash and interactively debug a Zephyr application
    debugserver         connect to board and launch a debug server
    attach              interactively debug a board
    post-init           finish init tasks
    list                print information about projects in the west manifest
    clone               clone remote projects into local installation
    fetch               "git fetch" changes from project remotes
    pull                "git pull" changes from project remotes
    rebase              "git rebase" local projects onto manifest versions
    branch              create a branch in one or more local projects
    checkout            check out a branch in one or more local projects
    diff                "git diff" for one or more projects
    status              "git status" for one or more projects
    update              update the manifest and west repositories
    forall              run a command in one or more local projects

It would be nice to be able to group these subparsers and hide the
post-init command, though, which we can't seem to do with plain
argparse.

Signed-off-by: Marti Bolivar <marti@foundries.io>
This commit is contained in:
Marti Bolivar 2019-01-09 16:55:35 -07:00 committed by Carles Cufí
parent d9582ac752
commit 269ea4ee88
8 changed files with 63 additions and 36 deletions

View File

@ -244,13 +244,13 @@ def bootstrap(args):
print('=== Initial configuration written to {} ==='
.format(config_path))
# Wrap west init with --cached:
# i.e. `west init <options> --use-cache `
# Call `west post-init <options> --use-cache <tempdir>` to finish up.
#
# Note: main west will try to discover zephyr base and fail, as it is
# not fully initialized at this time.
# Thus a dummy zephyr_base is provided.
os.chdir(directory)
cmd = ['--zephyr-base', directory, 'init', '--manifest-url',
cmd = ['--zephyr-base', directory, 'post-init', '--manifest-url',
manifest_url, '--manifest-rev', manifest_rev, '--use-cache',
tempdir]
wrap(cmd)

View File

@ -21,34 +21,34 @@ class WestCommand(ABC):
All top-level commands supported by west implement this interface.'''
def __init__(self, name, description, accepts_unknown_args=False):
def __init__(self, name, help, description, accepts_unknown_args=False):
'''Create a command instance.
`name`: the command's name, as entered by the user.
`description`: one-line command description to show to the user.
:param name: the command's name, as entered by the user
:param help: one-line command help text
:param description: multi-line command description
`accepts_unknown_args`: if true, the command can handle
arbitrary unknown command line arguments in its run()
method. Otherwise, passing unknown arguments will cause
UnknownArgumentsError to be raised.
'''
:param accepts_unknown_args: if true, the command can handle
arbitrary unknown command line arguments
in its run() method. Otherwise, passing
unknown arguments will cause
UnknownArgumentsError to be raised.'''
self.name = name
self.help = help
self.description = description
self._accept_unknown = accepts_unknown_args
def run(self, args, unknown):
'''Run the command.
`args`: known arguments parsed via `register_arguments()`
`unknown`: unknown arguments present on the command line
'''
:param args: known arguments parsed via `register_arguments()`
:param unknown: unknown arguments present on the command line '''
if unknown and not self._accept_unknown:
self.parser.error('unexpected arguments: {}'.format(unknown))
self.do_run(args, unknown)
def add_parser(self, parser_adder):
'''Registers a parser for this command, and returns it.
'''
'''Registers a parser for this command, and returns it.'''
self.parser = self.do_add_parser(parser_adder)
return self.parser
@ -60,15 +60,14 @@ class WestCommand(ABC):
def do_add_parser(self, parser_adder):
'''Subclass method for registering command line arguments.
`parser_adder` is an argparse argument subparsers adder.'''
:param parser_adder: is an argparse argument subparsers adder.'''
@abstractmethod
def do_run(self, args, unknown):
'''Subclasses must implement; called when the command is run.
`args` is the namespace of parsed known arguments.
If `accepts_unknown_args` was False when constructing this
object, `unknown` will be empty. Otherwise, it is an iterable
containing all unknown arguments present on the command line.
'''
:param args: is the namespace of parsed known arguments.
:param unknown: If `accepts_unknown_args` was False when constructing
this object, this paramter is an empty sequence.
Otherwise, it is an iterable containing all unknown
arguments present on the command line.'''

View File

@ -11,7 +11,7 @@ from west.build import DEFAULT_BUILD_DIR, DEFAULT_CMAKE_GENERATOR, \
is_zephyr_build
from west.commands import WestCommand
BUILD_HELP = '''\
BUILD_DESCRIPTION = '''\
Convenience wrapper for building Zephyr applications.
This command attempts to do what you mean when run from a Zephyr
@ -45,7 +45,8 @@ class Build(WestCommand):
def __init__(self):
super(Build, self).__init__(
'build',
BUILD_HELP,
'compile a Zephyr application',
BUILD_DESCRIPTION,
accepts_unknown_args=False)
self.source_dir = None
@ -70,6 +71,7 @@ class Build(WestCommand):
def do_add_parser(self, parser_adder):
parser = parser_adder.add_parser(
self.name,
help=self.help,
formatter_class=argparse.RawDescriptionHelpFormatter,
description=self.description)

View File

@ -1,4 +1,5 @@
# Copyright (c) 2018 Open Source Foundries Limited.
# Copyright 2019 Foundries.io
#
# SPDX-License-Identifier: Apache-2.0
@ -16,6 +17,7 @@ class Debug(WestCommand):
def __init__(self):
super(Debug, self).__init__(
'debug',
'flash and interactively debug a Zephyr application',
dedent('''
Connect to the board, program the flash, and start a
debugging session.\n\n''') +
@ -35,8 +37,10 @@ class DebugServer(WestCommand):
def __init__(self):
super(DebugServer, self).__init__(
'debugserver',
'connect to board and launch a debug server',
dedent('''
Connect to the board and accept debug networking connections.
Connect to the board and launch a debug server which accepts
incoming connections for debugging the connected board.
The debug server binds to a known port, and allows client software
started elsewhere to connect to it and debug the running
@ -56,9 +60,10 @@ class Attach(WestCommand):
def __init__(self):
super(Attach, self).__init__(
'attach',
'interactively debug a board',
dedent('''
Connect to the board without programming the flash, and
start a debugging session.\n\n''') +
Like 'debug', this connects to the board and starts a debugging
session, but it doesn't reflash the program on the board.\n\n''') +
desc_common('attach'),
accepts_unknown_args=True)

View File

@ -1,9 +1,12 @@
# Copyright (c) 2018 Open Source Foundries Limited.
# Copyright 2019 Foundries.io
#
# SPDX-License-Identifier: Apache-2.0
'''west "flash" command'''
from textwrap import dedent
from west.commands.run_common import desc_common, add_parser_common, \
do_run_common
from west.commands import WestCommand
@ -14,7 +17,9 @@ class Flash(WestCommand):
def __init__(self):
super(Flash, self).__init__(
'flash',
'Flash and run a binary on a board.\n\n' +
'flash and run a binary on a board',
dedent('''
Connects to the board and reprograms it with a new binary\n\n''') +
desc_common('flash'),
accepts_unknown_args=True)

View File

@ -1,4 +1,5 @@
# Copyright (c) 2018, Nordic Semiconductor ASA
# Copyright 2018, 2019 Foundries.io
#
# SPDX-License-Identifier: Apache-2.0
@ -23,15 +24,16 @@ from west.manifest import Manifest, MalformedManifest, MANIFEST_PROJECT_INDEX
# branch.
_MANIFEST_REV_BRANCH = 'manifest-rev'
class Init(WestCommand):
class PostInit(WestCommand):
def __init__(self):
super().__init__(
'init',
'post-init',
'finish init tasks (do not use)',
_wrap('''
Initialize projects.
Finish initializing projects.
Continue the initialization of the project containing the manifest
file.
file. You should never need to call this.
'''))
def do_add_parser(self, parser_adder):
@ -81,6 +83,7 @@ class List(WestCommand):
def __init__(self):
super().__init__(
'list',
'print information about projects in the west manifest',
_wrap('''
List projects.
@ -163,6 +166,7 @@ class Clone(WestCommand):
def __init__(self):
super().__init__(
'clone',
'clone remote projects into local installation',
_wrap('''
Clone projects.
@ -217,6 +221,7 @@ class Fetch(WestCommand):
def __init__(self):
super().__init__(
'fetch',
'"git fetch" changes from project remotes',
_wrap('''
Fetch projects.
@ -244,6 +249,7 @@ class Pull(WestCommand):
def __init__(self):
super().__init__(
'pull',
'"git pull" changes from project remotes',
_wrap('''
Clone/fetch and rebase projects.
@ -275,6 +281,7 @@ class Rebase(WestCommand):
def __init__(self):
super().__init__(
'rebase',
'"git rebase" local projects onto manifest versions',
_wrap('''
Rebase projects.
@ -296,6 +303,7 @@ class Branch(WestCommand):
def __init__(self):
super().__init__(
'branch',
'create a branch in one or more local projects',
_wrap('''
Create a branch or list branches, in multiple projects.
@ -335,6 +343,7 @@ class Checkout(WestCommand):
def __init__(self):
super().__init__(
'checkout',
'check out a branch in one or more local projects',
_wrap('''
Check out local branch.
@ -385,6 +394,7 @@ class Diff(WestCommand):
def __init__(self):
super().__init__(
'diff',
'"git diff" for one or more projects',
_wrap('''
'git diff' projects.
@ -410,6 +420,7 @@ class Status(WestCommand):
def __init__(self):
super().__init__(
'status',
'"git status" for one or more projects',
_wrap('''
Runs 'git status' for each of the specified projects (default: all
cloned projects). Extra arguments are passed as-is to 'git status'.
@ -429,6 +440,7 @@ class Update(WestCommand):
def __init__(self):
super().__init__(
'update',
'update the manifest and west repositories',
_wrap('''
Updates the manifest repository and/or the West source code
repository. The remote to update from is taken from the
@ -491,6 +503,7 @@ class ForAll(WestCommand):
def __init__(self):
super().__init__(
'forall',
'run a command in one or more local projects',
_wrap('''
Runs a shell (Linux) or batch (Windows) command within the
repository of each of the specified projects (default: all cloned
@ -551,6 +564,8 @@ def _add_parser(parser_adder, cmd, *extra_args, **kwargs):
# Adds and returns a subparser for the project-related WestCommand 'cmd'.
# Any defaults can be overridden with kwargs.
if 'help' not in kwargs:
kwargs['help'] = cmd.help
if 'description' not in kwargs:
kwargs['description'] = cmd.description
if 'formatter_class' not in kwargs:

View File

@ -27,6 +27,7 @@ def add_parser_common(parser_adder, command):
parser = parser_adder.add_parser(
command.name,
formatter_class=argparse.RawDescriptionHelpFormatter,
help=command.help,
description=command.description)
# Remember to update scripts/west-completion.bash if you add or remove

View File

@ -23,7 +23,7 @@ from west.commands.flash import Flash
from west.commands.debug import Debug, DebugServer, Attach
from west.commands.project import List, Clone, Fetch, Pull, Rebase, Branch, \
Checkout, Diff, Status, Update, ForAll, \
WestUpdated, Init
WestUpdated, PostInit
from west.manifest import Manifest, MalformedConfig
from west.util import quote_sh_list, in_multirepo_install, west_dir
@ -38,7 +38,7 @@ BUILD_FLASH_COMMANDS = [
]
PROJECT_COMMANDS = [
Init(),
PostInit(),
List(),
Clone(),
Fetch(),
@ -174,7 +174,7 @@ def parse_args(argv):
west_parser.add_argument('-V', '--version', action='store_true')
subparser_gen = west_parser.add_subparsers(title='commands',
subparser_gen = west_parser.add_subparsers(metavar='<command>',
dest='command')
for command in COMMANDS: