Ejemplo n.º 1
0
def runqemu(args, config, basepath, workspace):
    """Entry point for the devtool 'runqemu' subcommand"""

    tinfoil = setup_tinfoil(config_only=True, basepath=basepath)
    machine = tinfoil.config_data.getVar('MACHINE', True)
    bindir_native = tinfoil.config_data.getVar('STAGING_BINDIR_NATIVE', True)
    tinfoil.shutdown()

    if not glob.glob(os.path.join(bindir_native, 'qemu-system-*')):
        raise DevtoolError('QEMU is not available within this SDK')

    imagename = args.imagename
    if not imagename:
        sdk_targets = config.get('SDK', 'sdk_targets', '').split()
        if sdk_targets:
            imagename = sdk_targets[0]
    if not imagename:
        raise DevtoolError('Unable to determine image name to run, please specify one')

    try:
        exec_build_env_command(config.init_path, basepath, 'runqemu %s %s %s' % (machine, imagename, " ".join(args.args)), watch=True)
    except bb.process.ExecutionError as e:
        # We've already seen the output since watch=True, so just ensure we return something to the user
        return e.exitcode

    return 0
Ejemplo n.º 2
0
def edit_recipe(args, config, basepath, workspace):
    """Entry point for the devtool 'edit-recipe' subcommand"""
    if args.any_recipe:
        tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
        try:
            rd = parse_recipe(config, tinfoil, args.recipename, True)
            if not rd:
                return 1
            recipefile = rd.getVar('FILE', True)
        finally:
            tinfoil.shutdown()
    else:
        check_workspace_recipe(workspace, args.recipename)
        recipefile = workspace[args.recipename]['recipefile']
        if not recipefile:
            raise DevtoolError(
                "Recipe file for %s is not under the workspace" %
                args.recipename)

    editor = os.environ.get('EDITOR', None)
    if not editor:
        raise DevtoolError("EDITOR environment variable not set")

    import subprocess
    try:
        subprocess.check_call('%s "%s"' % (editor, recipefile), shell=True)
    except subprocess.CalledProcessError as e:
        return e.returncode

    return 0
Ejemplo n.º 3
0
def runqemu(args, config, basepath, workspace):
    """Entry point for the devtool 'runqemu' subcommand"""

    tinfoil = setup_tinfoil(config_only=True, basepath=basepath)
    try:
        machine = tinfoil.config_data.getVar('MACHINE')
        bindir_native = os.path.join(tinfoil.config_data.getVar('STAGING_DIR'),
                                     tinfoil.config_data.getVar('BUILD_ARCH'),
                                     tinfoil.config_data.getVar('bindir_native').lstrip(os.path.sep))
    finally:
        tinfoil.shutdown()

    if not glob.glob(os.path.join(bindir_native, 'qemu-system-*')):
        raise DevtoolError('QEMU is not available within this SDK')

    imagename = args.imagename
    if not imagename:
        sdk_targets = config.get('SDK', 'sdk_targets', '').split()
        if sdk_targets:
            imagename = sdk_targets[0]
    if not imagename:
        raise DevtoolError('Unable to determine image name to run, please specify one')

    try:
        # FIXME runqemu assumes that if OECORE_NATIVE_SYSROOT is set then it shouldn't
        # run bitbake to find out the values of various environment variables, which
        # isn't the case for the extensible SDK. Work around it for now.
        newenv = dict(os.environ)
        newenv.pop('OECORE_NATIVE_SYSROOT', '')
        exec_build_env_command(config.init_path, basepath, 'runqemu %s %s %s' % (machine, imagename, " ".join(args.args)), watch=True, env=newenv)
    except bb.process.ExecutionError as e:
        # We've already seen the output since watch=True, so just ensure we return something to the user
        return e.exitcode

    return 0
def build_image(args, config, basepath, workspace):
    """Entry point for the devtool 'build-image' subcommand."""

    image = args.imagename
    auto_image = False
    if not image:
        sdk_targets = config.get('SDK', 'sdk_targets', '').split()
        if sdk_targets:
            image = sdk_targets[0]
            auto_image = True
    if not image:
        raise DevtoolError('Unable to determine image to build, please specify one')

    try:
        if args.add_packages:
            add_packages = args.add_packages.split(',')
        else:
            add_packages = None
        result, outputdir = build_image_task(config, basepath, workspace, image, add_packages)
    except TargetNotImageError:
        if auto_image:
            raise DevtoolError('Unable to determine image to build, please specify one')
        else:
            raise DevtoolError('Specified recipe %s is not an image recipe' % image)

    if result == 0:
        logger.info('Successfully built %s. You can find output files in %s'
                    % (image, outputdir))
    return result
Ejemplo n.º 5
0
def configure(args, config, basepath, workspace):
    """Entry point for the devtool 'configure' subcommand"""

    if args.component not in workspace:
        raise DevtoolError(
            "recipe %s is not in your workspace, run devtool modify command first"
            % args.component)

    rd = ""
    tinfoil = setup_tinfoil(basepath=basepath)
    try:
        rd = parse_recipe(config,
                          tinfoil,
                          args.component,
                          appends=True,
                          filter_workspace=False)
        if not rd:
            return 1

        pn = rd.getVar('PN', True)
        if pn not in workspace:
            raise DevtoolError(
                "Run devtool modify before calling configure for %s" % pn)

    finally:
        tinfoil.shutdown()

    exec_build_env_command(config.init_path,
                           basepath,
                           'bitbake -c configure %s' % pn,
                           watch=True)

    return 0
