Example #1
0
    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)
Example #2
0
    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)
Example #3
0
 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)
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
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
Example #7
0
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
Example #8
0
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')