def do_run(self, args, ignored): if self.topdir: zb = os.environ.get('ZEPHYR_BASE') if zb: msg = textwrap.dedent(f''' Note: In your environment, ZEPHYR_BASE is set to: {zb} This forces west to search for a workspace there. Try unsetting ZEPHYR_BASE and re-running this command.''') else: msg = '' self.die_already(self.topdir, msg) if args.local and (args.manifest_url or args.manifest_rev): log.die('-l cannot be combined with -m or --mr') if shutil.which('git') is None: log.die("can't find git; install it or ensure it's on your PATH") if args.local: topdir = self.local(args) else: topdir = self.bootstrap(args) log.banner(f'Initialized. Now run "west update" inside {topdir}.')
def local(self, args): if args.manifest_rev is not None: log.die('--mr cannot be used with -l') manifest_dir = util.canon_path(args.directory or os.getcwd()) manifest_file = join(manifest_dir, 'west.yml') topdir = dirname(manifest_dir) rel_manifest = basename(manifest_dir) west_dir = os.path.join(topdir, WEST_DIR) log.banner('Initializing from existing manifest repository', rel_manifest) if not exists(manifest_file): log.die('No "west.yml" found in {}'.format(manifest_dir)) self.create(west_dir) os.chdir(topdir) # This validates the manifest. Note we cannot use # self.manifest from west init, as we are in the middle of # creating the installation right now. projects = self.projects(manifest_file) log.small_banner( 'Creating {} and local configuration'.format(west_dir)) update_config('manifest', 'path', rel_manifest) self.topdir = topdir return projects, manifest_dir
def do_run(self, args, user_args): if args.exclude_west: log.wrn('ignoring --exclude-west') failed_rebases = [] for project in self._projects(args.projects): if isinstance(project, ManifestProject): continue log.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 update(self): log.banner('updating ESP-IDF submodules..') module_path = (Path(os.getenv("ZEPHYR_BASE")).absolute() / r".." / "modules" / "hal" / "espressif") if not module_path.exists(): log.die('cannot find esp-idf project in $ZEPHYR_BASE path') # look for origin remote remote_name = cmd_check(("git", "remote"), cwd=module_path).decode('utf-8') if "origin" not in remote_name: # add origin url cmd_exec(("git", "remote", "add", "origin", ESP_IDF_REMOTE), cwd=module_path) else: remote_url = cmd_check(("git", "remote", "get-url", "origin"), cwd=module_path).decode('utf-8') # update origin URL if ESP_IDF_REMOTE not in remote_url: cmd_exec( ("git", "remote", "set-url", "origin", ESP_IDF_REMOTE), cwd=module_path) cmd_exec(("git", "submodule", "update", "--init", "--recursive"), cwd=module_path) log.banner('updating ESP-IDF submodules completed')
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 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 try: nsha = project.sha(project.revision) project.git('cat-file -e ' + nsha) except subprocess.CalledProcessError: log.wrn(f"{name_path}: can't get loot; please run " f'"west update" (need revision {project.revision})') 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, project.revision, 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: {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 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)
def do_run(self, args, user_args): for project in self._cloned_projects(args): log.banner( project.format('running "{c}" in {name_and_path}:', c=args.command)) subprocess.Popen(args.command, shell=True, cwd=project.abspath) \ .wait()
def bootstrap(self, args): manifest_url = args.manifest_url or MANIFEST_URL_DEFAULT manifest_rev = args.manifest_rev or MANIFEST_REV_DEFAULT topdir = util.canon_path(args.directory or os.getcwd()) west_dir = join(topdir, WEST_DIR) try: already = util.west_topdir(topdir, fall_back=False) self.die_already(already) except util.WestNotFound: pass log.banner('Initializing in', topdir) if not isdir(topdir): self.create(topdir, exist_ok=False) # Clone the manifest repository into a temporary directory. tempdir = join(west_dir, 'manifest-tmp') if exists(tempdir): log.dbg('removing existing temporary manifest directory', tempdir) shutil.rmtree(tempdir) try: self.clone_manifest(manifest_url, manifest_rev, tempdir) except subprocess.CalledProcessError: shutil.rmtree(tempdir, ignore_errors=True) raise # Verify the manifest file exists. temp_manifest = join(tempdir, 'west.yml') if not exists(temp_manifest): log.die(f'can\'t init: no "west.yml" found in {tempdir}\n' f' Hint: check --manifest-url={manifest_url} and ' '--manifest-rev={manifest_rev}\n' f' You may need to remove {west_dir} before retrying.') # Parse the manifest to get the manifest path, if it declares one. # Otherwise, use the URL. Ignore imports -- all we really # want to know is if there's a "self: path:" or not. projects = Manifest.from_file(temp_manifest, import_flags=ImportFlag.IGNORE, topdir=topdir).projects manifest_project = projects[MANIFEST_PROJECT_INDEX] if manifest_project.path: manifest_path = manifest_project.path else: manifest_path = posixpath.basename(urlparse(manifest_url).path) manifest_abspath = join(topdir, manifest_path) log.dbg('moving', tempdir, 'to', manifest_abspath, level=log.VERBOSE_EXTREME) try: shutil.move(tempdir, manifest_abspath) except shutil.Error as e: log.die(e) log.small_banner('setting manifest.path to', manifest_path) update_config('manifest', 'path', manifest_path, topdir=topdir) return topdir
def do_run(self, args, user_args): failed = [] for project in self._cloned_projects(args): log.banner(f'status of {project.name_and_path}:') try: project.git('status', extra_args=user_args) except subprocess.CalledProcessError: failed.append(project) self._handle_failed(args, failed)
def do_run(self, args, user_args): failed = [] for project in self._cloned_projects(args): log.banner( f'running "{args.subcommand}" in {project.name_and_path}:') rc = subprocess.Popen(args.subcommand, shell=True, cwd=project.abspath).wait() if rc: failed.append(project) self._handle_failed(args, failed)
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 msg = project.format('{name_and_path} outstanding downstream patches:') # 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 msg += ' NOTE: {} *must* be up to date'.format(z_rev) else: z_rev = z_project.revision log.banner(msg) try: nsha = project.sha(project.revision) project.git('cat-file -e ' + nsha) except subprocess.CalledProcessError: log.wrn( "can't get loot; please run \"west update {}\"".format( project.name), '(need revision {})'.format(project.revision)) return try: zsha = z_project.sha(z_project.revision) z_project.git('cat-file -e ' + zsha) except subprocess.CalledProcessError: log.wrn("can't get loot; please fetch upstream URL", z_project.url, '(need revision {})'.format(z_project.revision)) return try: analyzer = nwh.RepoAnalyzer(project, z_project, project.revision, z_rev) except nwh.InvalidRepositoryError as ire: log.die(str(ire)) try: for c in analyzer.downstream_outstanding: if args.files and not nwh.commit_affects_files(c, args.files): log.dbg( 'skipping {}; it does not affect file filter'.format( c.oid), level=log.VERBOSE_VERY) continue if args.sha_only: log.inf(str(c.oid)) else: log.inf('- {} {}'.format(c.oid, nwh.commit_shortlog(c))) except nwh.UnknownCommitsError as uce: log.die('unknown commits:', str(uce))
def do_run(self, args, ignored): failed = [] for project in self._cloned_projects(args): log.banner(project.format('diff for {name_and_path}:')) # Use paths that are relative to the base directory to make it # easier to see where the changes are try: project.git('diff --src-prefix={path}/ --dst-prefix={path}/') except subprocess.CalledProcessError: failed.append(project) self._handle_failed(args, failed)
def install(self, module_path): log.banner('downloading ESP-IDF tools..') if platform.system() == 'Windows': cmd_exec(("python.exe", "tools/idf_tools.py", "--tools-json=tools/zephyr_tools.json", "install"), cwd=module_path) else: cmd_exec(("./tools/idf_tools.py", "--tools-json=tools/zephyr_tools.json", "install"), cwd=module_path) log.banner('downloading ESP-IDF tools completed')
def do_run(self, args, user_args): if args.exclude_west: log.wrn('ignoring --exclude-west') fs = self._fetch_strategy(args) failed = [] for project in self._projects(args.projects): if isinstance(project, ManifestProject): continue log.banner(project.format('updating {name_and_path}:')) try: _update(project, fs, args.rebase, args.keep_descendants) except subprocess.CalledProcessError: failed.append(project) self._handle_failed(args, failed)
def do_run(self, args, unknown_args): self.check_west_version() self.setup_upstream_downstream(args) log.inf('Comparing nrf/west.yml with zephyr/west.yml at revision {}{}'. format(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 zn, zp in self.z_pmap.items(): nn = self.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.small_banner(p.format('{name_and_path}')) if missing_blacklisted and log.VERBOSE >= log.VERBOSE_NORMAL: log.banner('blacklisted but missing in NCS (these are all OK):') print_lst(missing_blacklisted) if present_blacklisted: log.banner('blacklisted upstream projects that are in NCS:') log.wrn('these names should be removed from nrf/west.yml') print_lst(present_blacklisted) if missing_allowed: log.banner('non-blacklisted upstream projects missing in NCS:') log.wrn('these should be blacklisted or added to nrf/west.yml') for p in missing_allowed: log.small_banner(p.format('{name_and_path}')) log.inf(p.format('upstream revision: {revision}')) log.inf(p.format('upstream URL: {url}')) if present_allowed: log.banner('projects present in NCS:') for zp in present_allowed: # Do some extra checking on unmerged commits. self.allowed_project(zp)
def bootstrap(self, args): manifest_url = args.manifest_url or MANIFEST_URL_DEFAULT manifest_rev = args.manifest_rev or MANIFEST_REV_DEFAULT topdir = util.canon_path(args.directory or os.getcwd()) west_dir = join(topdir, WEST_DIR) log.banner('Initializing in', topdir) if not isdir(topdir): self.create(topdir, exist_ok=False) os.chdir(topdir) # Clone the manifest repository into a temporary directory. It's # important that west_dir exists and we're under topdir, or we # won't be able to call self.projects() without error later. tempdir = join(west_dir, 'manifest-tmp') if exists(tempdir): log.dbg('removing existing temporary manifest directory', tempdir) shutil.rmtree(tempdir) try: self.clone_manifest(manifest_url, manifest_rev, tempdir) temp_manifest_file = join(tempdir, 'west.yml') if not exists(temp_manifest_file): log.die('No "west.yml" in manifest repository ({})'.format( tempdir)) projects = self.projects(temp_manifest_file) manifest_project = projects[MANIFEST_PROJECT_INDEX] if manifest_project.path: manifest_path = manifest_project.path manifest_abspath = join(topdir, manifest_path) else: url_path = urlparse(manifest_url).path manifest_path = posixpath.basename(url_path) manifest_abspath = join(topdir, manifest_path) shutil.move(tempdir, manifest_abspath) update_config('manifest', 'path', manifest_path) finally: shutil.rmtree(tempdir, ignore_errors=True) self.topdir = topdir return projects, manifest_project.abspath
def local(self, args): if args.manifest_rev is not None: log.die('--mr cannot be used with -l') manifest_dir = util.canon_path(args.directory or os.getcwd()) manifest_file = join(manifest_dir, 'west.yml') topdir = dirname(manifest_dir) rel_manifest = basename(manifest_dir) west_dir = os.path.join(topdir, WEST_DIR) if not exists(manifest_file): log.die(f'can\'t init: no "west.yml" found in {manifest_dir}') log.banner('Initializing from existing manifest repository', rel_manifest) log.small_banner(f'Creating {west_dir} and local configuration file') self.create(west_dir) os.chdir(topdir) update_config('manifest', 'path', rel_manifest) return topdir
def do_run(self, args, ignored): if self.topdir: zb = os.environ.get('ZEPHYR_BASE') if zb: msg = textwrap.dedent(''' Note: In your environment, ZEPHYR_BASE is set to: {} This forces west to search for an installation there. Try unsetting ZEPHYR_BASE and re-running this command.'''. format(zb)) else: msg = '' log.die('already initialized in {}, aborting.{}'.format( self.topdir, msg)) if args.local and (args.manifest_url or args.manifest_rev): log.die('-l cannot be combined with -m or --mr') if shutil.which('git') is None: log.die("can't find git; install it or ensure it's on your PATH") # west.manifest will try to read manifest.path and use it when # parsing the manifest. Clear it out for now so we can parse # the manifest without it; local() or bootstrap() will set it # properly. if config.get('manifest', 'path', fallback=None) is not None: config.remove_option('manifest', 'path') if args.local: projects, manifest_dir = self.local(args) else: projects, manifest_dir = self.bootstrap(args) self.fixup_zephyr_base(projects) log.banner('Initialized. Now run "west update" inside {}.'.format( self.topdir))
def update(self, module_path): log.banner('updating ESP-IDF submodules..') # look for origin remote remote_name = cmd_check(("git", "remote"), cwd=module_path).decode('utf-8') if "origin" not in remote_name: # add origin url cmd_exec(("git", "remote", "add", "origin", ESP_IDF_REMOTE), cwd=module_path) else: remote_url = cmd_check(("git", "remote", "get-url", "origin"), cwd=module_path).decode('utf-8') # update origin URL if ESP_IDF_REMOTE not in remote_url: cmd_exec( ("git", "remote", "set-url", "origin", ESP_IDF_REMOTE), cwd=module_path) cmd_exec(("git", "submodule", "update", "--init", "--recursive"), cwd=module_path) log.banner('updating ESP-IDF submodules completed')
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 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 run_command(self, argv): # Parse command line arguments and run the WestCommand. # If we're running an extension, instantiate it from its # spec and re-parse arguments before running. args, unknown = self.west_parser.parse_known_args(args=argv) # Set up logging verbosity before running the command, so e.g. # verbose messages related to argument handling errors work # properly. self.setup_logging(args) log.set_verbosity(args.verbose) log.dbg('args namespace:', args, level=log.VERBOSE_EXTREME) # If we were run as 'west -h ...' or 'west --help ...', # monkeypatch the args namespace so we end up running Help. The # user might have also provided a command. If so, print help about # that command. if args.help or args.command is None: args.command_name = args.command args.command = 'help' # Finally, run the command. try: if args.command in self.builtins: if self.mle: self.handle_builtin_manifest_load_err(args) cmd = self.builtins.get(args.command, self.builtins['help']) cmd.run(args, unknown, self.topdir, manifest=self.manifest) else: self.run_extension(args.command, argv) except KeyboardInterrupt: sys.exit(0) except BrokenPipeError: sys.exit(0) except CalledProcessError as cpe: log.err( f'command exited with status {cpe.returncode}: ' f'{quote_sh_list(cpe.cmd)}', fatal=True) if args.verbose >= log.VERBOSE_EXTREME: log.banner('Traceback (enabled by -vvv):') traceback.print_exc() sys.exit(cpe.returncode) except ExtensionCommandError as ece: msg = f"extension command \"{args.command}\" couldn't be run" if ece.hint: msg += '\n Hint: ' + ece.hint if args.verbose >= log.VERBOSE_EXTREME: log.err(msg, fatal=True) log.banner('Traceback (enabled by -vvv):') traceback.print_exc() else: tb_file = dump_traceback() msg += f'\n See {tb_file} for a traceback.' log.err(msg, fatal=True) sys.exit(ece.returncode) except CommandError as ce: # No need to dump_traceback() here. The command is responsible # for logging its own errors. sys.exit(ce.returncode)
def do_run(self, args, unknown_args): check_west_version() self.setup_upstream_downstream(args) log.inf('Comparing nrf/west.yml with zephyr/west.yml at revision ' f'{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.small_banner(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 nrf:') if present_blacklisted: log.wrn('these should all be removed from nrf') print_lst(present_blacklisted) else: log.inf('none (OK)') log.banner('non-blacklisted zephyr projects', 'missing from nrf:') if missing_allowed: log.wrn('these should be blacklisted or added to nrf') 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 nrf:') 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 update(self, project): log.banner(f'updating {project.name_and_path}:') if not project.is_cloned(): _clone(project) if self.fs == 'always' or _rev_type(project) not in ('tag', 'commit'): _fetch(project) else: log.dbg('skipping unnecessary fetch') _update_manifest_rev(project, f'{project.revision}^{{commit}}') # Head of manifest-rev is now pointing to current manifest revision. # Thus it is safe to unconditionally clear out the refs/west space. # # Doing this here instead of in _fetch() ensures that it gets cleaned # up when users upgrade from older versions of west (like 0.6.x) that # didn't handle this properly. # In future, this can be moved into _fetch() after the install base of # older west versions is expected to be smaller. _clean_west_refspace(project) if not _head_ok(project): # If nothing is checked out (which usually only happens if we # called _clone(project) above), check out 'manifest-rev' in a # detached HEAD state. # # Otherwise, the initial state would have nothing checked out, # and HEAD would point to a non-existent refs/heads/master # branch (that would get created if the user makes an initial # commit). Among other things, this ensures the rev-parse # --abbrev-ref HEAD below will always succeed. # # The --detach flag is strictly redundant here, because # the refs/heads/<branch> form already detaches HEAD, but # it avoids a spammy detached HEAD warning from Git. project.git('checkout --detach ' + QUAL_MANIFEST_REV) try: sha = project.sha(QUAL_MANIFEST_REV) except subprocess.CalledProcessError: # This is a sign something's really wrong. Add more help. log.err(f'no SHA for branch {MANIFEST_REV} ' f'in {project.name_and_path}; was the branch deleted?') raise cp = project.git('rev-parse --abbrev-ref HEAD', capture_stdout=True) current_branch = cp.stdout.decode('utf-8').strip() if current_branch != 'HEAD': is_ancestor = project.is_ancestor_of(sha, current_branch) try_rebase = self.args.rebase else: # HEAD means no branch is checked out. # If no branch is checked out, 'rebase' and # 'keep_descendants' don't matter. is_ancestor = False try_rebase = False if self.args.keep_descendants and is_ancestor: # A descendant is currently checked out and keep_descendants was # given, so there's nothing more to do. log.small_banner(f'{project.name}: left descendant branch ' f'"{current_branch}" checked out') elif try_rebase: # Attempt a rebase. log.small_banner(f'{project.name}: rebasing to {MANIFEST_REV}') project.git('rebase ' + QUAL_MANIFEST_REV) else: # We can't keep a descendant or rebase, so just check # out the new detached HEAD, then print some helpful context. project.git('checkout --detach --quiet ' + sha) log.small_banner( f'{project.name}: checked out {sha} as detached HEAD') _post_checkout_help(project, current_branch, sha, is_ancestor)
def do_run(self, args, ignored): for project in self._cloned_projects(args): log.banner(project.format('diff for {name_and_path}:')) # Use paths that are relative to the base directory to make it # easier to see where the changes are _git(project, 'diff --src-prefix={path}/ --dst-prefix={path}/')
def do_run(self, args, user_args): for project in self._cloned_projects(args): log.banner(project.format('status of {name_and_path}:')) _git(project, 'status', extra_args=user_args)