Esempio n. 1
0
 def check_call(self, args, cwd=None):
     cmd_str = util.quote_sh_list(args)
     log.dbg("running '{}'".format(cmd_str),
             'in',
             cwd or os.getcwd(),
             level=log.VERBOSE_VERY)
     subprocess.check_call(args, cwd=cwd)
    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)}')
Esempio n. 3
0
    def _setup_build_dir(self):
        # Initialize build_dir and created_build_dir attributes.
        # If we created the build directory, we must run CMake.
        log.dbg('setting up build directory', level=log.VERBOSE_EXTREME)
        # The CMake Cache has not been loaded yet, so this is safe
        board, _ = self._find_board()
        source_dir = self._find_source_dir()
        app = os.path.split(source_dir)[1]
        build_dir = find_build_dir(self.args.build_dir,
                                   board=board,
                                   source_dir=source_dir,
                                   app=app)
        if not build_dir:
            log.die('Unable to determine a default build folder. Check '
                    'your build.dir-fmt configuration option')

        if os.path.exists(build_dir):
            if not os.path.isdir(build_dir):
                log.die(
                    'build directory {} exists and is not a directory'.format(
                        build_dir))
        else:
            os.makedirs(build_dir, exist_ok=False)
            self.created_build_dir = True
            self.run_cmake = True

        self.build_dir = build_dir
Esempio n. 4
0
    def do_run(self, command, **kwargs):
        reset = False
        if not self.find_device():
            reset = True
            log.dbg('Device not found, waiting for it',
                    level=log.VERBOSE_EXTREME)
            # Use of print() here is advised. We don't want to lose
            # this information in a separate log -- this is
            # interactive and requires a terminal.
            print('Please reset your board to switch to DFU mode...')
            while not self.find_device():
                time.sleep(0.1)

        cmd = list(self.cmd)
        if self.dfuse:
            # http://dfu-util.sourceforge.net/dfuse.html
            dcfg = self.dfuse_config
            addr_opts = hex(dcfg.address) + ':' + dcfg.options
            cmd.extend(['-s', addr_opts])
        cmd.extend(['-a', self.alt, '-D', self.img])
        self.check_call(cmd)

        if self.dfuse and 'leave' in dcfg.options.split(':'):
            # Normal DFU devices generally need to be reset to switch
            # back to the flashed program.
            #
            # DfuSe targets do as well, except when 'leave' is given
            # as an option.
            reset = False
        if reset:
            print('Now reset your board again to switch back to runtime mode.')
Esempio n. 5
0
    def edt_flash_node(b, cache):
        # Get the EDT Node corresponding to the zephyr,flash chosen DT
        # node.

        # Retrieve the list of devicetree bindings from cache.
        try:
            bindings = cache.get_list('CACHED_DTS_ROOT_BINDINGS')
            log.dbg('DTS bindings:', bindings, level=log.VERBOSE_VERY)
        except KeyError:
            log.die('CMake cache has no CACHED_DTS_ROOT_BINDINGS.'
                    '\n  Try again after re-building your application.')

        # Ensure the build directory has a compiled DTS file
        # where we expect it to be.
        dts = b / 'zephyr' / (cache['CACHED_BOARD'] + '.dts.pre.tmp')
        if not dts.is_file():
            log.die("can't find DTS; expected:", dts)
        log.dbg('DTS file:', dts, level=log.VERBOSE_VERY)

        # Parse the devicetree using bindings from cache.
        try:
            edt = edtlib.EDT(dts, bindings)
        except edtlib.EDTError as e:
            log.die("can't parse devicetree:", e)

        # By convention, the zephyr,flash chosen node contains the
        # partition information about the zephyr image to sign.
        flash = edt.chosen_node('zephyr,flash')
        if not flash:
            log.die('devicetree has no chosen zephyr,flash node;',
                    "can't infer flash write block or image-0 slot sizes")

        return flash
