def do_run(self, args, user_args): if args.exclude_west: log.wrn('ignoring --exclude-west') failed_rebases = [] for project in _projects(args, listed_must_be_cloned=False, exclude_manifest=True): _banner(project.format('updating {name_and_path}:')) returncode = _update(project, args.rebase, args.keep_descendants) if returncode: failed_rebases.append(project) log.err(project.format('{name_and_path} failed to rebase')) if failed_rebases: # Avoid printing this message if exactly one project # was specified on the command line. if len(args.projects) != 1: log.err(('The following project{} failed to rebase; ' 'see above for details: {}').format( 's' if len(failed_rebases) > 1 else '', ', '.join(p.format('{name_and_path}') for p in failed_rebases))) raise CommandError(1)
def do_run(self, args, user_args): if args.update: _update_west() failed_rebases = [] for project in _projects(args, listed_must_be_cloned=False, exclude_manifest=True): _fetch(project) branch = _current_branch(project) sha = _sha(project, _MANIFEST_REV_BRANCH) if branch is not None: is_ancestor = _is_ancestor_of(project, sha, branch) try_rebase = args.rebase else: # If no branch is checked out, -k and -r don't matter. is_ancestor = False try_rebase = False if args.keep_descendants and is_ancestor: # A descendant is currently checked out and -k was # given, so there's nothing more to do. _inf( project, 'Left branch "{}", a descendant of {}, checked out'.format( branch, sha)) elif try_rebase: # Attempt a rebase. Don't exit the program on error; # instead, append to the list of failed rebases and # continue trying to update the other projects. We'll # tell the user a complete list of errors when we're done. cp = _rebase(project, check=False) if cp.returncode: failed_rebases.append(project) _err(project, '{name_and_path} failed to rebase') else: # We can't keep a descendant or rebase, so just check # out the new detached HEAD and print helpful # information about things they can do with any # locally checked out branch. _checkout_detach(project, _MANIFEST_REV_BRANCH) self._post_checkout_help(args, project, branch, sha, is_ancestor) if failed_rebases: # Avoid printing this message if exactly one project # was specified on the command line. if len(args.projects) != 1: log.err(('The following project{} failed to rebase; ' 'see above for details: {}').format( 's' if len(failed_rebases) > 1 else '', ', '.join( _expand_shorthands(p, '{name_and_path}') for p in failed_rebases))) raise CommandError(1)
def read(self, args): section, key = self._sk(args) cfg = configparser.ConfigParser() read_config(configfile=args.configfile or ALL, config=cfg) value = cfg.get(section, key, fallback=None) if value is not None: log.inf(value) else: log.dbg(f'{args.name} is unset') raise CommandError(returncode=1)
def _handle_failed(self, args, failed): # Shared code for commands (like status, diff, update) that need # to do the same thing to multiple projects, but collect # and report errors if anything failed. if not failed: return elif len(failed) < 20: s = 's:' if len(failed) > 1 else '' projects = ', '.join(f'{p.name}' for p in failed) log.err(f'{self.name} failed for project{s} {projects}') else: log.err(f'{self.name} failed for multiple projects; see above') raise CommandError(1)
def delete(self, args): section, key = self._sk(args) if args.delete_all: what = ALL elif args.configfile: what = args.configfile else: what = None # local or global, whichever comes first try: delete_config(section, key, configfile=what) except KeyError: log.dbg(f'{args.name} was not set in requested location(s)') raise CommandError(returncode=1) except PermissionError as pe: self._perm_error(pe, what, section, key)
def do_run_common(command, args, unknown_args): # This is the main routine for all the "west flash", "west debug", # etc. commands. if args.context: dump_context(command, args, unknown_args) return command_name = 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) # Get a concrete ZephyrBinaryRunner subclass to use based on # runners.yaml and command line arguments. runner_cls = use_runner_cls(command, board, args, runner_config) runner_name = runner_cls.name() # Set up runner logging to delegate to west.log commands. logger = logging.getLogger('runners') logger.setLevel(LOG_LEVEL) logger.addHandler(WestLogHandler()) # 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 do_run_common(command, user_args, user_runner_args): # This is the main routine for all the "west flash", "west debug", # etc. commands. if user_args.context: dump_context(command, user_args, user_runner_args) return command_name = command.name build_dir = get_build_dir(user_args) cache = load_cmake_cache(build_dir, user_args) board = cache['CACHED_BOARD'] if not user_args.skip_rebuild: rebuild(command, build_dir, user_args) # Load runners.yaml. yaml_path = runners_yaml_path(build_dir, board) runners_yaml = load_runners_yaml(yaml_path) # Get a concrete ZephyrBinaryRunner subclass to use based on # runners.yaml and command line arguments. runner_cls = use_runner_cls(command, board, user_args, runners_yaml, cache) runner_name = runner_cls.name() # Set up runner logging to delegate to west.log commands. logger = logging.getLogger('runners') logger.setLevel(LOG_LEVEL) logger.addHandler(WestLogHandler()) # 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 user_runner_args if arg != '--'] # Arguments in this order to allow specific to override general: # # - runner-specific runners.yaml arguments # - user-provided command line arguments final_argv = runners_yaml['args'][runner_name] + runner_args # 'user_args' contains parsed arguments which are: # # 1. provided on the command line, and # 2. handled by add_parser_common(), and # 3. *not* runner-specific # # 'final_argv' contains unparsed arguments from either: # # 1. runners.yaml, or # 2. the command line # # We next have to: # # - parse 'final_argv' now that we have all the command line # arguments # - create a RunnerConfig using 'user_args' and the result # of parsing 'final_argv' parser = argparse.ArgumentParser(prog=runner_name) add_parser_common(command, parser=parser) runner_cls.add_parser(parser) args, unknown = parser.parse_known_args(args=final_argv) if unknown: log.die(f'runner {runner_name} received unknown arguments: {unknown}') # Override args with any user_args. The latter must take # precedence, or e.g. --hex-file on the command line would be # ignored in favor of a board.cmake setting. for a, v in vars(user_args).items(): if v is not None: setattr(args, a, v) # Create the RunnerConfig from runners.yaml and any command line # overrides. runner_config = get_runner_config(build_dir, yaml_path, runners_yaml, args) log.dbg(f'runner_config: {runner_config}', level=log.VERBOSE_VERY) # Use that RunnerConfig to create the ZephyrBinaryRunner instance # and call its run(). try: runner = runner_cls.create(runner_config, args) 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 user_args.verbose: log.die(re) else: log.err('verbose mode enabled, dumping stack:', fatal=True) raise
def do_run_common(command, args, runner_args, cached_runner_var): if args.context: _dump_context(command, args, runner_args, cached_runner_var) return command_name = command.name build_dir = _build_dir(args) if not args.skip_rebuild: _banner('west {}: rebuilding'.format(command_name)) try: 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: cache = cmake.CMakeCache(cache_file) except FileNotFoundError: log.die('no CMake cache found (expected one at {})'.format(cache_file)) board = cache['CACHED_BOARD'] available = cache.get_list('ZEPHYR_RUNNERS') if not available: log.wrn('No cached runners are available in', cache_file) runner = args.runner or cache.get(cached_runner_var) if runner is None: log.die('No', command_name, 'runner available for board', board, '({} is not in the cache).'.format(cached_runner_var), "Check your board's documentation for instructions.") _banner('west {}: using runner {}'.format(command_name, runner)) if runner not in available: log.wrn('Runner {} is not configured for use with {}, ' 'this may not work'.format(runner, board)) runner_cls = get_runner_cls(runner) if command_name not in runner_cls.capabilities().commands: log.die('Runner {} does not support command {}'.format( runner, command_name)) # Runner creation, phase 2. # # 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') logger.setLevel(LOG_LEVEL) logger.addHandler(WestLogHandler()) cfg = cached_runner_config(build_dir, cache) _override_config_from_namespace(cfg, args) # 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')