Ejemplo n.º 6
0
def sdk_install(args, config, basepath, workspace):
    """Entry point for the devtool sdk-install command"""

    import oe.recipeutils
    import bb.process

    for recipe in args.recipename:
        if recipe in workspace:
            raise DevtoolError('recipe %s is a recipe in your workspace' % recipe)

    tasks = ['do_populate_sysroot', 'do_packagedata']
    stampprefixes = {}
    def checkstamp(recipe):
        stampprefix = stampprefixes[recipe]
        stamps = glob.glob(stampprefix + '*')
        for stamp in stamps:
            if '.sigdata.' not in stamp and stamp.startswith((stampprefix + '.', stampprefix + '_setscene.')):
                return True
        else:
            return False

    install_recipes = []
    tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
    try:
        for recipe in args.recipename:
            rd = parse_recipe(config, tinfoil, recipe, True)
            if not rd:
                return 1
            stampprefixes[recipe] = '%s.%s' % (rd.getVar('STAMP', True), tasks[0])
            if checkstamp(recipe):
                logger.info('%s is already installed' % recipe)
            else:
                install_recipes.append(recipe)
    finally:
        tinfoil.shutdown()

    if install_recipes:
        logger.info('Installing %s...' % ', '.join(install_recipes))
        install_tasks = []
        for recipe in install_recipes:
            for task in tasks:
                if recipe.endswith('-native') and 'package' in task:
                    continue
                install_tasks.append('%s:%s' % (recipe, task))
        options = ''
        if not args.allow_build:
            options += ' --setscene-only'
        try:
            exec_build_env_command(config.init_path, basepath, 'bitbake %s %s' % (options, ' '.join(install_tasks)), watch=True)
        except bb.process.ExecutionError as e:
            raise DevtoolError('Failed to install %s:\n%s' % (recipe, str(e)))
        failed = False
        for recipe in install_recipes:
            if checkstamp(recipe):
                logger.info('Successfully installed %s' % recipe)
            else:
                raise DevtoolError('Failed to install %s - unavailable' % recipe)
                failed = True
        if failed:
            return 2
def build_sdk(args, config, basepath, workspace):
    """Entry point for the devtool build-sdk command"""

    sdk_targets = config.get('SDK', 'sdk_targets', '').split()
    if sdk_targets:
        image = sdk_targets[0]
    else:
        raise DevtoolError('Unable to determine image to build SDK for')

    extra_append = ['SDK_DERIVATIVE = "1"']
    try:
        result, outputdir = build_image.build_image_task(
            config,
            basepath,
            workspace,
            image,
            task='populate_sdk_ext',
            extra_append=extra_append)
    except build_image.TargetNotImageError:
        raise DevtoolError('Unable to determine image to build SDK for')

    if result == 0:
        logger.info('Successfully built SDK. You can find output files in %s' %
                    outputdir)
    return result
Ejemplo n.º 8
0
def undeploy(args, config, basepath, workspace):
    """Entry point for the devtool 'undeploy' subcommand"""
    if args.all and args.recipename:
        raise argparse_oe.ArgumentUsageError(
            'Cannot specify -a/--all with a recipe name', 'undeploy-target')
    elif not args.recipename and not args.all:
        raise argparse_oe.ArgumentUsageError(
            'If you don\'t specify a recipe, you must specify -a/--all',
            'undeploy-target')

    extraoptions = ''
    if args.no_host_check:
        extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
    if not args.show_status:
        extraoptions += ' -q'

    scp_port = ''
    ssh_port = ''
    if args.port:
        scp_port = "-P %s" % args.port
        ssh_port = "-p %s" % args.port

    args.target = args.target.split(':')[0]

    tmpdir = tempfile.mkdtemp(prefix='devtool')
    try:
        tmpscript = '/tmp/devtool_undeploy.sh'
        shellscript = _prepare_remote_script(deploy=False,
                                             dryrun=args.dry_run,
                                             undeployall=args.all)
        # Write out the script to a file
        with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f:
            f.write(shellscript)
        # Copy it to the target
        ret = subprocess.call("scp %s %s %s/* %s:%s" %
                              (scp_port, extraoptions, tmpdir, args.target,
                               os.path.dirname(tmpscript)),
                              shell=True)
        if ret != 0:
            raise DevtoolError(
                'Failed to copy script to %s - rerun with -s to '
                'get a complete error message' % args.target)
    finally:
        shutil.rmtree(tmpdir)

    # Now run the script
    ret = subprocess.call(
        'ssh %s %s %s \'sh %s %s\'' %
        (ssh_port, extraoptions, args.target, tmpscript, args.recipename),
        shell=True)
    if ret != 0:
        raise DevtoolError('Undeploy failed - rerun with -s to get a complete '
                           'error message')

    if not args.all and not args.dry_run:
        logger.info('Successfully undeployed %s' % args.recipename)
    return 0