Esempio n. 6
0
    def get_board_snr_from_user(self):
        snrs = self.check_output(['nrfjprog', '--ids'])
        snrs = snrs.decode(sys.getdefaultencoding()).strip().splitlines()

        if len(snrs) == 0:
            raise RuntimeError('"nrfjprog --ids" did not find a board; Is the board connected?')
        elif len(snrs) == 1:
            board_snr = snrs[0]
            if board_snr == '0':
                raise RuntimeError('"nrfjprog --ids" returned 0; is a debugger already connected?')
            return board_snr

        log.dbg("Refusing the temptation to guess a board",
                level=log.VERBOSE_EXTREME)

        # Use of print() here is advised. We don't want to lose
        # this information in a separate log -- this is
        # interactive and requires a terminal.
        print('There are multiple boards connected.')
        for i, snr in enumerate(snrs, 1):
            print('{}. {}'.format(i, snr))

        p = 'Please select one with desired serial number (1-{}): '.format(
                len(snrs))
        while True:
            value = input(p)
            try:
                value = int(value)
            except ValueError:
                continue
            if 1 <= value <= len(snrs):
                break

        return snrs[value - 1]
Esempio n. 7
0
def find_build_dir(dir, **kwargs):
    '''Heuristic for finding a build directory.

    The default build directory is computed by reading the build.dir-fmt
    configuration option, defaulting to DEFAULT_BUILD_DIR if not set. It might
    be None if the build.dir-fmt configuration option is set but cannot be
    resolved.
    If the given argument is truthy, it is returned. Otherwise, if
    the default build folder is a build directory, it is returned.
    Next, if the current working directory is a build directory, it is
    returned. Finally, the default build directory is returned (may be None).
    '''

    if dir:
        build_dir = dir
    else:
        cwd = os.getcwd()
        default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR)
        try:
            default = _resolve_build_dir(default, cwd, **kwargs)
            log.dbg('config dir-fmt: {}'.format(default),
                    level=log.VERBOSE_EXTREME)
        except KeyError:
            default = None
        if default and is_zephyr_build(default):
            build_dir = default
        elif is_zephyr_build(cwd):
            build_dir = cwd
        else:
            build_dir = default
    log.dbg('build dir: {}'.format(build_dir), level=log.VERBOSE_EXTREME)
    if build_dir:
        return os.path.abspath(build_dir)
    else:
        return None
Esempio n. 8
0
def getExpressionData(filePath, numLines):
    """
    Scans the specified file for the first SPDX-License-Identifier:
    tag in the file.

    Arguments:
        - filePath: path to file to scan.
        - numLines: number of lines to scan for an expression before
                    giving up. If 0, will scan the entire file.
    Returns: parsed expression if found; None if not found.
    """
    log.dbg(f"  - getting licenses for {filePath}")

    with open(filePath, "r") as f:
        try:
            lineno = 0
            for line in f:
                lineno += 1
                if lineno > numLines > 0:
                    break
                expression = parseLineForExpression(line)
                if expression is not None:
                    return expression
        except UnicodeDecodeError:
            # invalid UTF-8 content
            return None

    # if we get here, we didn't find an expression
    return None
Esempio n. 9
0
    def do_run(self, args, ignored):
        self.args = args        # Avoid having to pass them around
        log.dbg('args:', args, level=log.VERBOSE_EXTREME)
        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)
Esempio n. 10
0
def run_cmake(args, cwd=None, capture_output=False):
    '''Run cmake to (re)generate a build system.
    If capture_output is set to True, returns the output of the command instead
    of displaying it on stdout/stderr..'''
    cmake = shutil.which('cmake')
    if cmake is None:
        log.die('CMake is not installed or cannot be found; cannot build.')
    cmd = [cmake] + args
    kwargs = dict()
    if capture_output:
        kwargs['stdout'] = subprocess.PIPE
        # CMake sends the output of message() to stderr unless it's STATUS
        kwargs['stderr'] = subprocess.STDOUT
    if cwd:
        kwargs['cwd'] = cwd
    log.dbg('Running CMake:', quote_sh_list(cmd), level=log.VERBOSE_NORMAL)
    p = subprocess.Popen(cmd, **kwargs)
    out, err = p.communicate()
    if p.returncode == 0:
        if out:
            return out.decode(sys.getdefaultencoding()).splitlines()
        else:
            return None
    else:
        # A real error occurred, raise an exception
        raise subprocess.CalledProcessError(p.returncode, p.args)
