@ -13,17 +13,16 @@ import tempfile
import textwrap
import textwrap
import traceback
import traceback
from west import cmake
from west import log
from west import log
from west import util
from build_helpers import find_build_dir , is_zephyr_build , \
from build_helpers import find_build_dir , is_zephyr_build , \
FIND_BUILD_DIR_DESCRIPTION
FIND_BUILD_DIR_DESCRIPTION
from west . commands import CommandError
from west . commands import CommandError
from west . configuration import config
from west . configuration import config
import yaml
from runners import get_runner_cls , ZephyrBinaryRunner , MissingProgram
from runners import get_runner_cls , ZephyrBinaryRunner , MissingProgram
from runners . core import RunnerConfig
from zephyr_ext_common import cached_runner_config
import zcmake
# Context-sensitive help indentation.
# Context-sensitive help indentation.
# Don't change this, or output from argparse won't match up.
# Don't change this, or output from argparse won't match up.
@ -70,12 +69,17 @@ class WestLogHandler(logging.Handler):
else :
else :
log . dbg ( fmt , level = log . VERBOSE_EXTREME )
log . dbg ( fmt , level = log . VERBOSE_EXTREME )
def add_parser_common ( parser_adder , command ) :
def command_verb ( command ) :
parser = parser_adder . add_parser (
return " flash " if command . name == " flash " else " debug "
command . name ,
formatter_class = argparse . RawDescriptionHelpFormatter ,
def add_parser_common ( command , parser_adder = None , parser = None ) :
help = command . help ,
if parser_adder is not None :
description = command . description )
parser = parser_adder . add_parser (
command . name ,
formatter_class = argparse . RawDescriptionHelpFormatter ,
help = command . help ,
description = command . description ,
epilog = FIND_BUILD_DIR_DESCRIPTION )
# Remember to update scripts/west-completion.bash if you add or remove
# Remember to update scripts/west-completion.bash if you add or remove
# flags
# flags
@ -85,88 +89,130 @@ def add_parser_common(parser_adder, command):
help ; this may be combined with - - runner to restrict
help ; this may be combined with - - runner to restrict
output to a given runner . ''' )
output to a given runner . ''' )
group = parser . add_argument_group ( title = ' General Options ' )
group = parser . add_argument_group ( title = ' General options ' )
group . add_argument ( ' -d ' , ' --build-dir ' ,
help = ' Build directory to obtain runner information ' +
' from. ' + FIND_BUILD_DIR_DESCRIPTION )
group . add_argument ( ' -c ' , ' --cmake-cache ' ,
help = ''' Path to CMake cache file containing runner
configuration ( this is generated by the Zephyr
build system when compiling binaries ) ;
default : { } .
If this is a relative path , it is assumed relative to
group . add_argument ( ' -d ' , ' --build-dir ' , metavar = ' DIR ' ,
the build directory . An absolute path can also be
help = ' zephyr build directory ' )
given instead . ''' .format(cmake.DEFAULT_CACHE))
group . add_argument ( ' -c ' , ' --cmake-cache ' , metavar = ' FILE ' ,
help = ' override the default CMake cache file ' )
group . add_argument ( ' -r ' , ' --runner ' ,
group . add_argument ( ' -r ' , ' --runner ' ,
help = ''' If given, overrides any cached {}
help = f ' overrides the default { command . name } runner ' )
runner . ''' .format(command.name))
group . add_argument ( ' --skip-rebuild ' , action = ' store_true ' ,
group . add_argument ( ' --skip-rebuild ' , action = ' store_true ' ,
help = ''' If given, do not rebuild the application
help = ' do not rebuild the application first ' )
before running { } commands . ''' .format(command.name))
group = parser . add_argument_group ( title = ' Common runner options ' )
group = parser . add_argument_group (
title = ' Configuration overrides ' ,
group . add_argument ( ' --board-dir ' , metavar = ' DIR ' ,
description = textwrap . dedent ( ''' \
help = ' zephyr board directory ' )
These values usually come from the Zephyr build system itself
# FIXME: we should just have a single --file argument.
as stored in the CMake cache ; providing these options
group . add_argument ( ' --elf-file ' , metavar = ' FILE ' , help = ' path to zephyr.elf ' )
overrides those settings . ''' ))
group . add_argument ( ' --hex-file ' , metavar = ' FILE ' , help = ' path to zephyr.hex ' )
group . add_argument ( ' --bin-file ' , metavar = ' FILE ' , help = ' path to zephyr.bin ' )
# Important:
# FIXME: these are runner-specific. Remove them from this location.
#
group . add_argument ( ' --gdb ' , help = ' path to GDB, if applicable ' )
# 1. The destination variables of these options must match
group . add_argument ( ' --openocd ' , help = ' path to OpenOCD, if applicable ' )
# the RunnerConfig slots.
# 2. The default values for all of these must be None.
#
# This is how we detect if the user provided them or not when
# overriding values from the cached configuration.
command_verb = " flash " if command . name == " flash " else " debug "
group . add_argument ( ' --board-dir ' ,
help = ' Zephyr board directory ' )
group . add_argument ( ' --elf-file ' ,
help = ' Path to elf file to {0} ' . format ( command_verb ) )
group . add_argument ( ' --hex-file ' ,
help = ' Path to hex file to {0} ' . format ( command_verb ) )
group . add_argument ( ' --bin-file ' ,
help = ' Path to binary file to {0} ' . format ( command_verb ) )
group . add_argument ( ' --gdb ' ,
help = ' Path to GDB, if applicable ' )
group . add_argument ( ' --openocd ' ,
help = ' Path to OpenOCD, if applicable ' )
group . add_argument (
group . add_argument (
' --openocd-search ' ,
' --openocd-search ' , metavar = ' DIR ' ,
help = ' P ath to add to OpenOCD search path, if applicable' )
help = ' path to add to OpenOCD search path, if applicable ' )
return parser
return parser
def desc_common ( command_name ) :
def desc_common ( command_name ) :
return textwrap . dedent ( ''' \
return textwrap . dedent ( f ''' \
Any options not recognized by this command are passed to the
Only common " west {command_name} " options are listed here .
back - end { command } runner ( run " west {command} --context "
To get help on available runner - specific options , run :
for help on available runner - specific options ) .
west { command_name } - - context - d BUILD_DIR
''' )
def do_run_common ( command , args , unknown_args ) :
# This is the main routine for all the "west flash", "west debug",
# etc. commands.
If you need to pass an option to a runner which has the
if args . context :
same name as one recognized by this command , you can
dump_context ( command , args , unknown_args )
end argument parsing with a ' -- ' , like so :
return
west { command } - - { command } - arg = value - - - - runner - arg = value2
command_name = command . name
''' .format(** { ' command ' : command_name}))
build_dir = get_build_dir ( args )
cache = load_cmake_cache ( build_dir , args )
board = cache [ ' CACHED_BOARD ' ]
if not args . skip_rebuild :
rebuild ( command , build_dir , args )
# Load runners.yaml.
runners_yaml = runners_yaml_path ( cache )
runner_config = load_runners_yaml ( runners_yaml , args )
def _override_config_from_namespace ( cfg , namespace ) :
# Get a concrete ZephyrBinaryRunner subclass to use based on
''' Override a RunnerConfig ' s contents with command-line values. '''
# runners.yaml and command line arguments.
for var in cfg . __slots__ :
runner_cls = use_runner_cls ( command , board , args , runner_config )
if var in namespace :
runner_name = runner_cls . name ( )
val = getattr ( namespace , var )
if val is not None :
setattr ( cfg , var , val )
# Set up runner logging to delegate to west.log commands.
logger = logging . getLogger ( ' runners ' )
logger . setLevel ( LOG_LEVEL )
logger . addHandler ( WestLogHandler ( ) )
def _build_dir ( args , die_if_none = True ) :
# If the user passed -- to force the parent argument parser to stop
# parsing, it will show up here, and needs to be filtered out.
runner_args = [ arg for arg in unknown_args if arg != ' -- ' ]
# Arguments are provided in this order to allow the specific to
# override the general:
#
# - common runners.yaml arguments
# - runner-specific runners.yaml arguments
# - command line arguments
final_argv = ( runner_config [ ' args ' ] [ ' common ' ] +
runner_config [ ' args ' ] [ runner_name ] +
runner_args )
# At this point, 'args' contains parsed arguments which are both:
#
# 1. provided on the command line
# 2. handled by add_parser_common()
#
# This doesn't include runner specific arguments on the command line or
# anything from runners.yaml.
#
# We therefore have to re-parse now that we know everything,
# including the final runner.
parser = argparse . ArgumentParser ( prog = runner_name )
add_parser_common ( command , parser = parser )
runner_cls . add_parser ( parser )
final_args , unknown = parser . parse_known_args ( args = final_argv )
if unknown :
log . die ( f ' runner { runner_name } received unknown arguments: { unknown } ' )
# Create the RunnerConfig from the values assigned to common
# arguments. This is a hacky way to go about this; probably
# ZephyrBinaryRunner should define what it needs to make this
# happen by itself. That would be a larger refactoring of the
# runners package than there's time for right now, though.
#
# Use that RunnerConfig to create the ZephyrBinaryRunner instance
# and call its run().
runner = runner_cls . create ( runner_cfg_from_args ( final_args ,
build_dir ) ,
final_args )
try :
runner . run ( command_name )
except ValueError as ve :
log . err ( str ( ve ) , fatal = True )
dump_traceback ( )
raise CommandError ( 1 )
except MissingProgram as e :
log . die ( ' required program ' , e . filename ,
' not found; install it or add its location to PATH ' )
except RuntimeError as re :
if not args . verbose :
log . die ( re )
else :
log . err ( ' verbose mode enabled, dumping stack: ' , fatal = True )
raise
def get_build_dir ( args , die_if_none = True ) :
# Get the build directory for the given argument list and environment.
# Get the build directory for the given argument list and environment.
if args . build_dir :
if args . build_dir :
return args . build_dir
return args . build_dir
@ -189,282 +235,161 @@ def _build_dir(args, die_if_none=True):
else :
else :
return None
return None
def dump_traceback ( ) :
def load_cmake_cache ( build_dir , args ) :
# Save the current exception to a file and return its path.
cache_file = path . join ( build_dir , args . cmake_cache or zcmake . DEFAULT_CACHE )
fd , name = tempfile . mkstemp ( prefix = ' west-exc- ' , suffix = ' .txt ' )
try :
close ( fd ) # traceback has no use for the fd
return zcmake . CMakeCache ( cache_file )
with open ( name , ' w ' ) as f :
except FileNotFoundError :
traceback . print_exc ( file = f )
log . die ( f ' no CMake cache found (expected one at { cache_file } ) ' )
log . inf ( " An exception trace has been saved in " , name )
def do_run_common ( command , args , runner_args , cached_runner_var ) :
def rebuild ( command , build_dir , args ) :
if args . context :
_banner ( f ' west { command . name } : rebuilding ' )
_dump_context ( command , args , runner_args , cached_runner_var )
try :
return
zcmake . run_build ( build_dir )
except CalledProcessError :
if args . build_dir :
log . die ( f ' re-build in { args . build_dir } failed ' )
else :
log . die ( f ' re-build in { build_dir } failed (no --build-dir given) ' )
command_name = command . name
def runners_yaml_path ( cache ) :
build_dir = _build_dir ( args )
try :
return cache [ ' ZEPHYR_RUNNERS_YAML ' ]
except KeyError :
board = cache . get ( ' CACHED_BOARD ' )
log . die ( f ' either a pristine build is needed, or board { board } '
" doesn ' t support west flash/debug "
' (no ZEPHYR_RUNNERS_YAML in CMake cache) ' )
if not args . skip_rebuild :
def load_runners_yaml ( path , args ) :
_banner ( ' west {} : rebuilding ' . format ( command_name ) )
# Load runners.yaml using its location in the CMake cache,
try :
# allowing a command line override for the cache file location.
cmake . run_build ( build_dir )
except CalledProcessError :
if args . build_dir :
log . die ( ' cannot run {} , build in {} failed ' . format (
command_name , args . build_dir ) )
else :
log . die ( ' cannot run {} ; no --build-dir given and build in '
' current directory {} failed ' . format ( command_name ,
build_dir ) )
# Runner creation, phase 1.
#
# Get the default runner name from the cache, allowing a command
# line override. Get the ZephyrBinaryRunner class by name, and
# make sure it supports the command.
cache_file = path . join ( build_dir , args . cmake_cache or cmake . DEFAULT_CACHE )
try :
try :
cache = cmake . CMakeCache ( cache_file )
with open ( path , ' r ' ) as f :
config = yaml . safe_load ( f . read ( ) )
except FileNotFoundError :
except FileNotFoundError :
log . die ( ' no CMake cache found (expected one at {} ) ' . format ( cache_file ) )
log . die ( f ' runners.yaml file not found: { path } ' )
board = cache [ ' CACHED_BOARD ' ]
available = cache . get_list ( ' ZEPHYR_RUNNERS ' )
if not config . get ( ' runners ' ) :
if not available :
log . wrn ( f ' no pre-configured runners in { path } ; '
log . wrn ( ' No cached runners are available in ' , cache_file )
" this probably won ' t work " )
runner = args . runner or cache . get ( cached_runner_var )
return config
def use_runner_cls ( command , board , args , runner_config ) :
# Get the ZephyrBinaryRunner class from its name, and make sure it
# supports the command. Print a message about the choice, and
# return the class.
runner = args . runner or runner_config . get ( command . runner_key )
if runner is None :
if runner is None :
log . die ( ' No ' , command_name , ' runner available for board ' , board ,
log . die ( f ' no { command . name } runner available for board { board } . '
' ( {} is not in the cache). ' . format ( cached_runner_var ) ,
" Check the board ' s documentation for instructions. " )
" Check your board ' s documentation for instructions. " )
_banner ( f ' west { command . name } : using runner { runner } ' )
_banner ( ' west {} : using runner {} ' . format ( command_name , runner ) )
available = runner_config . get ( ' runners ' , [ ] )
if runner not in available :
if runner not in available :
log . wrn ( ' Runner { } is not configured for use with {} , '
log . wrn ( f ' runner { runner } is not configured for use with { board } , '
' this may not work ' . format ( runner , board ) )
' this may not work ' )
runner_cls = get_runner_cls ( runner )
runner_cls = get_runner_cls ( runner )
if command_name not in runner_cls . capabilities ( ) . commands :
if command . name not in runner_cls . capabilities ( ) . commands :
log . die ( ' Runner {} does not support command {} ' . format (
log . die ( f ' runner { runner } does not support command { command . name } ' )
runner , command_name ) )
# Runner creation, phase 2.
return runner_cls
#
# At this point, the common options above are already parsed in
# 'args', and unrecognized arguments are in 'runner_args'.
#
# - Set up runner logging to delegate to west.
# - Pull the RunnerConfig out of the cache
# - Override cached values with applicable command-line options
logger = logging . getLogger ( ' runners ' )
def runner_cfg_from_args ( args , build_dir ) :
logger . setLevel ( LOG_LEVEL )
return RunnerConfig ( build_dir , args . board_dir , args . elf_file ,
logger . addHandler ( WestLogHandler ( ) )
args . hex_file , args . bin_file ,
cfg = cached_runner_config ( build_dir , cache )
gdb = args . gdb , openocd = args . openocd ,
_override_config_from_namespace ( cfg , args )
openocd_search = args . openocd_search )
# Runner creation, phase 3.
#
# - Pull out cached runner arguments, and append command-line
# values (which should override the cache)
# - Construct a runner-specific argument parser to handle cached
# values plus overrides given in runner_args
# - Parse arguments and create runner instance from final
# RunnerConfig and parsed arguments.
cached_runner_args = cache . get_list (
' ZEPHYR_RUNNER_ARGS_ {} ' . format ( cmake . make_c_identifier ( runner ) ) )
assert isinstance ( runner_args , list ) , runner_args
# If the user passed -- to force the parent argument parser to stop
# parsing, it will show up here, and needs to be filtered out.
runner_args = [ arg for arg in runner_args if arg != ' -- ' ]
final_runner_args = cached_runner_args + runner_args
parser = argparse . ArgumentParser ( prog = runner )
runner_cls . add_parser ( parser )
parsed_args , unknown = parser . parse_known_args ( args = final_runner_args )
if unknown :
log . die ( ' Runner ' , runner , ' received unknown arguments: ' , unknown )
runner = runner_cls . create ( cfg , parsed_args )
try :
runner . run ( command_name )
except ValueError as ve :
log . err ( str ( ve ) , fatal = True )
dump_traceback ( )
raise CommandError ( 1 )
except MissingProgram as e :
log . die ( ' required program ' , e . filename ,
' not found; install it or add its location to PATH ' )
except RuntimeError as re :
if not args . verbose :
log . die ( re )
else :
log . err ( ' verbose mode enabled, dumping stack: ' , fatal = True )
raise
def dump_traceback ( ) :
# Save the current exception to a file and return its path.
fd , name = tempfile . mkstemp ( prefix = ' west-exc- ' , suffix = ' .txt ' )
close ( fd ) # traceback has no use for the fd
with open ( name , ' w ' ) as f :
traceback . print_exc ( file = f )
log . inf ( " An exception trace has been saved in " , name )
#
#
# Context-specific help
# west {command} --context
#
#
def _dump_context ( command , args , runner_args , cached_runner_var ) :
def dump_context ( command , args , unknown_args ) :
build_dir = _build_dir ( args , die_if_none = False )
build_dir = get_build_dir ( args , die_if_none = False )
if build_dir is None :
# Try to figure out the CMake cache file based on the build
log . wrn ( ' no --build-dir given or found; output will be limited ' )
# directory or an explicit argument.
runner_config = None
if build_dir is not None :
cache_file = path . abspath (
path . join ( build_dir , args . cmake_cache or cmake . DEFAULT_CACHE ) )
elif args . cmake_cache :
cache_file = path . abspath ( args . cmake_cache )
else :
else :
cache_file = None
cache = load_cmake_cache ( build_dir , args )
board = cache [ ' CACHED_BOARD ' ]
runners_yaml = runners_yaml_path ( cache )
runner_config = load_runners_yaml ( runners_yaml , args )
# Load the cache itself, if possible.
# Re-build unless asked not to, to make sure the output is up to date.
if cache_file is None :
log . wrn ( ' No build directory (--build-dir) or CMake cache '
' (--cmake-cache) given or found; output will be limited ' )
cache = None
else :
try :
cache = cmake . CMakeCache ( cache_file )
except Exception :
log . die ( ' Cannot load cache {} . ' . format ( cache_file ) )
# If we have a build directory, try to ensure build artifacts are
# up to date. If that doesn't work, still try to print information
# on a best-effort basis.
if build_dir and not args . skip_rebuild :
if build_dir and not args . skip_rebuild :
try :
rebuild ( command , build_dir , args )
cmake . run_build ( build_dir )
except CalledProcessError :
msg = ' Failed re-building application; cannot load context. '
if args . build_dir :
msg + = ' Is {} the right --build-dir? ' . format ( args . build_dir )
else :
msg + = textwrap . dedent ( ''' \
Use - - build - dir ( - d ) to specify a build directory ; the one
used was { } . ''' .format(build_dir))
log . die ( ' \n ' . join ( textwrap . wrap ( msg , initial_indent = ' ' ,
subsequent_indent = INDENT ,
break_on_hyphens = False ) ) )
if cache is None :
_dump_no_context_info ( command , args )
if not args . runner :
return
if args . runner :
if args . runner :
# Just information on one runner was requested.
try :
_dump_one_runner_info ( cache , args , build_dir , INDENT )
cls = get_runner_cls ( args . runner )
return
except ValueError :
log . die ( f ' invalid runner name { args . runner } ; choices: ' +
board = cache [ ' CACHED_BOARD ' ]
' , ' . join ( cls . name ( ) for cls in
ZephyrBinaryRunner . get_runners ( ) ) )
all_cls = { cls . name ( ) : cls for cls in ZephyrBinaryRunner . get_runners ( ) if
else :
command . name in cls . capabilities ( ) . commands }
cls = None
available = [ r for r in cache . get_list ( ' ZEPHYR_RUNNERS ' ) if r in all_cls ]
available_cls = { r : all_cls [ r ] for r in available if r in all_cls }
default_runner = cache . get ( cached_runner_var )
cfg = cached_runner_config ( build_dir , cache )
log . inf ( ' All Zephyr runners which support {} : ' . format ( command . name ) ,
colorize = True )
for line in util . wrap ( ' , ' . join ( all_cls . keys ( ) ) , INDENT ) :
log . inf ( line )
log . inf ( ' (Not all may work with this build, see available runners below.) ' ,
colorize = True )
if cache is None :
log . wrn ( ' Missing or invalid CMake cache; there is no context. ' ,
' Use --build-dir to specify the build directory. ' )
return
log . inf ( ' Build directory: ' , colorize = True )
log . inf ( INDENT + build_dir )
log . inf ( ' Board: ' , colorize = True )
log . inf ( INDENT + board )
log . inf ( ' CMake cache: ' , colorize = True )
log . inf ( INDENT + cache_file )
if not available :
# Bail with a message if no runners are available.
msg = ( ' No runners available for {} . '
' Consult the documentation for instructions on how to run '
' binaries on this target. ' ) . format ( board )
for line in util . wrap ( msg , ' ' ) :
log . inf ( line , colorize = True )
return
log . inf ( ' Available {} runners: ' . format ( command . name ) , colorize = True )
log . inf ( INDENT + ' , ' . join ( available ) )
log . inf ( ' Additional options for available ' , command . name , ' runners: ' ,
colorize = True )
for runner in available :
_dump_runner_opt_help ( runner , all_cls [ runner ] )
log . inf ( ' Default {} runner: ' . format ( command . name ) , colorize = True )
log . inf ( INDENT + default_runner )
_dump_runner_config ( cfg , ' ' , INDENT )
log . inf ( ' Runner-specific information: ' , colorize = True )
for runner in available :
log . inf ( ' {} {} : ' . format ( INDENT , runner ) , colorize = True )
_dump_runner_cached_opts ( cache , runner , INDENT * 2 , INDENT * 3 )
_dump_runner_caps ( available_cls [ runner ] , INDENT * 2 )
if len ( available ) > 1 :
log . inf ( ' (Add -r RUNNER to just print information about one runner.) ' ,
colorize = True )
if runner_config is None :
dump_context_no_config ( command , cls )
else :
log . inf ( f ' build configuration: ' , colorize = True )
log . inf ( f ' { INDENT } build directory: { build_dir } ' )
log . inf ( f ' { INDENT } board: { board } ' )
log . inf ( f ' { INDENT } runners.yaml: { runners_yaml } ' )
if cls :
dump_runner_context ( command , cls , runner_config )
else :
dump_all_runner_context ( command , runner_config , board , build_dir )
def _dump_no_context_info ( command , args ) :
def dump_context_no_config ( command , cls ) :
all_cls = { cls . name ( ) : cls for cls in ZephyrBinaryRunner . get_runners ( ) if
if not cls :
command . name in cls . capabilities ( ) . commands }
all_cls = { cls . name ( ) : cls for cls in ZephyrBinaryRunner . get_runners ( )
log . inf ( ' All Zephyr runners which support {} : ' . format ( command . name ) ,
if command . name in cls . capabilities ( ) . commands }
colorize = True )
log . inf ( ' all Zephyr runners which support {} : ' . format ( command . name ) ,
for line in util . wrap ( ' , ' . join ( all_cls . keys ( ) ) , INDENT ) :
log . inf ( line )
if not args . runner :
log . inf ( ' Add -r RUNNER to print more information about any runner. ' ,
colorize = True )
colorize = True )
dump_wrapped_lines ( ' , ' . join ( all_cls . keys ( ) ) , INDENT )
log . inf ( )
log . inf ( ' Note: use -r RUNNER to limit information to one runner. ' )
else :
# This does the right thing with runner_config=None.
dump_runner_context ( command , cls , None )
def dump_runner_context ( command , cls , runner_config , indent = ' ' ) :
dump_runner_caps ( cls , indent )
dump_runner_option_help ( cls , indent )
def _dump_one_runner_info ( cache , args , build_dir , indent ) :
if runner_config is None :
runner = args . runner
cls = get_runner_cls ( runner )
if cache is None :
_dump_runner_opt_help ( runner , cls )
_dump_runner_caps ( cls , ' ' )
return
return
available = runner in cache . get_list ( ' ZEPHYR_RUNNERS ' )
if cls . name ( ) in runner_config [ ' runners ' ] :
cfg = cached_runner_config ( build_dir , cache )
dump_runner_args ( cls . name ( ) , runner_config , indent )
else :
log . inf ( ' Build directory: ' , colorize = True )
log . wrn ( f ' support for runner { cls . name ( ) } is not configured '
log . inf ( INDENT + build_dir )
f ' in this build directory ' )
log . inf ( ' Board: ' , colorize = True )
log . inf ( INDENT + cache [ ' CACHED_BOARD ' ] )
log . inf ( ' CMake cache: ' , colorize = True )
log . inf ( INDENT + cache . cache_file )
log . inf ( runner , ' is available: ' , ' yes ' if available else ' no ' ,
colorize = True )
_dump_runner_opt_help ( runner , cls )
_dump_runner_config ( cfg , ' ' , indent )
if available :
_dump_runner_cached_opts ( cache , runner , ' ' , indent )
_dump_runner_caps ( cls , ' ' )
if not available :
log . wrn ( ' Runner ' , runner , ' is not configured in this build. ' )
def dump_runner_caps ( cls , indent = ' ' ) :
# Print RunnerCaps for the given runner class.
def _dump_runner_caps ( cls , base_indent ) :
log . inf ( f ' { indent } { cls . name ( ) } capabilities: ' , colorize = True )
log . inf ( ' {} Capabilities: ' . format ( base_indent ) , colorize = True )
log . inf ( f ' { indent } { INDENT } { cls . capabilities ( ) } ' )
log . inf ( ' {} {} ' . format ( base_indent + INDENT , cls . capabilities ( ) ) )
def dump_runner_option_help ( cls , indent = ' ' ) :
# Print help text for class-specific command line options for the
# given runner class.
def _dump_runner_opt_help ( runner , cls ) :
# Construct and print the usage text
dummy_parser = argparse . ArgumentParser ( prog = ' ' , add_help = False )
dummy_parser = argparse . ArgumentParser ( prog = ' ' , add_help = False )
cls . add_parser ( dummy_parser )
cls . add_parser ( dummy_parser )
formatter = dummy_parser . _get_formatter ( )
formatter = dummy_parser . _get_formatter ( )
@ -481,31 +406,53 @@ def _dump_runner_opt_help(runner, cls):
formatter . add_arguments ( actions )
formatter . add_arguments ( actions )
formatter . end_section ( )
formatter . end_section ( )
# Get the runner help, with the "REMOVE ME" string gone
# Get the runner help, with the "REMOVE ME" string gone
runner_help = ' \n ' . join ( formatter . format_help ( ) . splitlines ( ) [ 1 : ] )
runner_help = f ' \n { indent } ' . join ( formatter . format_help ( ) . splitlines ( ) [ 1 : ] )
log . inf ( ' {} options: ' . format ( runner ) , colorize = True )
log . inf ( f ' { indent } { cls . name ( ) } options: ' , colorize = True )
log . inf ( runner_help )
log . inf ( indent + runner_help )
def dump_runner_args ( group , runner_config , indent = ' ' ) :
msg = f ' { indent } { group } arguments from runners.yaml: '
args = runner_config [ ' args ' ] [ group ]
if args :
log . inf ( msg , colorize = True )
for arg in args :
log . inf ( f ' { indent } { INDENT } { arg } ' )
else :
log . inf ( f ' { msg } (none) ' , colorize = True )
def dump_all_runner_context ( command , runner_config , board , build_dir ) :
all_cls = { cls . name ( ) : cls for cls in ZephyrBinaryRunner . get_runners ( ) if
command . name in cls . capabilities ( ) . commands }
available = runner_config [ ' runners ' ]
available_cls = { r : all_cls [ r ] for r in available if r in all_cls }
default_runner = runner_config [ command . runner_key ]
def _dump_runner_config ( cfg , initial_indent , subsequent_indent ) :
log . inf ( f ' zephyr runners which support " west { command . name } " : ' ,
log . inf ( ' {} Cached common runner configuration: ' . format ( initial_indent ) ,
colorize = True )
colorize = True )
for var in cfg . __slots__ :
dump_wrapped_lines ( ' , ' . join ( all_cls . keys ( ) ) , INDENT )
log . inf ( ' {} -- {} = {} ' . format ( subsequent_indent , var , getattr ( cfg , var ) ) )
log . inf ( )
dump_wrapped_lines ( ' Note: not all may work with this board and build '
' directory. Available runners are listed below. ' ,
def _dump_runner_cached_opts ( cache , runner , initial_indent , subsequent_indent ) :
INDENT )
runner_args = _get_runner_args ( cache , runner )
if not runner_args :
return
log . inf ( ' {} Cached runner-specific options: ' . format ( initial_indent ) ,
log . inf ( f ' available runners in runners.yaml: ' ,
colorize = True )
colorize = True )
for arg in runner_args :
dump_wrapped_lines ( ' , ' . join ( available ) , INDENT )
log . inf ( ' {} {} ' . format ( subsequent_indent , arg ) )
log . inf ( f ' default runner in runners.yaml: ' , colorize = True )
log . inf ( INDENT + default_runner )
dump_runner_args ( ' common ' , runner_config )
log . inf ( ' runner-specific context: ' , colorize = True )
for cls in available_cls . values ( ) :
dump_runner_context ( command , cls , runner_config , INDENT )
def _get_runner_args ( cache , runner ) :
if len ( available ) > 1 :
runner_ident = cmake . make_c_identifier ( runner )
log . inf ( )
args_var = ' ZEPHYR_RUNNER_ARGS_ {} ' . format ( runner_ident )
log . inf ( ' Note: use -r RUNNER to limit information to one runner. ' )
return cache . get_list ( args_var )
def dump_wrapped_lines ( text , indent ) :
for line in textwrap . wrap ( text , initial_indent = indent ,
subsequent_indent = indent ,
break_on_hyphens = False ,
break_long_words = False ) :
log . inf ( line )