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 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 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 build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" check_workspace_recipe(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
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 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") else: check_workspace_recipe(workspace, args.recipename, checksrc=False) elif not args.all: raise DevtoolError("Recipe must be specified, or specify -a/--all to " "reset all recipes") if args.all: recipes = workspace.keys() else: recipes = [args.recipename] if recipes and not args.no_clean: if len(recipes) == 1: logger.info('Cleaning sysroot for recipe %s...' % recipes[0]) else: logger.info('Cleaning sysroot for recipes %s...' % ', '.join(recipes)) try: exec_build_env_command(config.init_path, basepath, 'bitbake -c clean %s' % ' '.join(recipes)) 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)) for pn in recipes: _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)) _move_file(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
def build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" workspacepn = check_workspace_recipe(workspace, args.recipename, bbclassextend=True) build_tasks = _get_build_tasks(config) 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 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 _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 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 build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" check_workspace_recipe(workspace, args.recipename) build_task = _get_build_task(config) bbappend = workspace[args.recipename]["bbappend"] if args.disable_parallel_make: logger.info("Disabling 'make' parallelism") _set_file_values(bbappend, {"PARALLEL_MAKE": ""}) 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 finally: if args.disable_parallel_make: _set_file_values(bbappend, {"PARALLEL_MAKE": None}) return 0
def build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" check_workspace_recipe(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
def update_recipe(args, config, basepath, workspace): """Entry point for the devtool 'update-recipe' subcommand""" check_workspace_recipe(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(basepath=basepath, tracking=True) 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 build(args, config, basepath, workspace): """Entry point for the devtool 'build' subcommand""" check_workspace_recipe(workspace, args.recipename) build_task = _get_build_task(config) bbappend = workspace[args.recipename]['bbappend'] if args.disable_parallel_make: logger.info("Disabling 'make' parallelism") _set_file_values(bbappend, {'PARALLEL_MAKE': ''}) 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 finally: if args.disable_parallel_make: _set_file_values(bbappend, {'PARALLEL_MAKE': None}) return 0
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 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 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 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