Ejemplo n.º 9
0
def upgrade(args, config, basepath, workspace):
    """Entry point for the devtool 'upgrade' subcommand"""

    if args.recipename in workspace:
        raise DevtoolError("recipe %s is already in your workspace" %
                           args.recipename)
    if not args.version and not args.srcrev:
        raise DevtoolError(
            "You must provide a version using the --version/-V option, or for recipes that fetch from an SCM such as git, the --srcrev/-S option"
        )

    reason = oe.recipeutils.validate_pn(args.recipename)
    if reason:
        raise DevtoolError(reason)

    tinfoil = setup_tinfoil(basepath=basepath)

    rd = parse_recipe(config, tinfoil, args.recipename, True)
    if not rd:
        return 1

    pn = rd.getVar('PN', True)
    if pn != args.recipename:
        logger.info('Mapping %s to %s' % (args.recipename, pn))
    if pn in workspace:
        raise DevtoolError("recipe %s is already in your workspace" % pn)

    standard._check_compatible_recipe(pn, rd)
    if rd.getVar('PV', True) == args.version and rd.getVar(
            'SRCREV', True) == args.srcrev:
        raise DevtoolError(
            "Current and upgrade versions are the same version" % version)

    rf = None
    try:
        rev1 = standard._extract_source(args.srctree, False, 'devtool-orig',
                                        rd)
        rev2, md5, sha256 = _extract_new_source(args.version, args.srctree,
                                                args.no_patch, args.srcrev,
                                                args.branch, args.keep_temp,
                                                tinfoil, rd)
        rf = _create_new_recipe(args.version, md5, sha256,
                                config.workspace_path, rd)
    except bb.process.CmdError as e:
        _upgrade_error(e, rf, args.srctree)
    except DevtoolError as e:
        _upgrade_error(e, rf, args.srctree)
    standard._add_md5(config, pn, os.path.dirname(rf))

    af = _write_append(rf, args.srctree, args.same_dir, args.no_same_dir, rev2,
                       config.workspace_path, rd)
    standard._add_md5(config, pn, af)
    logger.info('Upgraded source extracted to %s' % args.srctree)
    return 0
Ejemplo n.º 10
0
def reset(args, config, basepath, workspace):
    """Entry point for the devtool 'reset' subcommand"""
    import bb
    if args.recipename:
        if args.all:
            raise DevtoolError(
                "Recipe cannot be specified if -a/--all is used")
        elif not args.recipename in workspace:
            raise DevtoolError("no recipe named %s in your workspace" %
                               args.recipename)
    elif not args.all:
        raise DevtoolError("Recipe must be specified, or specify -a/--all to "
                           "reset all recipes")
    if args.all:
        recipes = workspace
    else:
        recipes = [args.recipename]

    for pn in recipes:
        if not args.no_clean:
            logger.info('Cleaning sysroot for recipe %s...' % pn)
            try:
                exec_build_env_command(config.init_path, basepath,
                                       'bitbake -c clean %s' % pn)
            except bb.process.ExecutionError as e:
                raise DevtoolError(
                    'Command \'%s\' failed, output:\n%s\nIf you '
                    'wish, you may specify -n/--no-clean to '
                    'skip running this command when resetting' %
                    (e.command, e.stdout))

        _check_preserve(config, pn)

        preservepath = os.path.join(config.workspace_path, 'attic', pn)

        def preservedir(origdir):
            if os.path.exists(origdir):
                for root, dirs, files in os.walk(origdir):
                    for fn in files:
                        logger.warn('Preserving %s in %s' % (fn, preservepath))
                        bb.utils.mkdirhier(preservepath)
                        shutil.move(os.path.join(origdir, fn),
                                    os.path.join(preservepath, fn))
                    for dn in dirs:
                        os.rmdir(os.path.join(root, dn))
                os.rmdir(origdir)

        preservedir(os.path.join(config.workspace_path, 'recipes', pn))
        # We don't automatically create this dir next to appends, but the user can
        preservedir(os.path.join(config.workspace_path, 'appends', pn))

    return 0
Ejemplo n.º 11
0
def build(args, config, basepath, workspace):
    """Entry point for the devtool 'build' subcommand"""
    if not args.recipename in workspace:
        raise DevtoolError("no recipe named %s in your workspace" %
                           args.recipename)

    build_task = config.get('Build', 'build_task', 'populate_sysroot')

    postfile_param = ""
    postfile = ""
    if args.disable_parallel_make:
        logger.info("Disabling 'make' parallelism")
        postfile = os.path.join(basepath, 'conf', 'disable_parallelism.conf')
        _create_conf_file({'PARALLEL_MAKE':''}, postfile)
        postfile_param = "-R %s" % postfile
    try:
        exec_build_env_command(config.init_path, basepath, 'bitbake -c %s %s %s' % (build_task, postfile_param, args.recipename), watch=True)
    except bb.process.ExecutionError as e:
        # We've already seen the output since watch=True, so just ensure we return something to the user
        return e.exitcode
    finally:
        if postfile:
            logger.debug('Removing postfile')
            os.remove(postfile)

    return 0
Ejemplo n.º 12
0
def _write_append(rc, srctree, same_dir, no_same_dir, rev, copied, workspace,
                  d):
    """Writes an append file"""
    if not os.path.exists(rc):
        raise DevtoolError("bbappend not created because %s does not exist" %
                           rc)

    appendpath = os.path.join(workspace, 'appends')
    if not os.path.exists(appendpath):
        bb.utils.mkdirhier(appendpath)

    brf = os.path.basename(os.path.splitext(rc)[0])  # rc basename

    srctree = os.path.abspath(srctree)
    pn = d.getVar('PN')
    af = os.path.join(appendpath, '%s.bbappend' % brf)
    with open(af, 'w') as f:
        f.write('FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n\n')
        f.write('inherit externalsrc\n')
        f.write((
            '# NOTE: We use pn- overrides here to avoid affecting'
            'multiple variants in the case where the recipe uses BBCLASSEXTEND\n'
        ))
        f.write('EXTERNALSRC_pn-%s = "%s"\n' % (pn, srctree))
        b_is_s = use_external_build(same_dir, no_same_dir, d)
        if b_is_s:
            f.write('EXTERNALSRC_BUILD_pn-%s = "%s"\n' % (pn, srctree))
        f.write('\n')
        if rev:
            f.write('# initial_rev: %s\n' % rev)
        if copied:
            f.write('# original_path: %s\n' %
                    os.path.dirname(d.getVar('FILE')))
            f.write('# original_files: %s\n' % ' '.join(copied))
    return af