Esempio n. 11
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)
Esempio n. 12
0
    def create(cls, cfg, args):
        daparg = os.environ.get('PYOCD_DAPARG')
        if daparg:
            log.wrn('Setting PYOCD_DAPARG in the environment is',
                    'deprecated; use the --daparg option instead.')
            if args.daparg is None:
                log.dbg('Missing --daparg set to {} from environment'.format(
                    daparg),
                        level=log.VERBOSE_VERY)
                args.daparg = daparg

        build_conf = BuildConfiguration(cfg.build_dir)
        flash_addr = cls.get_flash_address(args, build_conf)

        return PyOcdBinaryRunner(cfg,
                                 args.target,
                                 flashtool=args.flashtool,
                                 flash_addr=flash_addr,
                                 flashtool_opts=args.flashtool_opt,
                                 gdbserver=args.gdbserver,
                                 gdb_port=args.gdb_port,
                                 tui=args.tui,
                                 board_id=args.board_id,
                                 daparg=args.daparg,
                                 frequency=args.frequency)
Esempio n. 13
0
    def getCodemodel(self):
        log.dbg("getting codemodel from CMake API reply files")

        # make sure the reply directory exists
        cmakeReplyDirPath = os.path.join(self.cfg.buildDir, ".cmake", "api",
                                         "v1", "reply")
        if not os.path.exists(cmakeReplyDirPath):
            log.err(
                f'cmake api reply directory {cmakeReplyDirPath} does not exist'
            )
            log.err('was query directory created before cmake build ran?')
            return None
        if not os.path.isdir(cmakeReplyDirPath):
            log.err(
                f'cmake api reply directory {cmakeReplyDirPath} exists but is not a directory'
            )
            return None

        # find file with "index" prefix; there should only be one
        indexFilePath = ""
        for f in os.listdir(cmakeReplyDirPath):
            if f.startswith("index"):
                indexFilePath = os.path.join(cmakeReplyDirPath, f)
                break
        if indexFilePath == "":
            # didn't find it
            log.err(
                f'cmake api reply index file not found in {cmakeReplyDirPath}')
            return None

        # parse it
        return parseReply(indexFilePath)
Esempio n. 14
0
def parseCMakeCacheFile(filePath):
    log.dbg(f"parsing CMake cache file at {filePath}")
    kv = {}
    try:
        with open(filePath, "r") as f:
            # should be a short file, so we'll use readlines
            lines = f.readlines()

            # walk through and look for non-comment, non-empty lines
            for line in lines:
                sline = line.strip()
                if sline == "":
                    continue
                if sline.startswith("#") or sline.startswith("//"):
                    continue

                # parse out : and = characters
                pline1 = sline.split(":", maxsplit=1)
                if len(pline1) != 2:
                    continue
                pline2 = pline1[1].split("=", maxsplit=1)
                if len(pline2) != 2:
                    continue
                kv[pline1[0]] = pline2[1]

            return kv

    except OSError as e:
        log.err(f"Error loading {filePath}: {str(e)}")
        return {}
Esempio n. 15
0
def _ensure_min_version(cmake, dry_run):
    cmd = [cmake, '--version']
    if dry_run:
        log.inf('Dry run:', quote_sh_list(cmd))
        return

    try:
        version_out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
    except subprocess.CalledProcessError as cpe:
        log.die('cannot get cmake version:', str(cpe))
    decoded = version_out.decode('utf-8')
    lines = decoded.splitlines()
    if not lines:
        log.die('can\'t get cmake version: ' +
                'unexpected "cmake --version" output:\n{}\n'.format(decoded) +
                'Please install CMake ' + _MIN_CMAKE_VERSION_STR +
                ' or higher (https://cmake.org/download/).')
    version = lines[0].split()[2]
    if '-' in version:
        # Handle semver cases like "3.19.20210206-g1e50ab6"
        # which Kitware uses for prerelease versions.
        version = version.split('-', 1)[0]
    if packaging.version.parse(version) < _MIN_CMAKE_VERSION:
        log.die(
            'cmake version', version,
            'is less than minimum version {};'.format(_MIN_CMAKE_VERSION_STR),
            'please update your CMake (https://cmake.org/download/).')
    else:
        log.dbg('cmake version', version, 'is OK; minimum version is',
                _MIN_CMAKE_VERSION_STR)
Esempio n. 16
0
def getHashes(filePath):
    """
    Scan for and return hashes.

    Arguments:
        - filePath: path to file to scan.
    Returns: tuple of (SHA1, SHA256, MD5) hashes for filePath, or
             None if file is not found.
    """
    hSHA1 = hashlib.sha1()
    hSHA256 = hashlib.sha256()
    hMD5 = hashlib.md5()

    log.dbg(f"  - getting hashes for {filePath}")

    try:
        with open(filePath, 'rb') as f:
            buf = f.read()
            hSHA1.update(buf)
            hSHA256.update(buf)
            hMD5.update(buf)
    except OSError:
        return None

    return (hSHA1.hexdigest(), hSHA256.hexdigest(), hMD5.hexdigest())
Esempio n. 17
0
def getCIncludes(compilerPath, srcFile, tcg):
    log.dbg(f"    - getting includes for {srcFile}")

    # prepare fragments
    fragments = [fr for fr in tcg.compileCommandFragments if fr.strip() != ""]

    # prepare include arguments
    includes = ["-I" + incl.path for incl in tcg.includes]

    # prepare defines
    defines = ["-D" + d.define for d in tcg.defines]

    # prepare command invocation
    cmd = [compilerPath, "-E", "-H"
           ] + fragments + includes + defines + [srcFile]

    cp = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
    if cp.returncode != 0:
        log.dbg(
            f"    - calling {compilerPath} failed with error code {cp.returncode}"
        )
        return []
    else:
        # response will be in cp.stderr, not cp.stdout
        return extractIncludes(cp.stderr)
Esempio n. 18
0
    def edt_flash_node(b, quiet=False):
        # Get the EDT Node corresponding to the zephyr,flash chosen DT
        # node; 'b' is the build directory as a pathlib object.

        # Ensure the build directory has a compiled DTS file
        # where we expect it to be.
        dts = b / 'zephyr' / 'zephyr.dts'
        if not quiet:
            log.dbg('DTS file:', dts, level=log.VERBOSE_VERY)
        edt_pickle = b / 'zephyr' / 'edt.pickle'
        if not edt_pickle.is_file():
            log.die("can't load devicetree; expected to find:", edt_pickle)

        # Load the devicetree.
        with open(edt_pickle, 'rb') as f:
            edt = pickle.load(f)

        # By convention, the zephyr,flash chosen node contains the
        # partition information about the zephyr image to sign.
        flash = edt.chosen_node('zephyr,flash')
        if not flash:
            log.die('devicetree has no chosen zephyr,flash node;',
                    "can't infer flash write block or image-0 slot sizes")

        return flash
Esempio n. 19
0
def _post_checkout_help(project, branch, sha, is_ancestor):
    # Print helpful information to the user about a project that
    # might have just left a branch behind.

    if branch is None:
        # If there was no branch checked out, there are no
        # additional diagnostics that need emitting.
        return

    rel = relpath(project.abspath)
    if is_ancestor:
        # If the branch we just left behind is a descendant of
        # the new HEAD (e.g. if this is a topic branch the
        # user is working on and the remote hasn't changed),
        # print a message that makes it easy to get back,
        # no matter where in the installation os.getcwd() is.
        log.wrn(project.format(
            'left behind {name} branch "{b}"; to switch '
            'back to it (fast forward), use: git -C {rp} checkout {b}',
            b=branch, rp=rel))
        log.dbg('(To do this automatically in the future,',
                'use "west update --keep-descendants".)')
    else:
        # Tell the user how they could rebase by hand, and
        # point them at west update --rebase.
        log.wrn(project.format(
            'left behind {name} branch "{b}"; '
            'to rebase onto the new HEAD: git -C {rp} rebase {sh} {b}',
            b=branch, rp=rel, sh=sha))
        log.dbg('(To do this automatically in the future,',
                'use "west update --rebase".)')
Esempio n. 20
0
def is_zephyr_build(path):
    '''Return true if and only if `path` appears to be a valid Zephyr
    build directory.

    "Valid" means the given path is a directory which contains a CMake
    cache with a 'ZEPHYR_BASE' or 'ZEPHYR_TOOLCHAIN_VARIANT' variable.

    (The check for ZEPHYR_BASE introduced sometime after Zephyr 2.4 to
    fix https://github.com/zephyrproject-rtos/zephyr/issues/28876; we
    keep support for the second variable around for compatibility with
    versions 2.2 and earlier, which didn't have ZEPHYR_BASE in cache.
    The cached ZEPHYR_BASE was added in
    https://github.com/zephyrproject-rtos/zephyr/pull/23054.)
    '''
    try:
        cache = zcmake.CMakeCache.from_build_dir(path)
    except FileNotFoundError:
        cache = {}

    if 'ZEPHYR_BASE' in cache or 'ZEPHYR_TOOLCHAIN_VARIANT' in cache:
        log.dbg(f'{path} is a zephyr build directory',
                level=log.VERBOSE_EXTREME)
        return True

    log.dbg(f'{path} is NOT a valid zephyr build directory',
            level=log.VERBOSE_EXTREME)
    return False
Esempio n. 21
0
    def flash(self, **kwargs):
        self.check_cmd(self.commander)
        if self.bin_name is None:
            raise ValueError('Cannot flash; bin_name is missing')

        lines = ['r'] # Reset and halt the target

        if self.erase:
            lines.append('erase') # Erase all flash sectors

        lines.append('loadfile {} 0x{:x}'.format(self.bin_name,
                                                 self.flash_addr))
        lines.append('g') # Start the CPU
        lines.append('q') # Close the connection and quit

        log.dbg('JLink commander script:')
        log.dbg('\n'.join(lines))

        # Don't use NamedTemporaryFile: the resulting file can't be
        # opened again on Windows.
        with tempfile.TemporaryDirectory(suffix='jlink') as d:
            fname = os.path.join(d, 'runner.jlink')
            with open(fname, 'wb') as f:
                f.writelines(bytes(line + '\n', 'utf-8') for line in lines)

            cmd = ([self.commander] +
                   ['-if', self.iface,
                    '-speed', self.speed,
                    '-device', self.device,
                    '-CommanderScript', fname])

            log.inf('Flashing Target Device')
            self.check_call(cmd)
Esempio n. 22
0
    def check_output(args, cwd=None):
        '''Runs subprocess.check_output(args, cwd=cwd) after
        logging the call at VERBOSE_VERY level.'''

        cmd_str = quote_sh_list(args)
        log.dbg(f"running '{cmd_str}' in {cwd or os.getcwd()}",
                level=log.VERBOSE_VERY)
        return subprocess.check_output(args, cwd=cwd)
Esempio n. 23
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
Esempio n. 24
0
    def git(self, cmd, extra_args=(), capture_stdout=False,
            capture_stderr=False, check=True, cwd=None):
        '''Helper for running a git command using metadata from a Project
        instance.

        :param cmd: git command as a string (or list of strings); all strings
                    are formatted using self.format() before use.
        :param extra_args: sequence of additional arguments to pass to the git
                           command (useful mostly if cmd is a string).
        :param capture_stdout: True if stdout should be captured into the
                               returned object instead of being printed.
        :param capture_stderr: Like capture_stdout, but for stderr. Use with
                               caution as it prevents error messages from being
                               shown to the user.
        :param check: True if a subprocess.CalledProcessError should be raised
                      if the git command finishes with a non-zero return code.
        :param cwd: directory to run command in (default: self.abspath)

        Returns a CompletedProcess (which is back-ported for Python 3.4).'''
        _warn_once_if_no_git()

        if isinstance(cmd, str):
            cmd_list = shlex.split(cmd)
        else:
            cmd_list = list(cmd)

        extra_args = list(extra_args)

        if cwd is None:
            cwd = self.abspath

        args = ['git'] + [self.format(arg) for arg in cmd_list] + extra_args
        cmd_str = util.quote_sh_list(args)

        log.dbg("running '{}'".format(cmd_str), 'in', cwd,
                level=log.VERBOSE_VERY)
        popen = subprocess.Popen(
            args, cwd=cwd,
            stdout=subprocess.PIPE if capture_stdout else None,
            stderr=subprocess.PIPE if capture_stderr else None)

        stdout, stderr = popen.communicate()

        dbg_msg = "'{}' in {} finished with exit status {}".format(
            cmd_str, cwd, popen.returncode)
        if capture_stdout:
            dbg_msg += " and wrote {} to stdout".format(stdout)
        if capture_stderr:
            dbg_msg += " and wrote {} to stderr".format(stderr)
        log.dbg(dbg_msg, level=log.VERBOSE_VERY)

        if check and popen.returncode:
            raise subprocess.CalledProcessError(popen.returncode, cmd_list,
                                                output=stdout, stderr=stderr)
        else:
            return CompletedProcess(popen.args, popen.returncode,
                                    stdout, stderr)
Esempio n. 25
0
 def read(self, args):
     section, key = self._sk(args)
     cfg = configparser.ConfigParser()
     read_config(configfile=args.configfile or ALL, config=cfg)
     value = cfg.get(section, key, fallback=None)
     if value is not None:
         log.inf(value)
     else:
         log.dbg(f'{args.name} is unset')
         raise CommandError(returncode=1)
Esempio n. 26
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))
Esempio n. 27
0
    def collectTargetDependencies(self, cfgTargets, cfgTarget, pkg):
        log.dbg(f"  - collecting target dependencies for {pkg.cfg.name}")

        # walk through target's dependencies
        for dep in cfgTarget.target.dependencies:
            # extract dep name from its id
            depFragments = dep.id.split(":")
            depName = depFragments[0]
            log.dbg(f"    - adding pending relationship for {depName}")

            # create relationship data between dependency packages
            rd = RelationshipData()
            rd.ownerType = RelationshipDataElementType.TARGETNAME
            rd.ownerTargetName = pkg.cfg.name
            rd.otherType = RelationshipDataElementType.TARGETNAME
            rd.otherTargetName = depName
            rd.rlnType = "HAS_PREREQUISITE"

            # add it to pending relationships queue
            self.pendingRelationships.append(rd)

            # if this is a target with any build artifacts (e.g. non-UTILITY),
            # also create STATIC_LINK relationship for dependency build files,
            # together with this Package's own target build file
            if len(cfgTarget.target.artifacts) == 0:
                continue

            # find the filename for the dependency's build product, using the
            # codemodel (since we might not have created this dependency's
            # Package or File yet)
            depAbspath = ""
            for ct in cfgTargets:
                if ct.name == depName:
                    # skip utility targets
                    if len(ct.target.artifacts) == 0:
                        continue
                    # all targets use the same relativeBaseDir, so this works
                    # even though pkg is the owner package
                    depAbspath = os.path.join(pkg.cfg.relativeBaseDir,
                                              ct.target.artifacts[0])
                    break
            if depAbspath == "":
                continue

            # create relationship data between build files
            rd = RelationshipData()
            rd.ownerType = RelationshipDataElementType.FILENAME
            rd.ownerFileAbspath = pkg.targetBuildFile.abspath
            rd.otherType = RelationshipDataElementType.FILENAME
            rd.otherFileAbspath = depAbspath
            rd.rlnType = "STATIC_LINK"

            # add it to pending relationships queue
            self.pendingRelationships.append(rd)
Esempio n. 28
0
def set_zephyr_base(args):
    '''Ensure ZEPHYR_BASE is set, emitting warnings if that's not
    possible, or if the user is pointing it somewhere different than
    what the manifest expects.'''
    zb_env = os.environ.get('ZEPHYR_BASE')

    if args.zephyr_base:
        # The command line --zephyr-base takes precedence over
        # everything else.
        zb = os.path.abspath(args.zephyr_base)
        zb_origin = 'command line'
    else:
        # If the user doesn't specify it concretely, use the project
        # with path 'zephyr' if that exists, or the ZEPHYR_BASE value
        # in the calling environment.
        #
        # At some point, we need a more flexible way to set environment
        # variables based on manifest contents, but this is good enough
        # to get started with and to ask for wider testing.
        try:
            manifest = Manifest.from_file()
        except MalformedConfig as e:
            log.die('Parsing of manifest file failed during command',
                    args.command, ':', *e.args)
        for project in manifest.projects:
            if project.path == 'zephyr':
                zb = project.abspath
                zb_origin = 'manifest file {}'.format(manifest.path)
                break
        else:
            if zb_env is None:
                log.wrn('no --zephyr-base given, ZEPHYR_BASE is unset,',
                        'and no manifest project has path "zephyr"')
                zb = None
                zb_origin = None
            else:
                zb = zb_env
                zb_origin = 'environment'

    if zb_env and os.path.abspath(zb) != os.path.abspath(zb_env):
        # The environment ZEPHYR_BASE takes precedence over either the
        # command line or the manifest, but in normal multi-repo
        # operation we shouldn't expect to need to set ZEPHYR_BASE to
        # point to some random place. In practice, this is probably
        # happening because zephyr-env.sh/cmd was run in some other
        # zephyr installation, and the user forgot about that.
        log.wrn('ZEPHYR_BASE={}'.format(zb_env),
                'in the calling environment, but has been set to', zb,
                'instead by the', zb_origin)

    os.environ['ZEPHYR_BASE'] = zb

    log.dbg('ZEPHYR_BASE={} (origin: {})'.format(zb, zb_origin))
Esempio n. 29
0
def run_cmake(args, quiet=False):
    '''Run cmake to (re)generate a build system'''
    cmake = shutil.which('cmake')
    if cmake is None:
        log.die('CMake is not installed or cannot be found; cannot build.')
    cmd = [cmake] + args
    kwargs = dict()
    if quiet:
        kwargs['stdout'] = subprocess.DEVNULL
        kwargs['stderr'] = subprocess.STDOUT
    log.dbg('Running CMake:', cmd, level=log.VERBOSE_VERY)
    log.dbg('As command:', quote_sh_list(cmd), level=log.VERBOSE_VERY)
    subprocess.check_call(cmd, **kwargs)
Esempio n. 30
0
    def do_run(self, args, ignored):
        self.args = args        # for check_force

        # Find the build directory and parse .config and DT.
        build_dir = find_build_dir(args.build_dir)
        self.check_force(os.path.isdir(build_dir),
                         'no such build directory {}'.format(build_dir))
        self.check_force(is_zephyr_build(build_dir),
                         "build directory {} doesn't look like a Zephyr build "
                         'directory'.format(build_dir))
        bcfg = BuildConfiguration(build_dir)

        # Decide on output formats.
        formats = []
        bin_exists = 'CONFIG_BUILD_OUTPUT_BIN' in bcfg
        if args.gen_bin:
            self.check_force(bin_exists,
                             '--bin given but CONFIG_BUILD_OUTPUT_BIN not set '
                             "in build directory's ({}) .config".
                             format(build_dir))
            formats.append('bin')
        elif args.gen_bin is None and bin_exists:
            formats.append('bin')

        hex_exists = 'CONFIG_BUILD_OUTPUT_HEX' in bcfg
        if args.gen_hex:
            self.check_force(hex_exists,

                             '--hex given but CONFIG_BUILD_OUTPUT_HEX not set '
                             "in build directory's ({}) .config".
                             format(build_dir))
            formats.append('hex')
        elif args.gen_hex is None and hex_exists:
            formats.append('hex')

        if not formats:
            if not args.quiet:
                log.dbg('nothing to do: no output files')
            return

        # Delegate to the signer.
        if args.tool == 'imgtool':
            signer = ImgtoolSigner()
        elif args.tool == 'rimage':
            signer = RimageSigner()
        # (Add support for other signers here in elif blocks)
        else:
            raise RuntimeError("can't happen")

        signer.sign(self, build_dir, bcfg, formats)