Example #1
0
    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}.')
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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)}')
Example #6
0
    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)
Example #7
0
    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()
Example #8
0
    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
Example #9
0
 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)
Example #10
0
 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)
Example #11
0
    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))
Example #12
0
 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)
Example #13
0
    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')
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
    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
Example #17
0
    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
Example #18
0
    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))
Example #19
0
    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')
Example #20
0
    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)
Example #21
0
    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.')
Example #22
0
    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)
Example #23
0
    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.')
Example #24
0
    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)
Example #25
0
 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}/')
Example #26
0
 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)