Ejemplo n.º 13
0
def _check_compatible_recipe(pn, d):
    """Check if the recipe is supported by devtool"""
    if pn == 'perf':
        raise DevtoolError("The perf recipe does not actually check out "
                           "source and thus cannot be supported by this tool")

    if pn in ['kernel-devsrc', 'package-index'] or pn.startswith('gcc-source'):
        raise DevtoolError("The %s recipe is not supported by this tool" % pn)

    if bb.data.inherits_class('image', d):
        raise DevtoolError("The %s recipe is an image, and therefore is not "
                           "supported by this tool" % pn)

    if bb.data.inherits_class('populate_sdk', d):
        raise DevtoolError("The %s recipe is an SDK, and therefore is not "
                           "supported by this tool" % pn)

    if bb.data.inherits_class('packagegroup', d):
        raise DevtoolError("The %s recipe is a packagegroup, and therefore is "
                           "not supported by this tool" % pn)

    if bb.data.inherits_class('meta', d):
        raise DevtoolError("The %s recipe is a meta-recipe, and therefore is "
                           "not supported by this tool" % pn)

    if bb.data.inherits_class('externalsrc', d) and d.getVar(
            'EXTERNALSRC', True):
        raise DevtoolError("externalsrc is currently enabled for the %s "
                           "recipe. This prevents the normal do_patch task "
                           "from working. You will need to disable this "
                           "first." % pn)
Ejemplo n.º 14
0
def _find_recipe_path(args, config, basepath, workspace):
    if args.any_recipe:
        tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
        try:
            rd = parse_recipe(config, tinfoil, args.recipename, True)
            if not rd:
                raise DevtoolError("Failed to find specified recipe")
            recipefile = rd.getVar('FILE')
        finally:
            tinfoil.shutdown()
    else:
        check_workspace_recipe(workspace, args.recipename)
        recipefile = workspace[args.recipename]['recipefile']
        if not recipefile:
            raise DevtoolError(
                "Recipe file for %s is not under the workspace" %
                args.recipename)
    return recipefile
Ejemplo n.º 15
0
def undeploy(args, config, basepath, workspace):
    """Entry point for the devtool 'undeploy' subcommand"""
    deploy_file = os.path.join(basepath, 'target_deploy', args.target,
                               args.recipename + '.list')
    if not os.path.exists(deploy_file):
        raise DevtoolError('%s has not been deployed' % args.recipename)

    if args.dry_run:
        print(
            'Previously deployed files to be un-deployed for %s on target %s:'
            % (args.recipename, args.target))
        with open(deploy_file, 'r') as f:
            for line in f:
                print('  %s' % line.rstrip())
        return 0

    extraoptions = ''
    if args.no_host_check:
        extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
    if not args.show_status:
        extraoptions += ' -q'

    ret = subprocess.call("scp %s %s %s:/tmp" %
                          (extraoptions, deploy_file, args.target),
                          shell=True)
    if ret != 0:
        raise DevtoolError('Failed to copy file list to %s - rerun with -s to '
                           'get a complete error message' % args.target)

    ret = subprocess.call(
        "ssh %s %s 'xargs -n1 rm -f </tmp/%s'" %
        (extraoptions, args.target, os.path.basename(deploy_file)),
        shell=True)
    if ret == 0:
        logger.info('Successfully undeployed %s' % args.recipename)
        os.remove(deploy_file)
    else:
        raise DevtoolError('Undeploy failed - rerun with -s to get a complete '
                           'error message')

    return ret
Ejemplo n.º 16
0
def menuconfig(args, config, basepath, workspace):
    """Entry point for the devtool 'menuconfig' subcommand"""

    rd = ""
    kconfigpath = ""
    pn_src = ""
    localfilesdir = ""
    workspace_dir = ""
    tinfoil = setup_tinfoil(basepath=basepath)
    try:
        rd = parse_recipe(config,
                          tinfoil,
                          args.component,
                          appends=True,
                          filter_workspace=False)
        if not rd:
            return 1

        check_workspace_recipe(workspace, args.component)
        pn = rd.getVar('PN', True)

        if not rd.getVarFlag('do_menuconfig', 'task'):
            raise DevtoolError(
                "This recipe does not support menuconfig option")

        workspace_dir = os.path.join(config.workspace_path, 'sources')
        kconfigpath = rd.getVar('B')
        pn_src = os.path.join(workspace_dir, pn)

        # add check to see if oe_local_files exists or not
        localfilesdir = os.path.join(pn_src, 'oe-local-files')
        if not os.path.exists(localfilesdir):
            bb.utils.mkdirhier(localfilesdir)
            # Add gitignore to ensure source tree is clean
            gitignorefile = os.path.join(localfilesdir, '.gitignore')
            with open(gitignorefile, 'w') as f:
                f.write(
                    '# Ignore local files, by default. Remove this file if you want to commit the directory to Git\n'
                )
                f.write('*\n')

    finally:
        tinfoil.shutdown()

    logger.info('Launching menuconfig')
    exec_build_env_command(config.init_path,
                           basepath,
                           'bitbake -c menuconfig %s' % pn,
                           watch=True)
    fragment = os.path.join(localfilesdir, 'devtool-fragment.cfg')
    res = standard._create_kconfig_diff(pn_src, rd, fragment)

    return 0
