zephyr/scripts/meta/west/main.py

113 lines
3.4 KiB
Python
Raw Normal View History

# Copyright 2018 Open Source Foundries Limited.
#
# SPDX-License-Identifier: Apache-2.0
'''Zephyr RTOS meta-tool (west) main module
'''
import argparse
from functools import partial
import os
import sys
from subprocess import CalledProcessError
from . import log
from .cmd import CommandContextError
scripts: west: add flash, debug, debugserver commands When run without any arguments, the commands work the same way that their CMake equivalents do. For example, if using the Ninja CMake generator, these are equivalent: west flash <----> ninja flash west debug <----> ninja debug west debugserver <----> ninja debugserver Like CMake's build tool mode, you can also run them from any directory in the system by passing the path to the build directory using --build-dir (-d): west flash -d build/my-board The commands will run the CMake-generated build system, so they keep dependencies up to date and users don't have to manually compile binaries between running CMake and using this tool. The commands also support important use cases that CMake can't: 1) Any arguments not handled by 'west flash' et al. are passed to the underlying runner. For example, if the runner supports --gdb-port, the default can be overridden like so: west debugserver --gdb-port=1234 Command processing by the 'west' command can also be halted using '--'; anything after that point (even if it's an option recognized by the west command) will be passed to the runner. Example: west debug -- --this-option-goes-to-the-debug-runner=foo 2) Any runner supported by the board can be selected at runtime using the -r (--runner) option. For example, if the board's flash runner defaults to nrfjprog but jlink is supported as well, it can be selected with: west flash -r jlink 3) The runner configuration can be persisted elsewhere, edited offline, and selected at runtime, using --cmake-cache (-c): west flash -c /home/me/some/other/CMakeCache.txt Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-10 06:16:30 +08:00
from .cmd.flash import Flash
from .cmd.debug import Debug, DebugServer
from .util import quote_sh_list
scripts: west: add flash, debug, debugserver commands When run without any arguments, the commands work the same way that their CMake equivalents do. For example, if using the Ninja CMake generator, these are equivalent: west flash <----> ninja flash west debug <----> ninja debug west debugserver <----> ninja debugserver Like CMake's build tool mode, you can also run them from any directory in the system by passing the path to the build directory using --build-dir (-d): west flash -d build/my-board The commands will run the CMake-generated build system, so they keep dependencies up to date and users don't have to manually compile binaries between running CMake and using this tool. The commands also support important use cases that CMake can't: 1) Any arguments not handled by 'west flash' et al. are passed to the underlying runner. For example, if the runner supports --gdb-port, the default can be overridden like so: west debugserver --gdb-port=1234 Command processing by the 'west' command can also be halted using '--'; anything after that point (even if it's an option recognized by the west command) will be passed to the runner. Example: west debug -- --this-option-goes-to-the-debug-runner=foo 2) Any runner supported by the board can be selected at runtime using the -r (--runner) option. For example, if the board's flash runner defaults to nrfjprog but jlink is supported as well, it can be selected with: west flash -r jlink 3) The runner configuration can be persisted elsewhere, edited offline, and selected at runtime, using --cmake-cache (-c): west flash -c /home/me/some/other/CMakeCache.txt Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-10 06:16:30 +08:00
COMMANDS = (Flash(), Debug(), DebugServer())
'''Supported top-level commands.'''
class InvalidWestContext(RuntimeError):
pass
def command_handler(command, known_args, unknown_args):
command.run(known_args, unknown_args)
def validate_context(args, unknown):
'''Validate the run-time context expected by west.'''
if args.zephyr_base:
os.environ['ZEPHYR_BASE'] = args.zephyr_base
else:
if 'ZEPHYR_BASE' not in os.environ:
log.wrn('--zephyr-base missing and no ZEPHYR_BASE',
'in the environment')
else:
args.zephyr_base = os.environ['ZEPHYR_BASE']
def parse_args(argv):
west_parser = argparse.ArgumentParser(
prog='west', description='The Zephyr RTOS meta-tool.',
epilog='Run "west <command> -h" for help on each command.')
west_parser.add_argument('-z', '--zephyr-base', default=None,
help='''Path to the Zephyr base directory. If not
given, ZEPHYR_BASE must be defined in the
environment, and will be used instead.''')
west_parser.add_argument('-v', '--verbose', default=0, action='count',
help='''Display verbose output. May be given
multiple times to increase verbosity.''')
subparser_gen = west_parser.add_subparsers(title='commands',
dest='command')
for command in COMMANDS:
parser = command.add_parser(subparser_gen)
parser.set_defaults(handler=partial(command_handler, command))
args, unknown = west_parser.parse_known_args(args=argv)
# Set up logging verbosity before doing anything else, so
# e.g. verbose messages related to argument handling errors
# work properly.
log.set_verbosity(args.verbose)
try:
validate_context(args, unknown)
except InvalidWestContext as iwc:
log.err(*iwc.args, fatal=True)
west_parser.print_usage(file=sys.stderr)
sys.exit(1)
if 'handler' not in args:
log.err('you must specify a command', fatal=True)
west_parser.print_usage(file=sys.stderr)
sys.exit(1)
return args, unknown
def main(argv=None):
if argv is None:
argv = sys.argv[1:]
args, unknown = parse_args(argv)
for_stack_trace = 'run as "west -v ... {} ..." for a stack trace'.format(
args.command)
try:
args.handler(args, unknown)
except KeyboardInterrupt:
sys.exit(0)
except CalledProcessError as cpe:
log.err('command exited with status {}: {}'.format(
cpe.args[0], quote_sh_list(cpe.args[1])))
if args.verbose:
raise
else:
log.inf(for_stack_trace)
except CommandContextError as cce:
log.die('command', args.command, 'cannot be run in this context:',
*cce.args)
except Exception as exc:
log.err(*exc.args, fatal=True)
if args.verbose:
raise
else:
log.inf(for_stack_trace)