def likely_merged(np, zp, nsha, zsha): analyzer = nwh.RepoAnalyzer(np, zp, nsha, zsha) likely_merged = analyzer.likely_merged if likely_merged: # likely_merged is a map from downstream commits to # lists of upstream commits that look similar. log.msg('downstream patches which are likely merged upstream', '(revert these if appropriate):', color=log.WRN_COLOR) for dc, ucs in likely_merged.items(): if len(ucs) == 1: log.inf(f'- {dc.oid} {commit_shortlog(dc)}') log.inf(f' Similar upstream shortlog:\n' f' {ucs[0].oid} {commit_shortlog(ucs[0])}') else: log.inf(f'- {dc.oid} {commit_shortlog(dc)}\n' ' Similar upstream shortlogs:') for i, uc in enumerate(ucs, start=1): log.inf(f' {i}. {uc.oid} {commit_shortlog(uc)}') else: log.dbg('no downstream patches seem to have been merged upstream')
def dump_context_no_config(command, cls): if not cls: all_cls = { cls.name(): cls for cls in ZephyrBinaryRunner.get_runners() if command.name in cls.capabilities().commands } log.inf('all Zephyr runners which support {}:'.format(command.name), 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 likely_merged(np, zp, nsha, zsha): analyzer = nwh.RepoAnalyzer(np, zp, nsha, zsha) likely_merged = analyzer.likely_merged if likely_merged: # likely_merged is a map from downstream commits to # lists of upstream commits that look similar. log.msg('downstream patches which are likely merged upstream', '(revert these if appropriate):', color=log.WRN_COLOR) for dc, ucs in likely_merged.items(): log.inf(f'- {dc.oid} ({nwh.commit_shortlog(dc)})\n' ' Similar upstream commits:') for uc in ucs: log.inf(f' {uc.oid} ({nwh.commit_shortlog(uc)})') else: log.inf('no downstream patches seem to have been merged upstream')
def dump_context(command, args, unknown_args): build_dir = get_build_dir(args, die_if_none=False) if build_dir is None: log.wrn('no --build-dir given or found; output will be limited') runner_config = None else: 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) # Re-build unless asked not to, to make sure the output is up to date. if build_dir and not args.skip_rebuild: rebuild(command, build_dir, args) if args.runner: try: cls = get_runner_cls(args.runner) except ValueError: log.die(f'invalid runner name {args.runner}; choices: ' + ', '.join(cls.name() for cls in ZephyrBinaryRunner.get_runners())) else: cls = None 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 sign(self, command, build_dir, bcfg, formats): args = command.args if args.tool_path: command.check_force( shutil.which(args.tool_path), '--tool-path {}: not an executable'.format(args.tool_path)) tool_path = args.tool_path else: tool_path = shutil.which('rimage') if not tool_path: log.die('rimage not found; either install it', 'or provide --tool-path') b = pathlib.Path(build_dir) cache = CMakeCache.from_build_dir(build_dir) board = cache['CACHED_BOARD'] log.inf('Signing for board ' + board) target = self.edt_get_rimage_target(board) log.inf('Signing for SOC target ' + target) if not args.quiet: log.inf('Signing with tool {}'.format(tool_path)) bootloader = str(b / 'zephyr' / 'bootloader.elf.mod') kernel = str(b / 'zephyr' / 'zephyr.elf.mod') out_bin = str(b / 'zephyr' / 'zephyr.ri') sign_base = ([tool_path] + args.tool_args + ['-o', out_bin, '-m', target, '-i', '3'] + [bootloader, kernel]) if not args.quiet: log.inf(quote_sh_list(sign_base)) subprocess.check_call(sign_base)
def do_run(self, args, remainder): self.args = args # Avoid having to pass them around log.dbg('args: {} remainder: {}'.format(args, remainder, level=log.VERBOSE_EXTREME)) # Store legacy -s option locally source_dir = self.args.source_dir self._parse_remainder(remainder) if source_dir: if self.args.source_dir: log.die("source directory specified twice:({} and {})".format( source_dir, self.args.source_dir)) self.args.source_dir = source_dir log.dbg('source_dir: {} cmake_opts: {}'.format(self.args.source_dir, self.args.cmake_opts)) self._sanity_precheck() self._setup_build_dir() if is_zephyr_build(self.build_dir): self._update_cache() if self.args.cmake or self.args.cmake_opts: self.run_cmake = True else: self.run_cmake = True self._setup_source_dir() self._sanity_check() log.inf('source directory: {}'.format(self.source_dir), colorize=True) log.inf('build directory: {}{}'.format( self.build_dir, (' (created)' if self.created_build_dir else '')), colorize=True) if self.cmake_cache: board = self.cmake_cache.get('CACHED_BOARD') elif self.args.board: board = self.args.board else: board = 'UNKNOWN' # shouldn't happen log.inf('BOARD:', board, colorize=True) self._run_cmake(self.args.cmake_opts) self._sanity_check() self._update_cache() extra_args = ['--target', args.target] if args.target else [] cmake.run_build(self.build_dir, extra_args=extra_args)
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] log.inf(f'zephyr runners which support "west {command.name}":', colorize=True) dump_wrapped_lines(', '.join(all_cls.keys()), INDENT) log.inf() dump_wrapped_lines( 'Note: not all may work with this board and build ' 'directory. Available runners are listed below.', INDENT) log.inf(f'available runners in runners.yaml:', colorize=True) dump_wrapped_lines(', '.join(available), INDENT) 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) if len(available) > 1: log.inf() log.inf('Note: use -r RUNNER to limit information to one runner.')
def dump_runner_caps(cls, indent=''): # Print RunnerCaps for the given runner class. log.inf(f'{indent}{cls.name()} capabilities:', colorize=True) log.inf(f'{indent}{INDENT}{cls.capabilities()}')
def print_gdbserver_message(self, gdb_port): log.inf('Intel S1000 GDB server running on port {}'.format(gdb_port))
def print_gdbserver_message(self): log.inf('J-Link GDB server running on port {}'.format(self.gdb_port))
def _dump_runner_caps(cls, base_indent): log.inf('{}Capabilities:'.format(base_indent), colorize=True) log.inf('{}{}'.format(base_indent + INDENT, cls.capabilities()))
def _dump_context(command, args, runner_args, cached_runner_var): build_dir = _build_dir(args, die_if_none=False) # Try to figure out the CMake cache file based on the build # directory or an explicit argument. 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: cache_file = None # Load the cache itself, if possible. if cache_file is None: log.wrn('No build directory (--build-dir) or CMake cache ' '(--cache-file) 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: try: 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: # Just information on one runner was requested. _dump_one_runner_info(cache, args, build_dir, INDENT) return board = cache['CACHED_BOARD'] all_cls = { cls.name(): cls for cls in ZephyrBinaryRunner.get_runners() if command.name in cls.capabilities().commands } 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.warn('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)
def _banner(msg): log.inf('-- west build: ' + msg, colorize=True)
def do_run(self, args, unknown_args): self.setup_upstream_downstream(args) # Get a dict containing projects that are in the NCS which are # *not* imported from Zephyr in nrf/west.yml. We will treat # these specially to make the output easier to understand. ignored_imports = Manifest.from_file( import_flags=ImportFlag.IGNORE_PROJECTS) in_nrf = set(p.name for p in ignored_imports.projects[MANIFEST_PROJECT_INDEX + 1:]) # This is a dict mapping names of projects which *are* imported # from zephyr to the Project instances. self.imported_pmap = {name: project for name, project in self.ncs_pmap.items() if name not in in_nrf} log.inf('Comparing your manifest-rev branches with zephyr/west.yml ' f'at {self.zephyr_rev}' + (', sha: ' + self.zephyr_sha if self.zephyr_rev != self.zephyr_sha else '')) log.inf() present_blacklisted = [] present_allowed = [] missing_blacklisted = [] missing_allowed = [] for zp in self.z_pmap.values(): nn = to_ncs_name(zp) present = nn in self.ncs_pmap blacklisted = PurePath(zp.path) in _PROJECT_BLACKLIST if present: if blacklisted: present_blacklisted.append(zp) else: present_allowed.append(zp) else: if blacklisted: missing_blacklisted.append(zp) else: missing_allowed.append(zp) def print_lst(projects): for p in projects: log.inf(f'{_name_and_path(p)}') if missing_blacklisted and log.VERBOSE >= log.VERBOSE_NORMAL: log.banner('blacklisted zephyr projects', 'not in nrf (these are all OK):') print_lst(missing_blacklisted) log.banner('blacklisted zephyr projects in NCS:') if present_blacklisted: log.wrn(f'these should all be removed from {self.manifest.path}!') print_lst(present_blacklisted) else: log.inf('none (OK)') log.banner('non-blacklisted zephyr projects missing from NCS:') if missing_allowed: west_yml = self.manifest.path log.wrn( f'missing projects should be added to NCS or blacklisted\n' f" To add to NCS:\n" f" 1. do the zephyr mergeup\n" f" 2. update zephyr revision in {west_yml}\n" f" 3. add projects to zephyr's name_whitelist in " f"{west_yml}\n" f" 4. run west {self.name} again to check your work\n" f" To blacklist: edit _PROJECT_BLACKLIST in {__file__}") for p in missing_allowed: log.small_banner(f'{_name_and_path(p)}:') log.inf(f'upstream revision: {p.revision}') log.inf(f'upstream URL: {p.url}') else: log.inf('none (OK)') if present_allowed: log.banner('projects in both zephyr and NCS:') for zp in present_allowed: # Do some extra checking on unmerged commits. self.allowed_project(zp) if log.VERBOSE <= log.VERBOSE_NONE: log.inf('\nNote: verbose output was omitted,', 'use "west -v ncs-compare" for more details.')
def print_loot(self, name, project, z_project, args): # Print a list of out of tree outstanding patches in the given # project. # # name: project name # project: the west.manifest.Project instance in the NCS manifest # z_project: the Project instance in the upstream manifest # args: parsed arguments from argparse name_path = _name_and_path(project) # Get the upstream revision of the project. The zephyr project # has to be treated as a special case. if name == 'zephyr': z_rev = self.zephyr_rev else: z_rev = z_project.revision n_rev = 'refs/heads/manifest-rev' try: nsha = project.sha(n_rev) project.git('cat-file -e ' + nsha) except subprocess.CalledProcessError: log.wrn(f"{name_path}: can't get loot; please run " f'"west update" (no "{n_rev}" ref)') return try: zsha = z_project.sha(z_rev) z_project.git('cat-file -e ' + zsha) except subprocess.CalledProcessError: log.wrn(f"{name_path}: can't get loot; please fetch upstream URL " f'{z_project.url} (need revision {z_project.revision})') return try: analyzer = nwh.RepoAnalyzer(project, z_project, n_rev, z_rev) except nwh.InvalidRepositoryError as ire: log.die(f"{name_path}: {str(ire)}") try: loot = analyzer.downstream_outstanding except nwh.UnknownCommitsError as uce: log.die(f'{name_path}: unknown commits: {str(uce)}') if not loot and log.VERBOSE <= log.VERBOSE_NONE: # Don't print output if there's no loot unless verbose # mode is on. return log.banner(name_path) log.inf(f'NCS commit (manifest-rev): {nsha}, upstream commit: {zsha}') log.inf('OOT patches: ' + (f'{len(loot)} total' if loot else 'none') + (', output limited by --file' if args.files else '')) for c in loot: if args.files and not nwh.commit_affects_files(c, args.files): log.dbg(f"skipping {c.oid}; it doesn't affect file filter", level=log.VERBOSE_VERY) continue if args.sha_only: log.inf(str(c.oid)) else: log.inf(f'- {c.oid} {nwh.commit_shortlog(c)}')
def dump_all_runner_context(command, runners_yaml, board, build_dir): all_cls = { cls.name(): cls for cls in ZephyrBinaryRunner.get_runners() if command.name in cls.capabilities().commands } available = runners_yaml['runners'] available_cls = {r: all_cls[r] for r in available if r in all_cls} default_runner = runners_yaml[command.runner_key] yaml_path = runners_yaml_path(build_dir, board) runners_yaml = load_runners_yaml(yaml_path) log.inf(f'zephyr runners which support "west {command.name}":', colorize=True) dump_wrapped_lines(', '.join(all_cls.keys()), INDENT) log.inf() dump_wrapped_lines( 'Note: not all may work with this board and build ' 'directory. Available runners are listed below.', INDENT) log.inf(f'available runners in runners.yaml:', colorize=True) dump_wrapped_lines(', '.join(available), INDENT) log.inf(f'default runner in runners.yaml:', colorize=True) log.inf(INDENT + default_runner) log.inf('common runner configuration:', colorize=True) runner_config = get_runner_config(build_dir, yaml_path, runners_yaml) for field, value in zip(runner_config._fields, runner_config): log.inf(f'{INDENT}- {field}: {value}') log.inf('runner-specific context:', colorize=True) for cls in available_cls.values(): dump_runner_context(command, cls, runners_yaml, INDENT) if len(available) > 1: log.inf() log.inf('Note: use -r RUNNER to limit information to one runner.')
def print_gdbserver_message(self, gdb_port): log.inf('Nios II GDB server running on port {}'.format(gdb_port))
def _msg(msg): # Prints "msg" as a smaller banner, i.e. prefixed with '-- ' and # not colorized. log.inf('--- ' + msg, colorize=False)
def _banner(msg): # Prints "msg" as a "banner", i.e. prefixed with '=== ' and colorized. log.inf('=== ' + msg, colorize=True)
def sign(self, command, build_dir, build_conf, formats): if not formats: return args = command.args b = pathlib.Path(build_dir) imgtool = self.find_imgtool(command, args) # The vector table offset is set in Kconfig: vtoff = self.get_cfg(command, build_conf, 'CONFIG_ROM_START_OFFSET') # Flash device write alignment and the partition's slot size # come from devicetree: flash = self.edt_flash_node(b, args.quiet) align, addr, size = self.edt_flash_params(flash) if build_conf.getboolean('CONFIG_BOOTLOADER_MCUBOOT'): log.wrn("CONFIG_BOOTLOADER_MCUBOOT is not set to y in " f"{build_conf.path}; this probably won't work") kernel = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr') if 'bin' in formats: in_bin = b / 'zephyr' / f'{kernel}.bin' if not in_bin.is_file(): log.die(f"no unsigned .bin found at {in_bin}") in_bin = os.fspath(in_bin) else: in_bin = None if 'hex' in formats: in_hex = b / 'zephyr' / f'{kernel}.hex' if not in_hex.is_file(): log.die(f"no unsigned .hex found at {in_hex}") in_hex = os.fspath(in_hex) else: in_hex = None if not args.quiet: log.banner('image configuration:') log.inf('partition offset: {0} (0x{0:x})'.format(addr)) log.inf('partition size: {0} (0x{0:x})'.format(size)) log.inf('rom start offset: {0} (0x{0:x})'.format(vtoff)) # Base sign command. # # We provide a default --version in case the user is just # messing around and doesn't want to set one. It will be # overridden if there is a --version in args.tool_args. sign_base = imgtool + [ 'sign', '--version', '0.0.0+0', '--align', str(align), '--header-size', str(vtoff), '--slot-size', str(size) ] sign_base.extend(args.tool_args) if not args.quiet: log.banner('signing binaries') if in_bin: out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin') sign_bin = sign_base + [in_bin, out_bin] if not args.quiet: log.inf(f'unsigned bin: {in_bin}') log.inf(f'signed bin: {out_bin}') log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) if in_hex: out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex') sign_hex = sign_base + [in_hex, out_hex] if not args.quiet: log.inf(f'unsigned hex: {in_hex}') log.inf(f'signed hex: {out_hex}') log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)
def sign(self, command, build_dir, build_conf, formats): args = command.args if args.tool_path: command.check_force( shutil.which(args.tool_path), '--tool-path {}: not an executable'.format(args.tool_path)) tool_path = args.tool_path else: tool_path = shutil.which('rimage') if not tool_path: log.die('rimage not found; either install it', 'or provide --tool-path') b = pathlib.Path(build_dir) cache = CMakeCache.from_build_dir(build_dir) board = cache['CACHED_BOARD'] log.inf('Signing for board ' + board) target = self.edt_get_rimage_target(board) conf = target + '.toml' log.inf('Signing for SOC target ' + target + ' using ' + conf) if not args.quiet: log.inf('Signing with tool {}'.format(tool_path)) bootloader = str(b / 'zephyr' / 'bootloader.elf.mod') kernel = str(b / 'zephyr' / 'zephyr.elf.mod') out_bin = str(b / 'zephyr' / 'zephyr.ri') out_xman = str(b / 'zephyr' / 'zephyr.ri.xman') out_tmp = str(b / 'zephyr' / 'zephyr.rix') conf_path_cmd = [] if cache.get('RIMAGE_CONFIG_PATH') and not args.tool_data: rimage_conf = pathlib.Path(cache['RIMAGE_CONFIG_PATH']) conf_path = str(rimage_conf / conf) conf_path_cmd = ['-c', conf_path] elif args.tool_data: conf_dir = pathlib.Path(args.tool_data) conf_path = str(conf_dir / conf) conf_path_cmd = ['-c', conf_path] else: log.die('Configuration not found') if '--no-manifest' in args.tool_args: no_manifest = True args.tool_args.remove('--no-manifest') else: no_manifest = False sign_base = ([tool_path] + args.tool_args + ['-o', out_bin] + conf_path_cmd + ['-i', '3', '-e'] + [bootloader, kernel]) if not args.quiet: log.inf(quote_sh_list(sign_base)) subprocess.check_call(sign_base) if no_manifest: filenames = [out_bin] else: filenames = [out_xman, out_bin] with open(out_tmp, 'wb') as outfile: for fname in filenames: with open(fname, 'rb') as infile: outfile.write(infile.read()) os.remove(out_bin) os.rename(out_tmp, out_bin)
def print_lst(projects): for p in projects: log.inf(f'{_name_and_path(p)}')
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: 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) cache = cmake.CMakeCache(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: raise CommandContextError( textwrap.dedent(""" No {} runner available for {}. Please either specify one manually, or check your board's documentation for alternative instructions.""".format(command_name, board))) log.inf('Using runner:', 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'. # # - Pull the RunnerConfig out of the cache # - Override cached values with applicable command-line options 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: raise CommandContextError('Runner', runner, 'received unknown arguments', unknown) runner = runner_cls.create(cfg, parsed_args) runner.run(command_name)
def allowed_project(self, zp): nn = to_ncs_name(zp) np = self.ncs_pmap[nn] # is_imported is true if we imported this project from the # zephyr manifest rather than defining it directly ourselves # in nrf/west.yml. is_imported = nn in self.imported_pmap imported = ', imported from zephyr' if is_imported else '' banner = f'{nn} ({zp.path}){imported}:' nrev = 'refs/heads/manifest-rev' if np.name == 'zephyr': zrev = self.zephyr_sha else: zrev = zp.revision nsha = self.checked_sha(np, nrev) zsha = self.checked_sha(zp, zrev) if not np.is_cloned() or nsha is None or zsha is None: log.small_banner(banner) if not np.is_cloned(): log.wrn('project is not cloned; please run "west update"') elif nsha is None: log.wrn(f"can't compare; please run \"west update {nn}\" " f'(need revision {np.revision})') elif zsha is None: log.wrn(f"can't compare; please fetch upstream URL {zp.url} " f'(need revision {zp.revision})') return cp = np.git(f'rev-list --left-right --count {zsha}...{nsha}', capture_stdout=True) behind, ahead = [int(c) for c in cp.stdout.split()] if zsha == nsha: status = 'up to date' elif ahead and not behind: status = f'ahead by {ahead} commit' + ("s" if ahead > 1 else "") elif np.is_ancestor_of(nsha, zsha): status = f'behind by {behind} commit' + ("s" if behind > 1 else "") else: status = f'diverged: {ahead} ahead, {behind} behind' commits = f'NCS commit: {nsha}, upstream commit: {zsha}' if 'up to date' in status or 'ahead by' in status: if log.VERBOSE > log.VERBOSE_NONE: # Up to date or ahead: only print in verbose mode. log.small_banner(banner) log.inf(commits) log.inf(status) likely_merged(np, zp, nsha, zsha) else: # Behind or diverged: always print. if is_imported and 'behind by' in status: status += ' and imported: update by doing zephyr mergeup' log.small_banner(banner) log.inf(commits) log.msg(status, color=log.WRN_COLOR) likely_merged(np, zp, nsha, zsha)
def _dump_one_runner_info(cache, args, build_dir, indent): runner = args.runner cls = get_runner_cls(runner) if cache is None: _dump_runner_opt_help(runner, cls) _dump_runner_caps(cls, '') return available = runner in cache.get_list('ZEPHYR_RUNNERS') cfg = cached_runner_config(build_dir, cache) log.inf('Build directory:', colorize=True) log.inf(INDENT + build_dir) 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 _sanity_check(self): # Sanity check the build configuration. # Side effect: may update cmake_cache attribute. log.dbg('sanity checking the build', level=log.VERBOSE_EXTREME) self._sanity_check_source_dir() self.check_force( is_zephyr_build(self.build_dir) or self.args.board, 'this looks like a new or clean build, please provide --board') if not self.cmake_cache: return # That's all we can check without a cache. cached_app = self.cmake_cache.get('APPLICATION_SOURCE_DIR') log.dbg('APPLICATION_SOURCE_DIR:', cached_app, level=log.VERBOSE_EXTREME) source_abs = (os.path.abspath(self.args.source_dir) if self.args.source_dir else None) cached_abs = os.path.abspath(cached_app) if cached_app else None log.dbg('pristine:', self.auto_pristine, level=log.VERBOSE_EXTREME) # If the build directory specifies a source app, make sure it's # consistent with --source-dir. apps_mismatched = (source_abs and cached_abs and source_abs != cached_abs) self.check_force( not apps_mismatched or self.auto_pristine, 'Build directory "{}" is for application "{}", but source ' 'directory "{}" was specified; please clean it, use --pristine, ' 'or use --build-dir to set another build directory'. format(self.build_dir, cached_abs, source_abs)) if apps_mismatched: self.run_cmake = True # If they insist, we need to re-run cmake. # If CACHED_BOARD is not defined, we need --board from the # command line. cached_board = self.cmake_cache.get('CACHED_BOARD') log.dbg('CACHED_BOARD:', cached_board, level=log.VERBOSE_EXTREME) # If app_mismatched and pristine are true we will run pristine on the # build, invalidating the cached board. Whenever we run pristine we # require the user to provide all the require inputs again. self.check_force((cached_board and not (apps_mismatched and self.auto_pristine)) or self.args.board, 'Cached board not defined, please provide --board') # Check consistency between cached board and --board. boards_mismatched = (self.args.board and cached_board and self.args.board != cached_board) self.check_force( not boards_mismatched or self.auto_pristine, 'Build directory {} targets board {}, but board {} was specified. ' '(Clean the directory, use --pristine, or use --build-dir to ' 'specify a different one.)'. format(self.build_dir, cached_board, self.args.board)) if self.auto_pristine and (apps_mismatched or boards_mismatched): log.inf('Making build dir {} pristine'.format(self.build_dir)) self._run_build('pristine') self.cmake_cache = None log.dbg('run_cmake:', True, level=log.VERBOSE_EXTREME) self.run_cmake = True # Tricky corner-case: The user has not specified a build folder but # there was one in the CMake cache. Since this is going to be # invalidated, reset to CWD and re-run the basic tests. if ((boards_mismatched and not apps_mismatched) and (not source_abs and cached_abs)): self._setup_source_dir() self._sanity_check_source_dir()
def _dump_runner_config(cfg, initial_indent, subsequent_indent): log.inf('{}Cached common runner configuration:'.format(initial_indent), colorize=True) for var in cfg.__slots__: log.inf('{}--{}={}'.format(subsequent_indent, var, getattr(cfg, var)))
def _banner(msg): log.inf('-- ' + msg, colorize=True)
def sign(self, command, build_dir, bcfg, formats): args = command.args if args.tool_path: command.check_force( shutil.which(args.tool_path), '--tool-path {}: not an executable'.format(args.tool_path)) tool_path = args.tool_path else: tool_path = shutil.which('imgtool') if not tool_path: log.die( 'imgtool not found; either install it', '(e.g. "pip3 install imgtool") or provide --tool-path') align, vtoff, slot_size = [ self.get_cfg(command, bcfg, x) for x in ('DT_FLASH_WRITE_BLOCK_SIZE', 'CONFIG_TEXT_SECTION_OFFSET', 'DT_FLASH_AREA_IMAGE_0_SIZE') ] log.dbg('build config: --align={}, --header-size={}, --slot-size={}'. format(align, vtoff, slot_size)) # Base sign command. # # We provide a default --version in case the user is just # messing around and doesn't want to set one. It will be # overridden if there is a --version in args.tool_args. sign_base = [tool_path, 'sign', '--version', '0.0.0+0'] if align: sign_base.extend(['--align', str(align)]) else: log.wrn('expected nonzero flash alignment, but ' 'DT_FLASH_WRITE_BLOCK_SIZE={} ' "in build directory's ({}) device tree".format( align, build_dir)) if vtoff: sign_base.extend(['--header-size', str(vtoff)]) else: log.wrn('expected nonzero header size, but ' 'CONFIG_TEXT_SECTION_OFFSET={} ' "in build directory's ({}) .config".format( vtoff, build_dir)) if slot_size: sign_base.extend(['--slot-size', str(slot_size)]) else: log.wrn('expected nonzero slot size, but ' 'DT_FLASH_AREA_IMAGE_0_SIZE={} ' "in build directory's ({}) device tree".format( slot_size, build_dir)) b = pathlib.Path(build_dir) cache = cmake.CMakeCache.from_build_dir(build_dir) runner_config = cached_runner_config(build_dir, cache) # Build a signed .bin if 'bin' in formats and runner_config.bin_file: out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin') log.inf('Generating:', out_bin) sign_bin = (sign_base + args.tool_args + [runner_config.bin_file, out_bin]) log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) # Build a signed .hex if 'hex' in formats and runner_config.hex_file: out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex') log.inf('Generating:', out_hex) sign_hex = (sign_base + args.tool_args + [runner_config.hex_file, out_hex]) log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)
def sign(self, command, build_dir, bcfg, formats): if not formats: return args = command.args b = pathlib.Path(build_dir) cache = CMakeCache.from_build_dir(build_dir) tool_path = self.find_imgtool(command, args) # The vector table offset is set in Kconfig: vtoff = self.get_cfg(command, bcfg, 'CONFIG_TEXT_SECTION_OFFSET') # Flash device write alignment and the partition's slot size # come from devicetree: flash = self.edt_flash_node(b, cache) align, addr, size = self.edt_flash_params(flash) runner_config = cached_runner_config(build_dir, cache) if 'bin' in formats: in_bin = runner_config.bin_file if not in_bin: log.die("can't find unsigned .bin to sign") else: in_bin = None if 'hex' in formats: in_hex = runner_config.hex_file if not in_hex: log.die("can't find unsigned .hex to sign") else: in_hex = None log.banner('image configuration:') log.inf('partition offset: {0} (0x{0:x})'.format(addr)) log.inf('partition size: {0} (0x{0:x})'.format(size)) log.inf('text section offset: {0} (0x{0:x})'.format(vtoff)) # Base sign command. # # We provide a default --version in case the user is just # messing around and doesn't want to set one. It will be # overridden if there is a --version in args.tool_args. sign_base = [ tool_path, 'sign', '--version', '0.0.0+0', '--align', str(align), '--header-size', str(vtoff), '--slot-size', str(size) ] sign_base.extend(args.tool_args) log.banner('signed binaries:') if in_bin: out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin') sign_bin = sign_base + [in_bin, out_bin] log.inf('bin: {}'.format(out_bin)) log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) if in_hex: out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex') sign_hex = sign_base + [in_hex, out_hex] log.inf('hex: {}'.format(out_hex)) log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)