Ejemplo n.º 17
0
def _rename_recipe_file(bpn, oldpv, newpv, path):
    oldrecipe = "%s_%s.bb" % (bpn, oldpv)
    newrecipe = "%s_%s.bb" % (bpn, newpv)
    if os.path.isfile(os.path.join(path, oldrecipe)):
        if oldrecipe != newrecipe:
            _run('mv %s %s' % (oldrecipe, newrecipe), cwd=path)
    else:
        recipe = "%s_git.bb" % bpn
        if os.path.isfile(os.path.join(path, recipe)):
            newrecipe = recipe
            raise DevtoolError("Original recipe not found on workspace")
    return os.path.join(path, newrecipe)
Ejemplo n.º 18
0
def update_recipe(args, config, basepath, workspace):
    """Entry point for the devtool 'update-recipe' subcommand"""
    if not args.recipename in workspace:
        raise DevtoolError("no recipe named %s in your workspace" %
                           args.recipename)

    if args.append:
        if not os.path.exists(args.append):
            raise DevtoolError('bbappend destination layer directory "%s" '
                               'does not exist' % args.append)
        if not os.path.exists(os.path.join(args.append, 'conf', 'layer.conf')):
            raise DevtoolError('conf/layer.conf not found in bbappend '
                               'destination layer "%s"' % args.append)

    tinfoil = setup_tinfoil()

    rd = parse_recipe(config, tinfoil, args.recipename, True)
    if not rd:
        return 1

    srctree = workspace[args.recipename]['srctree']
    if args.mode == 'auto':
        mode = _guess_recipe_update_mode(srctree, rd)
    else:
        mode = args.mode

    if mode == 'srcrev':
        _update_recipe_srcrev(args, srctree, rd, tinfoil.config_data)
    elif mode == 'patch':
        _update_recipe_patch(args, config, srctree, rd, tinfoil.config_data)
    else:
        raise DevtoolError('update_recipe: invalid mode %s' % mode)

    rf = rd.getVar('FILE', True)
    if rf.startswith(config.workspace_path):
        logger.warn(
            'Recipe file %s has been updated but is inside the workspace - you will need to move it (and any associated files next to it) out to the desired layer before using "devtool reset" in order to keep any changes'
            % rf)

    return 0
Ejemplo n.º 19
0
def update_recipe(args, config, basepath, workspace):
    """Entry point for the devtool 'update-recipe' subcommand"""
    if not args.recipename in workspace:
        raise DevtoolError("no recipe named %s in your workspace" %
                           args.recipename)

    if args.append:
        if not os.path.exists(args.append):
            raise DevtoolError('bbappend destination layer directory "%s" '
                               'does not exist' % args.append)
        if not os.path.exists(os.path.join(args.append, 'conf', 'layer.conf')):
            raise DevtoolError('conf/layer.conf not found in bbappend '
                               'destination layer "%s"' % args.append)

    tinfoil = setup_tinfoil()

    rd = _parse_recipe(config, tinfoil, args.recipename, True)
    if not rd:
        return 1

    orig_src_uri = rd.getVar('SRC_URI', False) or ''
    if args.mode == 'auto':
        if 'git://' in orig_src_uri:
            mode = 'srcrev'
        else:
            mode = 'patch'
    else:
        mode = args.mode

    srctree = workspace[args.recipename]['srctree']

    if mode == 'srcrev':
        _update_recipe_srcrev(args, srctree, rd, tinfoil.config_data)
    elif mode == 'patch':
        _update_recipe_patch(args, config, srctree, rd, tinfoil.config_data)
    else:
        raise DevtoolError('update_recipe: invalid mode %s' % mode)

    return 0
Ejemplo n.º 20
0
def _get_uri(rd):
    srcuris = rd.getVar('SRC_URI').split()
    if not len(srcuris):
        raise DevtoolError('SRC_URI not found on recipe')
    # Get first non-local entry in SRC_URI - usually by convention it's
    # the first entry, but not always!
    srcuri = None
    for entry in srcuris:
        if not entry.startswith('file://'):
            srcuri = entry
            break
    if not srcuri:
        raise DevtoolError('Unable to find non-local entry in SRC_URI')
    srcrev = '${AUTOREV}'
    if '://' in srcuri:
        # Fetch a URL
        rev_re = re.compile(';rev=([^;]+)')
        res = rev_re.search(srcuri)
        if res:
            srcrev = res.group(1)
            srcuri = rev_re.sub('', srcuri)
    return srcuri, srcrev
Ejemplo n.º 21
0
def _get_uri(rd):
    srcuris = rd.getVar('SRC_URI', True).split()
    if not len(srcuris):
        raise DevtoolError('SRC_URI not found on recipe')
    srcuri = srcuris[0]  # it is assumed, URI is at first position
    srcrev = '${AUTOREV}'
    if '://' in srcuri:
        # Fetch a URL
        rev_re = re.compile(';rev=([^;]+)')
        res = rev_re.search(srcuri)
        if res:
            srcrev = res.group(1)
            srcuri = rev_re.sub('', srcuri)
    return srcuri, srcrev
