From 269ea4ee88d61ca2b90825730dfbe0ac681b01e3 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 9 Jan 2019 16:55:35 -0700 Subject: [PATCH] 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: 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 --- src/west/_bootstrap/main.py | 6 ++--- src/west/commands/__init__.py | 39 ++++++++++++++++----------------- src/west/commands/build.py | 6 +++-- src/west/commands/debug.py | 11 +++++++--- src/west/commands/flash.py | 7 +++++- src/west/commands/project.py | 23 +++++++++++++++---- src/west/commands/run_common.py | 1 + src/west/main.py | 6 ++--- 8 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/west/_bootstrap/main.py b/src/west/_bootstrap/main.py index 87642a5..81482be 100644 --- a/src/west/_bootstrap/main.py +++ b/src/west/_bootstrap/main.py @@ -244,13 +244,13 @@ def bootstrap(args): print('=== Initial configuration written to {} ===' .format(config_path)) - # Wrap west init with --cached: - # i.e. `west init --use-cache ` + # Call `west post-init --use-cache ` 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) diff --git a/src/west/commands/__init__.py b/src/west/commands/__init__.py index 7697571..30564d6 100644 --- a/src/west/commands/__init__.py +++ b/src/west/commands/__init__.py @@ -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.''' diff --git a/src/west/commands/build.py b/src/west/commands/build.py index a7405e9..981bd1f 100644 --- a/src/west/commands/build.py +++ b/src/west/commands/build.py @@ -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) diff --git a/src/west/commands/debug.py b/src/west/commands/debug.py index 7ce3c1b..1a78193 100644 --- a/src/west/commands/debug.py +++ b/src/west/commands/debug.py @@ -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) diff --git a/src/west/commands/flash.py b/src/west/commands/flash.py index 72b716a..b7ff238 100644 --- a/src/west/commands/flash.py +++ b/src/west/commands/flash.py @@ -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) diff --git a/src/west/commands/project.py b/src/west/commands/project.py index fcc989f..fb1cb08 100644 --- a/src/west/commands/project.py +++ b/src/west/commands/project.py @@ -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: diff --git a/src/west/commands/run_common.py b/src/west/commands/run_common.py index 22a1f6e..fa8de90 100644 --- a/src/west/commands/run_common.py +++ b/src/west/commands/run_common.py @@ -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 diff --git a/src/west/main.py b/src/west/main.py index 52d1bbf..959f231 100755 --- a/src/west/main.py +++ b/src/west/main.py @@ -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='', dest='command') for command in COMMANDS: