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
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
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(basepath=basepath) 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(basepath=basepath) except bb.process.ExecutionError as err: raise DevtoolError("Failed to build kern-tools-native:\n%s" % err.stdout) return tinfoil
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
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 package(args, config, basepath, workspace): """Entry point for the devtool 'package' subcommand""" check_workspace_recipe(workspace, args.recipename) tinfoil = setup_tinfoil(basepath=basepath) try: tinfoil.prepare(config_only=True) image_pkgtype = config.get('Package', 'image_pkgtype', '') if not image_pkgtype: image_pkgtype = tinfoil.config_data.getVar('IMAGE_PKGTYPE', True) deploy_dir_pkg = tinfoil.config_data.getVar('DEPLOY_DIR_%s' % image_pkgtype.upper(), 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' % deploy_dir_pkg) return 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 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
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
def show_var_expansions(recipe, var, plumbing_mode=False): # When plumbing_mode is truthy, var is a list of variables try: tinfoil = setup_tinfoil(config_only=True, basepath=basepath) tinfoil.parseRecipes() try: metadata = tinfoil.parse_recipe(recipe) except: sys.exit(1) if plumbing_mode: vars_vals = {} for v in var: vars_vals[v] = metadata.getVar(v, True) return vars_vals else: val = metadata.getVar(var, True) if val is not None: print('=== Final value') print( '%s = %s' % (var, val)) print('\n=== Expansion') expand_expr('${' + var + '}', metadata) else: sys.stderr.write('%s: no such variable.\n' % var) sys.exit(1) finally: tinfoil.shutdown()
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) reason = oe.recipeutils.validate_pn(args.recipename) if reason: raise DevtoolError(reason) tinfoil = setup_tinfoil(basepath=basepath, tracking=True) 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', False, 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, args.srcrev, args.srcbranch, config.workspace_path, tinfoil, 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
def search(args, config, basepath, workspace): """Entry point for the devtool 'search' subcommand""" tinfoil = setup_tinfoil(config_only=False, basepath=basepath) try: pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR') defsummary = tinfoil.config_data.getVar('SUMMARY', False) or '' keyword_rc = re.compile(args.keyword) for fn in os.listdir(pkgdata_dir): pfn = os.path.join(pkgdata_dir, fn) if not os.path.isfile(pfn): continue packages = [] match = False if keyword_rc.search(fn): match = True if not match: with open(pfn, 'r') as f: for line in f: if line.startswith('PACKAGES:'): packages = line.split(':', 1)[1].strip().split() for pkg in packages: if keyword_rc.search(pkg): match = True break if os.path.exists( os.path.join(pkgdata_dir, 'runtime', pkg + '.packaged')): with open(os.path.join(pkgdata_dir, 'runtime', pkg), 'r') as f: for line in f: if ': ' in line: splitline = line.split(':', 1) key = splitline[0] value = splitline[1].strip() if key in [ 'PKG_%s' % pkg, 'DESCRIPTION', 'FILES_INFO' ] or key.startswith('FILERPROVIDES_'): if keyword_rc.search(value): match = True break if match: rd = parse_recipe(config, tinfoil, fn, True) summary = rd.getVar('SUMMARY') if summary == rd.expand(defsummary): summary = '' print("%s %s" % (fn.ljust(20), summary)) finally: tinfoil.shutdown() return 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
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
def search(args, config, basepath, workspace): """Entry point for the devtool 'search' subcommand""" tinfoil = setup_tinfoil(config_only=False, basepath=basepath) try: pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR', True) defsummary = tinfoil.config_data.getVar('SUMMARY', False) or '' keyword_rc = re.compile(args.keyword) for fn in os.listdir(pkgdata_dir): pfn = os.path.join(pkgdata_dir, fn) if not os.path.isfile(pfn): continue packages = [] match = False if keyword_rc.search(fn): match = True if not match: with open(pfn, 'r') as f: for line in f: if line.startswith('PACKAGES:'): packages = line.split(':', 1)[1].strip().split() for pkg in packages: if keyword_rc.search(pkg): match = True break if os.path.exists(os.path.join(pkgdata_dir, 'runtime', pkg + '.packaged')): with open(os.path.join(pkgdata_dir, 'runtime', pkg), 'r') as f: for line in f: if ': ' in line: splitline = line.split(':', 1) key = splitline[0] value = splitline[1].strip() if key in ['PKG_%s' % pkg, 'DESCRIPTION', 'FILES_INFO'] or key.startswith('FILERPROVIDES_'): if keyword_rc.search(value): match = True break if match: rd = parse_recipe(config, tinfoil, fn, True) summary = rd.getVar('SUMMARY', True) if summary == rd.expand(defsummary): summary = '' print("%s %s" % (fn.ljust(20), summary)) finally: tinfoil.shutdown() return 0
def search(args, config, basepath, workspace): """Entry point for the devtool 'search' subcommand""" tinfoil = setup_tinfoil(config_only=True, basepath=basepath) pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR', True) tinfoil.shutdown() keyword_rc = re.compile(args.keyword) for fn in os.listdir(pkgdata_dir): pfn = os.path.join(pkgdata_dir, fn) if not os.path.isfile(pfn): continue packages = [] match = False if keyword_rc.search(fn): match = True if not match: with open(pfn, 'r') as f: for line in f: if line.startswith('PACKAGES:'): packages = line.split(':', 1)[1].strip().split() for pkg in packages: if keyword_rc.search(pkg): match = True break if os.path.exists( os.path.join(pkgdata_dir, 'runtime', pkg + '.packaged')): with open(os.path.join(pkgdata_dir, 'runtime', pkg), 'r') as f: for line in f: if ': ' in line: splitline = line.split(':', 1) key = splitline[0] value = splitline[1].strip() if key in [ 'PKG_%s' % pkg, 'DESCRIPTION', 'FILES_INFO' ] or key.startswith('FILERPROVIDES_'): if keyword_rc.search(value): match = True break if match: print(fn) return 0
def _get_recipes(workspace, config): """Get list of target recipes from the workspace.""" result = [] tinfoil = setup_tinfoil() for recipe in workspace: data = parse_recipe(config, tinfoil, recipe, True) if 'class-target' in data.getVar('OVERRIDES', True).split(':'): if recipe in data.getVar('PACKAGES', True): result.append(recipe) else: logger.warning("Skipping recipe %s as it doesn't produce " "package with the same name", recipe) tinfoil.shutdown() return result
def extract(args, config, basepath, workspace): import bb tinfoil = setup_tinfoil() rd = _parse_recipe(config, tinfoil, args.recipename, True) if not rd: return -1 srctree = os.path.abspath(args.srctree) initial_rev = _extract_source(srctree, args.keep_temp, args.branch, rd) if initial_rev: return 0 else: return -1
def extract_bitbake_metadata(recipes): try: tinfoil = setup_tinfoil(config_only=True, basepath=basepath) tinfoil.parseRecipes() data = {} try: metadata = tinfoil.parse_recipe("virtual/kernel") except: sys.exit(1) machine = metadata.getVar('MACHINE', True) data['image-bootloader'] = metadata.getVar('IMAGE_BOOTLOADER', True) data['soc-family'] = metadata.getVar('SOC_FAMILY', True) if data['soc-family'] is None: data['soc-family'] = metadata.getVar('MACHINEOVERRIDES', True) data['recipes'] = {} metadata = None for recipe in recipes: try: metadata = tinfoil.parse_recipe(recipe) except: continue pv = metadata.getVar('PV', True) localversion = metadata.getVar('LOCALVERSION', True) version = pv + (localversion or '') data['recipes'][recipe] = {} data['recipes'][recipe]['recipe'] = metadata.getVar('PN', True) data['recipes'][recipe]['version'] = version data['recipes'][recipe]['file'] = tinfoil.get_recipe_file(recipe) data['recipes'][recipe]['srcbranch'] = metadata.getVar( 'SRCBRANCH', True) data['recipes'][recipe]['compatible-machine'] = metadata.getVar( 'COMPATIBLE_MACHINE', True) description = metadata.getVar('DESCRIPTION', True) if not description: description = metadata.getVar('SUMMARY', True) data['recipes'][recipe]['description'] = description return {machine: data} finally: tinfoil.shutdown()
def build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" workspacepn = check_workspace_recipe(workspace, args.recipename, bbclassextend=True) tinfoil = setup_tinfoil(config_only=False, basepath=basepath) try: rd = parse_recipe(config, tinfoil, args.recipename, appends=True, filter_workspace=False) if not rd: return 1 deploytask = 'do_deploy' in rd.getVar('__BBTASKS') finally: tinfoil.shutdown() if args.clean: # use clean instead of cleansstate to avoid messing things up in eSDK build_tasks = ['do_clean'] else: build_tasks = _get_build_tasks(config) if deploytask: build_tasks.append('do_deploy') bbappend = workspace[workspacepn]['bbappend'] if args.disable_parallel_make: logger.info("Disabling 'make' parallelism") _set_file_values(bbappend, {'PARALLEL_MAKE': ''}) try: bbargs = [] for task in build_tasks: if args.recipename.endswith('-native') and 'package' in task: continue bbargs.append('%s:%s' % (args.recipename, task)) exec_build_env_command(config.init_path, basepath, 'bitbake %s' % ' '.join(bbargs), 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 args.disable_parallel_make: _set_file_values(bbappend, {'PARALLEL_MAKE': None}) return 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) reason = oe.recipeutils.validate_pn(args.recipename) if reason: raise DevtoolError(reason) tinfoil = setup_tinfoil(basepath=basepath, tracking=True) 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', False, 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, args.srcrev, args.srcbranch, config.workspace_path, tinfoil, 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
def extract(args, config, basepath, workspace): """Entry point for the devtool 'extract' subcommand""" import bb tinfoil = setup_tinfoil() rd = _parse_recipe(config, tinfoil, args.recipename, True) if not rd: return 1 srctree = os.path.abspath(args.srctree) initial_rev = _extract_source(srctree, args.keep_temp, args.branch, rd) if initial_rev: return 0 else: return 1
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)
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
def extract_bitbake_metadata(recipes): try: tinfoil = setup_tinfoil(config_only=True, basepath=basepath) tinfoil.parseRecipes() data = {} try: metadata = tinfoil.parse_recipe("virtual/kernel") except: sys.exit(1) machine = metadata.getVar('MACHINE', True) data['image-bootloader'] = metadata.getVar('IMAGE_BOOTLOADER', True) data['soc-family'] = metadata.getVar('SOC_FAMILY', True) if data['soc-family'] is None: data['soc-family'] = metadata.getVar('MACHINEOVERRIDES', True) data['recipes'] = {} metadata = None for recipe in recipes: try: metadata = tinfoil.parse_recipe(recipe) except: continue pv = metadata.getVar('PV', True) localversion = metadata.getVar('LOCALVERSION', True) version = pv + (localversion or '') data['recipes'][recipe] = {} data['recipes'][recipe]['recipe'] = metadata.getVar('PN', True) data['recipes'][recipe]['version'] = version data['recipes'][recipe]['file'] = tinfoil.get_recipe_file(recipe) data['recipes'][recipe]['srcbranch'] = metadata.getVar('SRCBRANCH', True) data['recipes'][recipe]['compatible-machine'] = metadata.getVar('COMPATIBLE_MACHINE', True) description = metadata.getVar('DESCRIPTION', True) if not description: description = metadata.getVar('SUMMARY', True) data['recipes'][recipe]['description'] = description return {machine: data} finally: tinfoil.shutdown()
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
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
def extract(args, config, basepath, workspace): import bb import oe.recipeutils tinfoil = setup_tinfoil() recipefile = _get_recipe_file(tinfoil.cooker, args.recipename) if not recipefile: # Error already logged return -1 rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data) srctree = os.path.abspath(args.srctree) initial_rev = _extract_source(srctree, args.keep_temp, args.branch, rd) if initial_rev: return 0 else: return -1
def kernel_menuconfig(args, config, basepath, workspace): """Entry point for the devtool 'kernel-menuconfig' subcommand""" # FIXME we end up with a triple parse here which is ugly (one for # the initial tinfoil instantiation, one for the modify, and then # finally one for the call to bitbake). Unfortunately it's # unavoidable without significant refactoring though so that will # have to wait until next release. tinfoil = setup_tinfoil(basepath=basepath) try: tinfoil.prepare(config_only=False) rd = parse_recipe(config, tinfoil, 'virtual/kernel', appends=True, filter_workspace=False) if not rd: return 1 pn = rd.getVar('PN', True) # We need to do this carefully as the version will change as a result of running devtool modify ver = rd.expand('${EXTENDPE}${PV}-${PR}') taintfn = (rd.getVar('STAMP', True) + '.do_compile.taint').replace(ver, '*') finally: tinfoil.shutdown() if not pn in workspace: # FIXME this will break if any options are added to the modify # subcommand. margs = argparse.Namespace() margs.recipename = pn margs.srctree = None margs.wildcard = False margs.extract = True margs.no_extract = False margs.same_dir = False margs.no_same_dir = False margs.branch = 'devtool' standard.modify(margs, config, basepath, workspace) exec_build_env_command(config.init_path, basepath, 'bitbake -c menuconfig %s' % pn, watch=True) # Remove taint created by do_menuconfig, if any for fn in glob.glob(taintfn): os.remove(fn) return 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') 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 scriptutils.run_editor(recipefile)
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
def latest_version(args, config, basepath, workspace): """Entry point for the devtool 'latest_version' subcommand""" tinfoil = setup_tinfoil(basepath=basepath, tracking=True) try: rd = parse_recipe(config, tinfoil, args.recipename, True) if not rd: return 1 version_info = oe.recipeutils.get_recipe_upstream_version(rd) # "new-commits-available" is an indication that upstream never issues version tags if not version_info['version'].endswith("new-commits-available"): logger.info("Current version: {}".format(version_info['current_version'])) logger.info("Latest version: {}".format(version_info['version'])) if version_info['revision']: logger.info("Latest version's commit: {}".format(version_info['revision'])) else: logger.info("Latest commit: {}".format(version_info['revision'])) finally: tinfoil.shutdown() return 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
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
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
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
def build_image_task(config, basepath, workspace, image, add_packages=None, task=None, extra_append=None): # remove <image>.bbappend to make sure setup_tinfoil doesn't # break because of it target_basename = config.get('SDK', 'target_basename', '') if target_basename: appendfile = os.path.join(config.workspace_path, 'appends', '%s.bbappend' % target_basename) try: os.unlink(appendfile) except OSError as exc: if exc.errno != errno.ENOENT: raise tinfoil = setup_tinfoil(basepath=basepath) rd = parse_recipe(config, tinfoil, image, True) if not rd: # Error already shown return (1, None) if not bb.data.inherits_class('image', rd): raise TargetNotImageError() # Get the actual filename used and strip the .bb and full path target_basename = rd.getVar('FILE', True) target_basename = os.path.splitext(os.path.basename(target_basename))[0] config.set('SDK', 'target_basename', target_basename) config.write() appendfile = os.path.join(config.workspace_path, 'appends', '%s.bbappend' % target_basename) outputdir = None try: if workspace or add_packages: if add_packages: packages = add_packages else: packages = _get_packages(tinfoil, workspace, config) else: packages = None if not task: if not packages and not add_packages and workspace: logger.warning('No recipes in workspace, building image %s unmodified', image) elif not packages: logger.warning('No packages to add, building image %s unmodified', image) if packages or extra_append: bb.utils.mkdirhier(os.path.dirname(appendfile)) with open(appendfile, 'w') as afile: if packages: # include packages from workspace recipes into the image afile.write('IMAGE_INSTALL_append = " %s"\n' % ' '.join(packages)) if not task: logger.info('Building image %s with the following ' 'additional packages: %s', image, ' '.join(packages)) if extra_append: for line in extra_append: afile.write('%s\n' % line) if task in ['populate_sdk', 'populate_sdk_ext']: outputdir = rd.getVar('SDK_DEPLOY', True) else: outputdir = rd.getVar('DEPLOY_DIR_IMAGE', True) tinfoil.shutdown() options = '' if task: options += '-c %s' % task # run bitbake to build image (or specified task) try: exec_build_env_command(config.init_path, basepath, 'bitbake %s %s' % (options, image), watch=True) except ExecutionError as err: return (err.exitcode, None) finally: if os.path.isfile(appendfile): os.unlink(appendfile) return (0, outputdir)
def deploy(args, config, basepath, workspace): """Entry point for the devtool 'deploy' subcommand""" import math import oe.recipeutils import oe.package check_workspace_recipe(workspace, args.recipename, checksrc=False) try: host, destdir = args.target.split(':') except ValueError: destdir = '/' else: args.target = host if not destdir.endswith('/'): destdir += '/' tinfoil = setup_tinfoil(basepath=basepath) try: try: rd = tinfoil.parse_recipe(args.recipename) except Exception as e: raise DevtoolError('Exception parsing recipe %s: %s' % (args.recipename, e)) recipe_outdir = rd.getVar('D') if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir): raise DevtoolError( 'No files to deploy - have you built the %s ' 'recipe? If so, the install step has not installed ' 'any files.' % args.recipename) if args.strip and not args.dry_run: # Fakeroot copy to new destination srcdir = recipe_outdir recipe_outdir = os.path.join(rd.getVar('WORKDIR'), 'devtool-deploy-target-stripped') if os.path.isdir(recipe_outdir): bb.utils.remove(recipe_outdir, True) exec_fakeroot(rd, "cp -af %s %s" % (os.path.join(srcdir, '.'), recipe_outdir), shell=True) os.environ['PATH'] = ':'.join( [os.environ['PATH'], rd.getVar('PATH') or '']) oe.package.strip_execs(args.recipename, recipe_outdir, rd.getVar('STRIP'), rd.getVar('libdir'), rd.getVar('base_libdir'), rd) filelist = [] inodes = set({}) ftotalsize = 0 for root, _, files in os.walk(recipe_outdir): for fn in files: fstat = os.lstat(os.path.join(root, fn)) # Get the size in kiB (since we'll be comparing it to the output of du -k) # MUST use lstat() here not stat() or getfilesize() since we don't want to # dereference symlinks if fstat.st_ino in inodes: fsize = 0 else: fsize = int(math.ceil(float(fstat.st_size) / 1024)) inodes.add(fstat.st_ino) ftotalsize += fsize # The path as it would appear on the target fpath = os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn) filelist.append((fpath, fsize)) if args.dry_run: print('Files to be deployed for %s on target %s:' % (args.recipename, args.target)) for item, _ in filelist: print(' %s' % item) return 0 extraoptions = '' if args.no_host_check: extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' if not args.show_status: extraoptions += ' -q' scp_sshexec = '' ssh_sshexec = 'ssh' if args.ssh_exec: scp_sshexec = "-S %s" % args.ssh_exec ssh_sshexec = args.ssh_exec scp_port = '' ssh_port = '' if args.port: scp_port = "-P %s" % args.port ssh_port = "-p %s" % args.port if args.key: extraoptions += ' -i %s' % args.key # In order to delete previously deployed files and have the manifest file on # the target, we write out a shell script and then copy it to the target # so we can then run it (piping tar output to it). # (We cannot use scp here, because it doesn't preserve symlinks.) tmpdir = tempfile.mkdtemp(prefix='devtool') try: tmpscript = '/tmp/devtool_deploy.sh' tmpfilelist = os.path.join(os.path.dirname(tmpscript), 'devtool_deploy.list') shellscript = _prepare_remote_script( deploy=True, verbose=args.show_status, nopreserve=args.no_preserve, nocheckspace=args.no_check_space) # Write out the script to a file with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: f.write(shellscript) # Write out the file list with open(os.path.join(tmpdir, os.path.basename(tmpfilelist)), 'w') as f: f.write('%d\n' % ftotalsize) for fpath, fsize in filelist: f.write('%s %d\n' % (fpath, fsize)) # Copy them to the target ret = subprocess.call("scp %s %s %s %s/* %s:%s" % (scp_sshexec, 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 = exec_fakeroot(rd, 'tar cf - . | %s %s %s %s \'sh %s %s %s %s\'' % (ssh_sshexec, ssh_port, extraoptions, args.target, tmpscript, args.recipename, destdir, tmpfilelist), cwd=recipe_outdir, shell=True) if ret != 0: raise DevtoolError( 'Deploy failed - rerun with -s to get a complete ' 'error message') logger.info('Successfully deployed %s' % recipe_outdir) files_list = [] for root, _, files in os.walk(recipe_outdir): for filename in files: filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) files_list.append(os.path.join(destdir, filename)) finally: tinfoil.shutdown() return 0
def configure_help(args, config, basepath, workspace): """Entry point for the devtool 'configure-help' subcommand""" import oe.utils check_workspace_recipe(workspace, args.recipename) tinfoil = setup_tinfoil(config_only=False, basepath=basepath) try: rd = parse_recipe(config, tinfoil, args.recipename, appends=True, filter_workspace=False) if not rd: return 1 b = rd.getVar('B', True) s = rd.getVar('S', True) configurescript = os.path.join(s, 'configure') confdisabled = 'noexec' in rd.getVarFlags( 'do_configure') or 'do_configure' not in (rd.getVar( '__BBTASKS', False) or []) configureopts = oe.utils.squashspaces( rd.getVar('CONFIGUREOPTS', True) or '') extra_oeconf = oe.utils.squashspaces( rd.getVar('EXTRA_OECONF', True) or '') extra_oecmake = oe.utils.squashspaces( rd.getVar('EXTRA_OECMAKE', True) or '') do_configure = rd.getVar('do_configure', True) or '' do_configure_noexpand = rd.getVar('do_configure', False) or '' packageconfig = rd.getVarFlags('PACKAGECONFIG') or [] autotools = bb.data.inherits_class( 'autotools', rd) and ('oe_runconf' in do_configure or 'autotools_do_configure' in do_configure) cmake = bb.data.inherits_class('cmake', rd) and ('cmake_do_configure' in do_configure) cmake_do_configure = rd.getVar('cmake_do_configure', True) pn = rd.getVar('PN', True) finally: tinfoil.shutdown() if 'doc' in packageconfig: del packageconfig['doc'] if autotools and not os.path.exists(configurescript): logger.info('Running do_configure to generate configure script') try: stdout, _ = exec_build_env_command(config.init_path, basepath, 'bitbake -c configure %s' % msg, args.recipename, stderr=subprocess.STDOUT) except bb.process.ExecutionError: pass if confdisabled or do_configure.strip() in ('', ':'): raise DevtoolError( "do_configure task has been disabled for this recipe") elif args.no_pager and not os.path.exists(configurescript): raise DevtoolError( "No configure script found and no other information to display") else: configopttext = '' if autotools and configureopts: configopttext = ''' Arguments currently passed to the configure script: %s Some of those are fixed.''' % (configureopts + ' ' + extra_oeconf) if extra_oeconf: configopttext += ''' The ones that are specified through EXTRA_OECONF (which you can change or add to easily): %s''' % extra_oeconf elif cmake: in_cmake = False cmake_cmd = '' for line in cmake_do_configure.splitlines(): if in_cmake: cmake_cmd = cmake_cmd + ' ' + line.strip().rstrip('\\') if not line.endswith('\\'): break if line.lstrip().startswith('cmake '): cmake_cmd = line.strip().rstrip('\\') if line.endswith('\\'): in_cmake = True else: break if cmake_cmd: configopttext = ''' The current cmake command line: %s Arguments specified through EXTRA_OECMAKE (which you can change or add to easily) %s''' % (oe.utils.squashspaces(cmake_cmd), extra_oecmake) else: configopttext = ''' The current implementation of cmake_do_configure: cmake_do_configure() { %s } Arguments specified through EXTRA_OECMAKE (which you can change or add to easily) %s''' % (cmake_do_configure.rstrip(), extra_oecmake) elif do_configure: configopttext = ''' The current implementation of do_configure: do_configure() { %s }''' % do_configure.rstrip() if '${EXTRA_OECONF}' in do_configure_noexpand: configopttext += ''' Arguments specified through EXTRA_OECONF (which you can change or add to easily): %s''' % extra_oeconf if packageconfig: configopttext += ''' Some of these options may be controlled through PACKAGECONFIG; for more details please see the recipe.''' if args.arg: helpargs = ' '.join(args.arg) elif cmake: helpargs = '-LH' else: helpargs = '--help' msg = '''configure information for %s ------------------------------------------ %s''' % (pn, configopttext) if cmake: msg += ''' The cmake %s output for %s follows. After "-- Cache values" you should see a list of variables you can add to EXTRA_OECMAKE (prefixed with -D and suffixed with = followed by the desired value, without any spaces). ------------------------------------------''' % (helpargs, pn) elif os.path.exists(configurescript): msg += ''' The ./configure %s output for %s follows. ------------------------------------------''' % (helpargs, pn) olddir = os.getcwd() tmppath = tempfile.mkdtemp() with tempfile.NamedTemporaryFile('w', delete=False) as tf: if not args.no_header: tf.write(msg + '\n') tf.close() try: try: cmd = 'cat %s' % tf.name if cmake: cmd += '; cmake %s %s 2>&1' % (helpargs, s) os.chdir(b) elif os.path.exists(configurescript): cmd += '; %s %s' % (configurescript, helpargs) if sys.stdout.isatty() and not args.no_pager: pager = os.environ.get('PAGER', 'less') cmd = '(%s) | %s' % (cmd, pager) subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError as e: return e.returncode finally: os.chdir(olddir) shutil.rmtree(tmppath) os.remove(tf.name)
def update_recipe(args, config, basepath, workspace): if not args.recipename in workspace: logger.error("no recipe named %s in your workspace" % args.recipename) return -1 # Get initial revision from bbappend appends = glob.glob(os.path.join(config.workspace_path, 'appends', '%s_*.bbappend' % args.recipename)) if not appends: logger.error('unable to find workspace bbappend for recipe %s' % args.recipename) return -1 tinfoil = setup_tinfoil() import bb from oe.patch import GitApplyTree import oe.recipeutils srctree = workspace[args.recipename] commits = [] update_rev = None if args.initial_rev: initial_rev = args.initial_rev else: initial_rev = None with open(appends[0], 'r') as f: for line in f: if line.startswith('# initial_rev:'): initial_rev = line.split(':')[-1].strip() elif line.startswith('# commit:'): commits.append(line.split(':')[-1].strip()) if initial_rev: # Find first actually changed revision (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=srctree) newcommits = stdout.split() for i in xrange(min(len(commits), len(newcommits))): if newcommits[i] == commits[i]: update_rev = commits[i] if not initial_rev: logger.error('Unable to find initial revision - please specify it with --initial-rev') return -1 if not update_rev: update_rev = initial_rev # Find list of existing patches in recipe file recipefile = _get_recipe_file(tinfoil.cooker, args.recipename) if not recipefile: # Error already logged return -1 rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data) existing_patches = oe.recipeutils.get_recipe_patches(rd) removepatches = [] if not args.no_remove: # Get all patches from source tree and check if any should be removed tempdir = tempfile.mkdtemp(prefix='devtool') try: GitApplyTree.extractPatches(srctree, initial_rev, tempdir) newpatches = os.listdir(tempdir) for patch in existing_patches: patchfile = os.path.basename(patch) if patchfile not in newpatches: removepatches.append(patch) finally: shutil.rmtree(tempdir) # Get updated patches from source tree tempdir = tempfile.mkdtemp(prefix='devtool') try: GitApplyTree.extractPatches(srctree, update_rev, tempdir) # Match up and replace existing patches with corresponding new patches updatepatches = False updaterecipe = False newpatches = os.listdir(tempdir) for patch in existing_patches: patchfile = os.path.basename(patch) if patchfile in newpatches: logger.info('Updating patch %s' % patchfile) shutil.move(os.path.join(tempdir, patchfile), patch) newpatches.remove(patchfile) updatepatches = True srcuri = (rd.getVar('SRC_URI', False) or '').split() if newpatches: # Add any patches left over patchdir = os.path.join(os.path.dirname(recipefile), rd.getVar('BPN', True)) bb.utils.mkdirhier(patchdir) for patchfile in newpatches: logger.info('Adding new patch %s' % patchfile) shutil.move(os.path.join(tempdir, patchfile), os.path.join(patchdir, patchfile)) srcuri.append('file://%s' % patchfile) updaterecipe = True if removepatches: # Remove any patches that we don't need for patch in removepatches: patchfile = os.path.basename(patch) for i in xrange(len(srcuri)): if srcuri[i].startswith('file://') and os.path.basename(srcuri[i]).split(';')[0] == patchfile: logger.info('Removing patch %s' % patchfile) srcuri.pop(i) # FIXME "git rm" here would be nice if the file in question is tracked # FIXME there's a chance that this file is referred to by another recipe, in which case deleting wouldn't be the right thing to do os.remove(patch) updaterecipe = True break if updaterecipe: logger.info('Updating recipe %s' % os.path.basename(recipefile)) oe.recipeutils.patch_recipe(rd, recipefile, {'SRC_URI': ' '.join(srcuri)}) elif not updatepatches: # Neither patches nor recipe were updated logger.info('No patches need updating') finally: shutil.rmtree(tempdir) return 0
def sdk_update(args, config, basepath, workspace): """Entry point for devtool sdk-update command""" updateserver = args.updateserver if not updateserver: updateserver = config.get('SDK', 'updateserver', '') logger.debug("updateserver: %s" % updateserver) # Make sure we are using sdk-update from within SDK logger.debug("basepath = %s" % basepath) old_locked_sig_file_path = os.path.join(basepath, 'conf/locked-sigs.inc') if not os.path.exists(old_locked_sig_file_path): logger.error("Not using devtool's sdk-update command from within an extensible SDK. Please specify correct basepath via --basepath option") return -1 else: logger.debug("Found conf/locked-sigs.inc in %s" % basepath) if not '://' in updateserver: logger.error("Update server must be a URL") return -1 layers_dir = os.path.join(basepath, 'layers') conf_dir = os.path.join(basepath, 'conf') # Grab variable values tinfoil = setup_tinfoil(config_only=True, basepath=basepath) try: stamps_dir = tinfoil.config_data.getVar('STAMPS_DIR') sstate_mirrors = tinfoil.config_data.getVar('SSTATE_MIRRORS') site_conf_version = tinfoil.config_data.getVar('SITE_CONF_VERSION') finally: tinfoil.shutdown() tmpsdk_dir = tempfile.mkdtemp() try: os.makedirs(os.path.join(tmpsdk_dir, 'conf')) new_locked_sig_file_path = os.path.join(tmpsdk_dir, 'conf', 'locked-sigs.inc') # Fetch manifest from server tmpmanifest = os.path.join(tmpsdk_dir, 'conf', 'sdk-conf-manifest') ret = subprocess.call("wget -q -O %s %s/conf/sdk-conf-manifest" % (tmpmanifest, updateserver), shell=True) changedfiles = check_manifest(tmpmanifest, basepath) if not changedfiles: logger.info("Already up-to-date") return 0 # Update metadata logger.debug("Updating metadata via git ...") #Check for the status before doing a fetch and reset if os.path.exists(os.path.join(basepath, 'layers/.git')): out = subprocess.check_output("git status --porcelain", shell=True, cwd=layers_dir) if not out: ret = subprocess.call("git fetch --all; git reset --hard @{u}", shell=True, cwd=layers_dir) else: logger.error("Failed to update metadata as there have been changes made to it. Aborting."); logger.error("Changed files:\n%s" % out); return -1 else: ret = -1 if ret != 0: ret = subprocess.call("git clone %s/layers/.git" % updateserver, shell=True, cwd=tmpsdk_dir) if ret != 0: logger.error("Updating metadata via git failed") return ret logger.debug("Updating conf files ...") for changedfile in changedfiles: ret = subprocess.call("wget -q -O %s %s/%s" % (changedfile, updateserver, changedfile), shell=True, cwd=tmpsdk_dir) if ret != 0: logger.error("Updating %s failed" % changedfile) return ret # Check if UNINATIVE_CHECKSUM changed uninative = False if 'conf/local.conf' in changedfiles: def read_uninative_checksums(fn): chksumitems = [] with open(fn, 'r') as f: for line in f: if line.startswith('UNINATIVE_CHECKSUM'): splitline = re.split(r'[\[\]"\']', line) if len(splitline) > 3: chksumitems.append((splitline[1], splitline[3])) return chksumitems oldsums = read_uninative_checksums(os.path.join(basepath, 'conf/local.conf')) newsums = read_uninative_checksums(os.path.join(tmpsdk_dir, 'conf/local.conf')) if oldsums != newsums: uninative = True for buildarch, chksum in newsums: uninative_file = os.path.join('downloads', 'uninative', chksum, '%s-nativesdk-libc.tar.bz2' % buildarch) mkdir(os.path.join(tmpsdk_dir, os.path.dirname(uninative_file))) ret = subprocess.call("wget -q -O %s %s/%s" % (uninative_file, updateserver, uninative_file), shell=True, cwd=tmpsdk_dir) # Ok, all is well at this point - move everything over tmplayers_dir = os.path.join(tmpsdk_dir, 'layers') if os.path.exists(tmplayers_dir): shutil.rmtree(layers_dir) shutil.move(tmplayers_dir, layers_dir) for changedfile in changedfiles: destfile = os.path.join(basepath, changedfile) os.remove(destfile) shutil.move(os.path.join(tmpsdk_dir, changedfile), destfile) os.remove(os.path.join(conf_dir, 'sdk-conf-manifest')) shutil.move(tmpmanifest, conf_dir) if uninative: shutil.rmtree(os.path.join(basepath, 'downloads', 'uninative')) shutil.move(os.path.join(tmpsdk_dir, 'downloads', 'uninative'), os.path.join(basepath, 'downloads')) if not sstate_mirrors: with open(os.path.join(conf_dir, 'site.conf'), 'a') as f: f.write('SCONF_VERSION = "%s"\n' % site_conf_version) f.write('SSTATE_MIRRORS_append = " file://.* %s/sstate-cache/PATH \\n "\n' % updateserver) finally: shutil.rmtree(tmpsdk_dir) if not args.skip_prepare: # Find all potentially updateable tasks sdk_update_targets = [] tasks = ['do_populate_sysroot', 'do_packagedata'] for root, _, files in os.walk(stamps_dir): for fn in files: if not '.sigdata.' in fn: for task in tasks: if '.%s.' % task in fn or '.%s_setscene.' % task in fn: sdk_update_targets.append('%s:%s' % (os.path.basename(root), task)) # Run bitbake command for the whole SDK logger.info("Preparing build system... (This may take some time.)") try: exec_build_env_command(config.init_path, basepath, 'bitbake --setscene-only %s' % ' '.join(sdk_update_targets), stderr=subprocess.STDOUT) output, _ = exec_build_env_command(config.init_path, basepath, 'bitbake -n %s' % ' '.join(sdk_update_targets), stderr=subprocess.STDOUT) runlines = [] for line in output.splitlines(): if 'Running task ' in line: runlines.append(line) if runlines: logger.error('Unexecuted tasks found in preparation log:\n %s' % '\n '.join(runlines)) return -1 except bb.process.ExecutionError as e: logger.error('Preparation failed:\n%s' % e.stdout) return -1 return 0
def deploy(args, config, basepath, workspace): """Entry point for the devtool 'deploy' subcommand""" import re import math import oe.recipeutils check_workspace_recipe(workspace, args.recipename, checksrc=False) try: host, destdir = args.target.split(':') except ValueError: destdir = '/' else: args.target = host if not destdir.endswith('/'): destdir += '/' tinfoil = setup_tinfoil(basepath=basepath) try: try: rd = tinfoil.parse_recipe(args.recipename) except Exception as e: raise DevtoolError('Exception parsing recipe %s: %s' % (args.recipename, e)) recipe_outdir = rd.getVar('D') if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir): raise DevtoolError('No files to deploy - have you built the %s ' 'recipe? If so, the install step has not installed ' 'any files.' % args.recipename) filelist = [] ftotalsize = 0 for root, _, files in os.walk(recipe_outdir): for fn in files: # Get the size in kiB (since we'll be comparing it to the output of du -k) # MUST use lstat() here not stat() or getfilesize() since we don't want to # dereference symlinks fsize = int(math.ceil(float(os.lstat(os.path.join(root, fn)).st_size)/1024)) ftotalsize += fsize # The path as it would appear on the target fpath = os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn) filelist.append((fpath, fsize)) if args.dry_run: print('Files to be deployed for %s on target %s:' % (args.recipename, args.target)) for item, _ in filelist: print(' %s' % item) return 0 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 not args.port: raise DevtoolError("If you specify -P/--port then you must provide the port to be used to connect to the target") else: scp_port = "-P %s" % args.port ssh_port = "-p %s" % args.port # In order to delete previously deployed files and have the manifest file on # the target, we write out a shell script and then copy it to the target # so we can then run it (piping tar output to it). # (We cannot use scp here, because it doesn't preserve symlinks.) tmpdir = tempfile.mkdtemp(prefix='devtool') try: tmpscript = '/tmp/devtool_deploy.sh' tmpfilelist = os.path.join(os.path.dirname(tmpscript), 'devtool_deploy.list') shellscript = _prepare_remote_script(deploy=True, verbose=args.show_status, nopreserve=args.no_preserve, nocheckspace=args.no_check_space) # Write out the script to a file with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: f.write(shellscript) # Write out the file list with open(os.path.join(tmpdir, os.path.basename(tmpfilelist)), 'w') as f: f.write('%d\n' % ftotalsize) for fpath, fsize in filelist: f.write('%s %d\n' % (fpath, fsize)) # Copy them 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 = exec_fakeroot(rd, 'tar cf - . | ssh %s %s %s \'sh %s %s %s %s\'' % (ssh_port, extraoptions, args.target, tmpscript, args.recipename, destdir, tmpfilelist), cwd=recipe_outdir, shell=True) if ret != 0: raise DevtoolError('Deploy failed - rerun with -s to get a complete ' 'error message') logger.info('Successfully deployed %s' % recipe_outdir) files_list = [] for root, _, files in os.walk(recipe_outdir): for filename in files: filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) files_list.append(os.path.join(destdir, filename)) finally: tinfoil.shutdown() return 0
def deploy(args, config, basepath, workspace): """Entry point for the devtool 'deploy' subcommand""" import re import oe.recipeutils check_workspace_recipe(workspace, args.recipename, checksrc=False) try: host, destdir = args.target.split(':') except ValueError: destdir = '/' else: args.target = host deploy_dir = os.path.join(basepath, 'target_deploy', args.target) deploy_file = os.path.join(deploy_dir, args.recipename + '.list') tinfoil = setup_tinfoil(basepath=basepath) try: rd = oe.recipeutils.parse_recipe_simple(tinfoil.cooker, args.recipename, tinfoil.config_data) except Exception as e: raise DevtoolError('Exception parsing recipe %s: %s' % (args.recipename, e)) recipe_outdir = rd.getVar('D', True) if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir): raise DevtoolError('No files to deploy - have you built the %s ' 'recipe? If so, the install step has not installed ' 'any files.' % args.recipename) if args.dry_run: print('Files to be deployed for %s on target %s:' % (args.recipename, args.target)) for root, _, files in os.walk(recipe_outdir): for fn in files: print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)) return 0 if os.path.exists(deploy_file): if undeploy(args, config, basepath, workspace): # Error already shown return 1 extraoptions = '' if args.no_host_check: extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' if args.show_status: tarextractopts = 'xv' else: tarextractopts = 'x' extraoptions += ' -q' # We cannot use scp here, because it doesn't preserve symlinks ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'tar %s -C %s -f -\'' % (extraoptions, args.target, tarextractopts, destdir), cwd=recipe_outdir, shell=True) if ret != 0: raise DevtoolError('Deploy failed - rerun with -s to get a complete ' 'error message') logger.info('Successfully deployed %s' % recipe_outdir) if not os.path.exists(deploy_dir): os.makedirs(deploy_dir) files_list = [] for root, _, files in os.walk(recipe_outdir): for filename in files: filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) files_list.append(os.path.join(destdir, filename)) with open(deploy_file, 'w') as fobj: fobj.write('\n'.join(files_list)) return 0
def configure_help(args, config, basepath, workspace): """Entry point for the devtool 'configure-help' subcommand""" import oe.utils check_workspace_recipe(workspace, args.recipename) tinfoil = setup_tinfoil(config_only=False, basepath=basepath) try: rd = parse_recipe(config, tinfoil, args.recipename, appends=True, filter_workspace=False) if not rd: return 1 b = rd.getVar('B') s = rd.getVar('S') configurescript = os.path.join(s, 'configure') confdisabled = 'noexec' in rd.getVarFlags('do_configure') or 'do_configure' not in (rd.getVar('__BBTASKS', False) or []) configureopts = oe.utils.squashspaces(rd.getVar('CONFIGUREOPTS') or '') extra_oeconf = oe.utils.squashspaces(rd.getVar('EXTRA_OECONF') or '') extra_oecmake = oe.utils.squashspaces(rd.getVar('EXTRA_OECMAKE') or '') do_configure = rd.getVar('do_configure') or '' do_configure_noexpand = rd.getVar('do_configure', False) or '' packageconfig = rd.getVarFlags('PACKAGECONFIG') or [] autotools = bb.data.inherits_class('autotools', rd) and ('oe_runconf' in do_configure or 'autotools_do_configure' in do_configure) cmake = bb.data.inherits_class('cmake', rd) and ('cmake_do_configure' in do_configure) cmake_do_configure = rd.getVar('cmake_do_configure') pn = rd.getVar('PN') finally: tinfoil.shutdown() if 'doc' in packageconfig: del packageconfig['doc'] if autotools and not os.path.exists(configurescript): logger.info('Running do_configure to generate configure script') try: stdout, _ = exec_build_env_command(config.init_path, basepath, 'bitbake -c configure %s' % args.recipename, stderr=subprocess.STDOUT) except bb.process.ExecutionError: pass if confdisabled or do_configure.strip() in ('', ':'): raise DevtoolError("do_configure task has been disabled for this recipe") elif args.no_pager and not os.path.exists(configurescript): raise DevtoolError("No configure script found and no other information to display") else: configopttext = '' if autotools and configureopts: configopttext = ''' Arguments currently passed to the configure script: %s Some of those are fixed.''' % (configureopts + ' ' + extra_oeconf) if extra_oeconf: configopttext += ''' The ones that are specified through EXTRA_OECONF (which you can change or add to easily): %s''' % extra_oeconf elif cmake: in_cmake = False cmake_cmd = '' for line in cmake_do_configure.splitlines(): if in_cmake: cmake_cmd = cmake_cmd + ' ' + line.strip().rstrip('\\') if not line.endswith('\\'): break if line.lstrip().startswith('cmake '): cmake_cmd = line.strip().rstrip('\\') if line.endswith('\\'): in_cmake = True else: break if cmake_cmd: configopttext = ''' The current cmake command line: %s Arguments specified through EXTRA_OECMAKE (which you can change or add to easily) %s''' % (oe.utils.squashspaces(cmake_cmd), extra_oecmake) else: configopttext = ''' The current implementation of cmake_do_configure: cmake_do_configure() { %s } Arguments specified through EXTRA_OECMAKE (which you can change or add to easily) %s''' % (cmake_do_configure.rstrip(), extra_oecmake) elif do_configure: configopttext = ''' The current implementation of do_configure: do_configure() { %s }''' % do_configure.rstrip() if '${EXTRA_OECONF}' in do_configure_noexpand: configopttext += ''' Arguments specified through EXTRA_OECONF (which you can change or add to easily): %s''' % extra_oeconf if packageconfig: configopttext += ''' Some of these options may be controlled through PACKAGECONFIG; for more details please see the recipe.''' if args.arg: helpargs = ' '.join(args.arg) elif cmake: helpargs = '-LH' else: helpargs = '--help' msg = '''configure information for %s ------------------------------------------ %s''' % (pn, configopttext) if cmake: msg += ''' The cmake %s output for %s follows. After "-- Cache values" you should see a list of variables you can add to EXTRA_OECMAKE (prefixed with -D and suffixed with = followed by the desired value, without any spaces). ------------------------------------------''' % (helpargs, pn) elif os.path.exists(configurescript): msg += ''' The ./configure %s output for %s follows. ------------------------------------------''' % (helpargs, pn) olddir = os.getcwd() tmppath = tempfile.mkdtemp() with tempfile.NamedTemporaryFile('w', delete=False) as tf: if not args.no_header: tf.write(msg + '\n') tf.close() try: try: cmd = 'cat %s' % tf.name if cmake: cmd += '; cmake %s %s 2>&1' % (helpargs, s) os.chdir(b) elif os.path.exists(configurescript): cmd += '; %s %s' % (configurescript, helpargs) if sys.stdout.isatty() and not args.no_pager: pager = os.environ.get('PAGER', 'less') cmd = '(%s) | %s' % (cmd, pager) subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError as e: return e.returncode finally: os.chdir(olddir) shutil.rmtree(tmppath) os.remove(tf.name)
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
def deploy(args, config, basepath, workspace): """Entry point for the devtool 'deploy' subcommand""" import re import oe.recipeutils if not args.recipename in workspace: logger.error("no recipe named %s in your workspace" % args.recipename) return -1 try: host, destdir = args.target.split(':') except ValueError: destdir = '/' else: args.target = host deploy_dir = os.path.join(basepath, 'target_deploy', args.target) deploy_file = os.path.join(deploy_dir, args.recipename + '.list') tinfoil = setup_tinfoil() try: rd = oe.recipeutils.parse_recipe_simple(tinfoil.cooker, args.recipename, tinfoil.config_data) except Exception as e: logger.error('Exception parsing recipe %s: %s' % (args.recipename, e)) return 2 recipe_outdir = rd.getVar('D', True) if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir): logger.error('No files to deploy - have you built the %s recipe? If so, the install step has not installed any files.' % args.recipename) return -1 if args.dry_run: print('Files to be deployed for %s on target %s:' % (args.recipename, args.target)) for root, _, files in os.walk(recipe_outdir): for fn in files: print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)) return 0 if os.path.exists(deploy_file): if undeploy(args, config, basepath, workspace): # Error already shown return -1 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 -r %s %s/* %s:%s' % (extraoptions, recipe_outdir, args.target, destdir), shell=True) if ret != 0: logger.error('Deploy failed - rerun with -s to get a complete error message') return ret logger.info('Successfully deployed %s' % recipe_outdir) if not os.path.exists(deploy_dir): os.makedirs(deploy_dir) files_list = [] for root, _, files in os.walk(recipe_outdir): for filename in files: filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) files_list.append(os.path.join(destdir, filename)) with open(deploy_file, 'w') as fobj: fobj.write('\n'.join(files_list)) return 0
def modify(args, config, basepath, workspace): import bb import oe.recipeutils if args.recipename in workspace: logger.error("recipe %s is already in your workspace" % args.recipename) return -1 if not args.extract: if not os.path.isdir(args.srctree): logger.error("directory %s does not exist or not a directory (specify -x to extract source from recipe)" % args.srctree) return -1 tinfoil = setup_tinfoil() recipefile = _get_recipe_file(tinfoil.cooker, args.recipename) if not recipefile: # Error already logged return -1 rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data) initial_rev = None commits = [] srctree = os.path.abspath(args.srctree) if args.extract: initial_rev = _extract_source(args.srctree, False, args.branch, rd) if not initial_rev: return -1 # Get list of commits since this revision (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=args.srctree) commits = stdout.split() else: if os.path.exists(os.path.join(args.srctree, '.git')): (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=args.srctree) initial_rev = stdout.rstrip() # Handle if S is set to a subdirectory of the source s = rd.getVar('S', True) workdir = rd.getVar('WORKDIR', True) if s != workdir and os.path.dirname(s) != workdir: srcsubdir = os.sep.join(os.path.relpath(s, workdir).split(os.sep)[1:]) srctree = os.path.join(srctree, srcsubdir) appendpath = os.path.join(config.workspace_path, 'appends') if not os.path.exists(appendpath): os.makedirs(appendpath) appendname = os.path.splitext(os.path.basename(recipefile))[0] if args.wildcard: appendname = re.sub(r'_.*', '_%', appendname) appendfile = os.path.join(appendpath, appendname + '.bbappend') with open(appendfile, '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' % (args.recipename, srctree)) if bb.data.inherits_class('autotools-brokensep', rd): logger.info('using source tree as build directory since original recipe inherits autotools-brokensep') f.write('EXTERNALSRC_BUILD_pn-%s = "%s"\n' % (args.recipename, srctree)) if initial_rev: f.write('\n# initial_rev: %s\n' % initial_rev) for commit in commits: f.write('# commit: %s\n' % commit) _add_md5(config, args.recipename, appendfile) logger.info('Recipe %s now set up to build from %s' % (args.recipename, srctree)) return 0