Ejemplo n.º 22
0
def upgrade(args, config, basepath, workspace):
    """Entry point for the devtool 'upgrade' subcommand"""

    if args.recipename in workspace:
        raise DevtoolError("recipe %s is already in your workspace" % args.recipename)
    if not args.version and not args.srcrev:
        raise DevtoolError("You must provide a version using the --version/-V option, or for recipes that fetch from an SCM such as git, the --srcrev/-S option")
    if args.srcbranch and not args.srcrev:
        raise DevtoolError("If you specify --srcbranch/-B then you must use --srcrev/-S to specify the revision" % args.recipename)

    tinfoil = setup_tinfoil(basepath=basepath, tracking=True)
    try:
        rd = parse_recipe(config, tinfoil, args.recipename, True)
        if not rd:
            return 1

        pn = rd.getVar('PN')
        if pn != args.recipename:
            logger.info('Mapping %s to %s' % (args.recipename, pn))
        if pn in workspace:
            raise DevtoolError("recipe %s is already in your workspace" % pn)

        if args.srctree:
            srctree = os.path.abspath(args.srctree)
        else:
            srctree = standard.get_default_srctree(config, pn)

        standard._check_compatible_recipe(pn, rd)
        old_srcrev = rd.getVar('SRCREV')
        if old_srcrev == 'INVALID':
            old_srcrev = None
        if old_srcrev and not args.srcrev:
            raise DevtoolError("Recipe specifies a SRCREV value; you must specify a new one when upgrading")
        if rd.getVar('PV') == args.version and old_srcrev == args.srcrev:
            raise DevtoolError("Current and upgrade versions are the same version")

        rf = None
        try:
            rev1 = standard._extract_source(srctree, False, 'devtool-orig', False, rd, tinfoil)
            rev2, md5, sha256 = _extract_new_source(args.version, srctree, args.no_patch,
                                                    args.srcrev, args.branch, args.keep_temp,
                                                    tinfoil, rd)
            rf, copied = _create_new_recipe(args.version, md5, sha256, args.srcrev, args.srcbranch, config.workspace_path, tinfoil, rd)
        except bb.process.CmdError as e:
            _upgrade_error(e, rf, srctree)
        except DevtoolError as e:
            _upgrade_error(e, rf, srctree)
        standard._add_md5(config, pn, os.path.dirname(rf))

        af = _write_append(rf, srctree, args.same_dir, args.no_same_dir, rev2,
                        copied, config.workspace_path, rd)
        standard._add_md5(config, pn, af)
        logger.info('Upgraded source extracted to %s' % srctree)
        logger.info('New recipe is %s' % rf)
    finally:
        tinfoil.shutdown()
    return 0
Ejemplo n.º 23
0
def _prep_extract_operation(config, basepath, recipename):
    """HACK: Ugly workaround for making sure that requirements are met when
       trying to extract a package. Returns the tinfoil instance to be used."""
    tinfoil = setup_tinfoil()
    rd = parse_recipe(config, tinfoil, recipename, True)

    if bb.data.inherits_class('kernel-yocto', rd):
        tinfoil.shutdown()
        try:
            stdout, _ = exec_build_env_command(config.init_path, basepath,
                                               'bitbake kern-tools-native')
            tinfoil = setup_tinfoil()
        except bb.process.ExecutionError as err:
            raise DevtoolError("Failed to build kern-tools-native:\n%s" %
                               err.stdout)
    return tinfoil
Ejemplo n.º 24
0
def find_recipe(args, config, basepath, workspace):
    """Entry point for the devtool 'find-recipe' subcommand"""
    if args.any_recipe:
        tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
        try:
            rd = parse_recipe(config, tinfoil, args.recipename, True)
            if not rd:
                return 1
            recipefile = rd.getVar('FILE')
        finally:
            tinfoil.shutdown()
    else:
        check_workspace_recipe(workspace, args.recipename)
        recipefile = workspace[args.recipename]['recipefile']
        if not recipefile:
            raise DevtoolError("Recipe file for %s is not under the workspace" %
                               args.recipename)
Ejemplo n.º 25
0
def build(args, config, basepath, workspace):
    """Entry point for the devtool 'build' subcommand"""
    import bb
    if not args.recipename in workspace:
        raise DevtoolError("no recipe named %s in your workspace" %
                           args.recipename)
    build_task = config.get('Build', 'build_task', 'populate_sysroot')
    try:
        exec_build_env_command(config.init_path,
                               basepath,
                               'bitbake -c %s %s' %
                               (build_task, args.recipename),
                               watch=True)
    except bb.process.ExecutionError as e:
        # We've already seen the output since watch=True, so just ensure we return something to the user
        return e.exitcode

    return 0
Ejemplo n.º 26
0
def _find_recipe_path(args, config, basepath, workspace):
    if args.any_recipe:
        logger.warning(
            '-a/--any-recipe option is now always active, and thus the option will be removed in a future release'
        )
    if args.recipename in workspace:
        recipefile = workspace[args.recipename]['recipefile']
    else:
        recipefile = None
    if not recipefile:
        tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
        try:
            rd = parse_recipe(config, tinfoil, args.recipename, True)
            if not rd:
                raise DevtoolError("Failed to find specified recipe")
            recipefile = rd.getVar('FILE')
        finally:
            tinfoil.shutdown()
    return recipefile
Ejemplo n.º 27
0
def _check_git_config():
    def getconfig(name):
        try:
            value = bb.process.run('git config --global %s' % name)[0].strip()
        except bb.process.ExecutionError as e:
            if e.exitcode == 1:
                value = None
            else:
                raise
        return value

    username = getconfig('user.name')
    useremail = getconfig('user.email')
    configerr = []
    if not username:
        configerr.append('Please set your name using:\n  git config --global user.name')
    if not useremail:
        configerr.append('Please set your email using:\n  git config --global user.email')
    if configerr:
        raise DevtoolError('Your git configuration is incomplete which will prevent rebases from working:\n' + '\n'.join(configerr))
Ejemplo n.º 28
0
def package(args, config, basepath, workspace):
    """Entry point for the devtool 'package' subcommand"""
    if not args.recipename in workspace:
        raise DevtoolError("no recipe named %s in your workspace" %
                           args.recipename)

    image_pkgtype = config.get('Package', 'image_pkgtype', '')
    if not image_pkgtype:
        tinfoil = setup_tinfoil()
        try:
            tinfoil.prepare(config_only=True)
            image_pkgtype = tinfoil.config_data.getVar('IMAGE_PKGTYPE', True)
        finally:
            tinfoil.shutdown()

    package_task = config.get('Package', 'package_task', 'package_write_%s' % image_pkgtype)
    try:
        exec_build_env_command(config.init_path, basepath, 'bitbake -c %s %s' % (package_task, args.recipename), watch=True)
    except bb.process.ExecutionError as e:
        # We've already seen the output since watch=True, so just ensure we return something to the user
        return e.exitcode
    logger.info('Your packages are in %s/tmp/deploy/%s' % (basepath, image_pkgtype))

    return 0
Ejemplo n.º 29
0
def upgrade(args, config, basepath, workspace):
    """Entry point for the devtool 'upgrade' subcommand"""

    if args.recipename in workspace:
        raise DevtoolError("recipe %s is already in your workspace" %
                           args.recipename)
    if args.srcbranch and not args.srcrev:
        raise DevtoolError(
            "If you specify --srcbranch/-B then you must use --srcrev/-S to specify the revision"
            % args.recipename)

    _check_git_config()

    tinfoil = setup_tinfoil(basepath=basepath, tracking=True)
    try:
        rd = parse_recipe(config, tinfoil, args.recipename, True)
        if not rd:
            return 1

        pn = rd.getVar('PN')
        if pn != args.recipename:
            logger.info('Mapping %s to %s' % (args.recipename, pn))
        if pn in workspace:
            raise DevtoolError("recipe %s is already in your workspace" % pn)

        if args.srctree:
            srctree = os.path.abspath(args.srctree)
        else:
            srctree = standard.get_default_srctree(config, pn)

        # try to automatically discover latest version and revision if not provided on command line
        if not args.version and not args.srcrev:
            version_info = oe.recipeutils.get_recipe_upstream_version(rd)
            if version_info['version'] and not version_info[
                    'version'].endswith("new-commits-available"):
                args.version = version_info['version']
            if version_info['revision']:
                args.srcrev = version_info['revision']
        if not args.version and not args.srcrev:
            raise DevtoolError(
                "Automatic discovery of latest version/revision failed - you must provide a version using the --version/-V option, or for recipes that fetch from an SCM such as git, the --srcrev/-S option."
            )

        standard._check_compatible_recipe(pn, rd)
        old_srcrev = rd.getVar('SRCREV')
        if old_srcrev == 'INVALID':
            old_srcrev = None
        if old_srcrev and not args.srcrev:
            raise DevtoolError(
                "Recipe specifies a SRCREV value; you must specify a new one when upgrading"
            )
        old_ver = rd.getVar('PV')
        if old_ver == args.version and old_srcrev == args.srcrev:
            raise DevtoolError(
                "Current and upgrade versions are the same version")
        if args.version:
            if bb.utils.vercmp_string(args.version, old_ver) < 0:
                logger.warning(
                    'Upgrade version %s compares as less than the current version %s. If you are using a package feed for on-target upgrades or providing this recipe for general consumption, then you should increment PE in the recipe (or if there is no current PE value set, set it to "1")'
                    % (args.version, old_ver))
            check_prerelease_version(args.version, 'devtool upgrade')

        rf = None
        license_diff = None
        try:
            logger.info('Extracting current version source...')
            rev1, srcsubdir1 = standard._extract_source(
                srctree,
                False,
                'devtool-orig',
                False,
                config,
                basepath,
                workspace,
                args.fixed_setup,
                rd,
                tinfoil,
                no_overrides=args.no_overrides)
            old_licenses = _extract_licenses(srctree,
                                             rd.getVar('LIC_FILES_CHKSUM'))
            logger.info('Extracting upgraded version source...')
            rev2, md5, sha256, srcbranch, srcsubdir2 = _extract_new_source(
                args.version, srctree, args.no_patch, args.srcrev,
                args.srcbranch, args.branch, args.keep_temp, tinfoil, rd)
            new_licenses = _extract_licenses(srctree,
                                             rd.getVar('LIC_FILES_CHKSUM'))
            license_diff = _generate_license_diff(old_licenses, new_licenses)
            rf, copied = _create_new_recipe(args.version, md5, sha256,
                                            args.srcrev, srcbranch, srcsubdir1,
                                            srcsubdir2, config.workspace_path,
                                            tinfoil, rd, license_diff,
                                            new_licenses)
        except bb.process.CmdError as e:
            _upgrade_error(e, rf, srctree)
        except DevtoolError as e:
            _upgrade_error(e, rf, srctree)
        standard._add_md5(config, pn, os.path.dirname(rf))

        af = _write_append(rf, srctree, args.same_dir, args.no_same_dir, rev2,
                           copied, config.workspace_path, rd)
        standard._add_md5(config, pn, af)

        update_unlockedsigs(basepath, workspace, args.fixed_setup, [pn])

        logger.info('Upgraded source extracted to %s' % srctree)
        logger.info('New recipe is %s' % rf)
        if license_diff:
            logger.info(
                'License checksums have been updated in the new recipe; please refer to it for the difference between the old and the new license texts.'
            )
    finally:
        tinfoil.shutdown()
    return 0
Ejemplo n.º 30
0
def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old,
                       srcsubdir_new, workspace, tinfoil, rd, license_diff,
                       new_licenses):
    """Creates the new recipe under workspace"""

    bpn = rd.getVar('BPN')
    path = os.path.join(workspace, 'recipes', bpn)
    bb.utils.mkdirhier(path)
    copied, _ = oe.recipeutils.copy_recipe_files(rd, path, all_variants=True)
    if not copied:
        raise DevtoolError(
            'Internal error - no files were copied for recipe %s' % bpn)
    logger.debug('Copied %s to %s' % (copied, path))

    oldpv = rd.getVar('PV')
    if not newpv:
        newpv = oldpv
    origpath = rd.getVar('FILE')
    fullpath = _rename_recipe_files(origpath, bpn, oldpv, newpv, path)
    logger.debug('Upgraded %s => %s' % (origpath, fullpath))

    newvalues = {}
    if _recipe_contains(rd, 'PV') and newpv != oldpv:
        newvalues['PV'] = newpv

    if srcrev:
        newvalues['SRCREV'] = srcrev

    if srcbranch:
        src_uri = oe.recipeutils.split_var_value(
            rd.getVar('SRC_URI', False) or '')
        changed = False
        replacing = True
        new_src_uri = []
        for entry in src_uri:
            scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(
                entry)
            if replacing and scheme in ['git', 'gitsm']:
                branch = params.get('branch', 'master')
                if rd.expand(branch) != srcbranch:
                    # Handle case where branch is set through a variable
                    res = re.match(r'\$\{([^}@]+)\}', branch)
                    if res:
                        newvalues[res.group(1)] = srcbranch
                        # We know we won't change SRC_URI now, so break out
                        break
                    else:
                        params['branch'] = srcbranch
                        entry = bb.fetch2.encodeurl(
                            (scheme, network, path, user, passwd, params))
                        changed = True
                replacing = False
            new_src_uri.append(entry)
        if changed:
            newvalues['SRC_URI'] = ' '.join(new_src_uri)

    newvalues['PR'] = None

    # Work out which SRC_URI entries have changed in case the entry uses a name
    crd = rd.createCopy()
    crd.setVar('PV', newpv)
    for var, value in newvalues.items():
        crd.setVar(var, value)
    old_src_uri = (rd.getVar('SRC_URI') or '').split()
    new_src_uri = (crd.getVar('SRC_URI') or '').split()
    newnames = []
    addnames = []
    for newentry in new_src_uri:
        _, _, _, _, _, params = bb.fetch2.decodeurl(newentry)
        if 'name' in params:
            newnames.append(params['name'])
            if newentry not in old_src_uri:
                addnames.append(params['name'])
    # Find what's been set in the original recipe
    oldnames = []
    noname = False
    for varflag in rd.getVarFlags('SRC_URI'):
        if varflag.endswith(('.md5sum', '.sha256sum')):
            name = varflag.rsplit('.', 1)[0]
            if name not in oldnames:
                oldnames.append(name)
        elif varflag in ['md5sum', 'sha256sum']:
            noname = True
    # Even if SRC_URI has named entries it doesn't have to actually use the name
    if noname and addnames and addnames[0] not in oldnames:
        addnames = []
    # Drop any old names (the name actually might include ${PV})
    for name in oldnames:
        if name not in newnames:
            newvalues['SRC_URI[%s.md5sum]' % name] = None
            newvalues['SRC_URI[%s.sha256sum]' % name] = None

    if md5 and sha256:
        if addnames:
            nameprefix = '%s.' % addnames[0]
        else:
            nameprefix = ''
        newvalues['SRC_URI[%smd5sum]' % nameprefix] = md5
        newvalues['SRC_URI[%ssha256sum]' % nameprefix] = sha256

    if srcsubdir_new != srcsubdir_old:
        s_subdir_old = os.path.relpath(os.path.abspath(rd.getVar('S')),
                                       rd.getVar('WORKDIR'))
        s_subdir_new = os.path.relpath(os.path.abspath(crd.getVar('S')),
                                       crd.getVar('WORKDIR'))
        if srcsubdir_old == s_subdir_old and srcsubdir_new != s_subdir_new:
            # Subdir for old extracted source matches what S points to (it should!)
            # but subdir for new extracted source doesn't match what S will be
            newvalues['S'] = '${WORKDIR}/%s' % srcsubdir_new.replace(
                newpv, '${PV}')
            if crd.expand(newvalues['S']) == crd.expand('${WORKDIR}/${BP}'):
                # It's the default, drop it
                # FIXME what if S is being set in a .inc?
                newvalues['S'] = None
                logger.info(
                    'Source subdirectory has changed, dropping S value since it now matches the default ("${WORKDIR}/${BP}")'
                )
            else:
                logger.info(
                    'Source subdirectory has changed, updating S value')

    if license_diff:
        newlicchksum = " ".join([
            "file://{}".format(l['path']) +
            (";beginline={}".format(l['beginline']) if l['beginline'] else "")
            + (";endline={}".format(l['endline']) if l['endline'] else "") +
            (";md5={}".format(l['actual_md5'])) for l in new_licenses
        ])
        newvalues["LIC_FILES_CHKSUM"] = newlicchksum
        _add_license_diff_to_recipe(fullpath, license_diff)

    rd = tinfoil.parse_recipe_file(fullpath, False)
    oe.recipeutils.patch_recipe(rd, fullpath, newvalues)

    return fullpath, copied