def add(args, config, basepath, workspace): """Entry point for the devtool 'add' subcommand""" import bb import oe.recipeutils if args.recipename in workspace: raise DevtoolError("recipe %s is already in your workspace" % args.recipename) reason = oe.recipeutils.validate_pn(args.recipename) if reason: raise DevtoolError(reason) srctree = os.path.abspath(args.srctree) if os.path.exists(srctree): if args.fetch: if not os.path.isdir(srctree): raise DevtoolError("Cannot fetch into source tree path %s as " "it exists and is not a directory" % srctree) elif os.listdir(srctree): raise DevtoolError("Cannot fetch into source tree path %s as " "it already exists and is non-empty" % srctree) elif not args.fetch: raise DevtoolError("Specified source tree %s could not be found" % srctree) appendpath = os.path.join(config.workspace_path, 'appends') if not os.path.exists(appendpath): os.makedirs(appendpath) recipedir = os.path.join(config.workspace_path, 'recipes', args.recipename) bb.utils.mkdirhier(recipedir) rfv = None if args.version: if '_' in args.version or ' ' in args.version: raise DevtoolError('Invalid version string "%s"' % args.version) rfv = args.version if args.fetch: if args.fetch.startswith('git://'): rfv = 'git' elif args.fetch.startswith('svn://'): rfv = 'svn' elif args.fetch.startswith('hg://'): rfv = 'hg' if rfv: bp = "%s_%s" % (args.recipename, rfv) else: bp = args.recipename recipefile = os.path.join(recipedir, "%s.bb" % bp) if args.color == 'auto' and sys.stdout.isatty(): color = 'always' else: color = args.color extracmdopts = '' if args.fetch: source = args.fetch extracmdopts = '-x %s' % srctree else: source = srctree if args.version: extracmdopts += ' -V %s' % args.version if args.binary: extracmdopts += ' -b' try: stdout, _ = exec_build_env_command(config.init_path, basepath, 'recipetool --color=%s create -o %s "%s" %s' % (color, recipefile, source, extracmdopts)) except bb.process.ExecutionError as e: raise DevtoolError('Command \'%s\' failed:\n%s' % (e.command, e.stdout)) _add_md5(config, args.recipename, recipefile) if args.fetch and not args.no_git: setup_git_repo(srctree, args.version, 'devtool') initial_rev = None if os.path.exists(os.path.join(srctree, '.git')): (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) initial_rev = stdout.rstrip() tinfoil = setup_tinfoil(config_only=True, basepath=basepath) rd = oe.recipeutils.parse_recipe(recipefile, None, tinfoil.config_data) if not rd: return 1 appendfile = os.path.join(appendpath, '%s.bbappend' % bp) with open(appendfile, 'w') as f: f.write('inherit externalsrc\n') f.write('EXTERNALSRC = "%s"\n' % srctree) b_is_s = use_external_build(args.same_dir, args.no_same_dir, rd) if b_is_s: f.write('EXTERNALSRC_BUILD = "%s"\n' % srctree) if initial_rev: f.write('\n# initial_rev: %s\n' % initial_rev) if args.binary: f.write('do_install_append() {\n') f.write(' rm -rf ${D}/.git\n') f.write(' rm -f ${D}/singletask.lock\n') f.write('}\n') _add_md5(config, args.recipename, appendfile) logger.info('Recipe %s has been automatically created; further editing may be required to make it fully functional' % recipefile) tinfoil.shutdown() return 0
def _extract_source(srctree, keep_temp, devbranch, d): """Extract sources of a recipe""" import bb.event import oe.recipeutils def eventfilter(name, handler, event, d): """Bitbake event filter for devtool extract operation""" if name == 'base_eventhandler': return True else: return False if hasattr(bb.event, 'set_eventfilter'): bb.event.set_eventfilter(eventfilter) pn = d.getVar('PN', True) _check_compatible_recipe(pn, d) if os.path.exists(srctree): if not os.path.isdir(srctree): raise DevtoolError("output path %s exists and is not a directory" % srctree) elif os.listdir(srctree): raise DevtoolError("output path %s already exists and is " "non-empty" % srctree) if 'noexec' in (d.getVarFlags('do_unpack', False) or []): raise DevtoolError("The %s recipe has do_unpack disabled, unable to " "extract source" % pn) # Prepare for shutil.move later on bb.utils.mkdirhier(srctree) os.rmdir(srctree) # We don't want notes to be printed, they are too verbose origlevel = bb.logger.getEffectiveLevel() if logger.getEffectiveLevel() > logging.DEBUG: bb.logger.setLevel(logging.WARNING) initial_rev = None tempdir = tempfile.mkdtemp(prefix='devtool') try: crd = d.createCopy() # Make a subdir so we guard against WORKDIR==S workdir = os.path.join(tempdir, 'workdir') crd.setVar('WORKDIR', workdir) crd.setVar('T', os.path.join(tempdir, 'temp')) if not crd.getVar('S', True).startswith(workdir): # Usually a shared workdir recipe (kernel, gcc) # Try to set a reasonable default if bb.data.inherits_class('kernel', d): crd.setVar('S', '${WORKDIR}/source') else: crd.setVar('S', '${WORKDIR}/%s' % os.path.basename(d.getVar('S', True))) if bb.data.inherits_class('kernel', d): # We don't want to move the source to STAGING_KERNEL_DIR here crd.setVar('STAGING_KERNEL_DIR', '${S}') task_executor = BbTaskExecutor(crd) crd.setVar('EXTERNALSRC_forcevariable', '') logger.info('Fetching %s...' % pn) task_executor.exec_func('do_fetch', False) logger.info('Unpacking...') task_executor.exec_func('do_unpack', False) if bb.data.inherits_class('kernel-yocto', d): # Extra step for kernel to populate the source directory logger.info('Doing kernel checkout...') task_executor.exec_func('do_kernel_checkout', False) srcsubdir = crd.getVar('S', True) # Move local source files into separate subdir recipe_patches = [os.path.basename(patch) for patch in oe.recipeutils.get_recipe_patches(crd)] local_files = oe.recipeutils.get_recipe_local_files(crd) local_files = [fname for fname in local_files if os.path.exists(os.path.join(workdir, fname))] if local_files: for fname in local_files: _move_file(os.path.join(workdir, fname), os.path.join(tempdir, 'oe-local-files', fname)) with open(os.path.join(tempdir, 'oe-local-files', '.gitignore'), 'w') as f: f.write('# Ignore local files, by default. Remove this file ' 'if you want to commit the directory to Git\n*\n') if srcsubdir == workdir: # Find non-patch non-local sources that were "unpacked" to srctree # directory src_files = [fname for fname in _ls_tree(workdir) if os.path.basename(fname) not in recipe_patches] # Force separate S so that patch files can be left out from srctree srcsubdir = tempfile.mkdtemp(dir=workdir) crd.setVar('S', srcsubdir) # Move source files to S for path in src_files: _move_file(os.path.join(workdir, path), os.path.join(srcsubdir, path)) elif os.path.dirname(srcsubdir) != workdir: # Handle if S is set to a subdirectory of the source srcsubdir = os.path.join(workdir, os.path.relpath(srcsubdir, workdir).split(os.sep)[0]) scriptutils.git_convert_standalone_clone(srcsubdir) patchdir = os.path.join(srcsubdir, 'patches') haspatches = False if os.path.exists(patchdir): if os.listdir(patchdir): haspatches = True else: os.rmdir(patchdir) # Make sure that srcsubdir exists bb.utils.mkdirhier(srcsubdir) if not os.path.exists(srcsubdir) or not os.listdir(srcsubdir): logger.warning("no source unpacked to S, either the %s recipe " "doesn't use any source or the correct source " "directory could not be determined" % pn) setup_git_repo(srcsubdir, crd.getVar('PV', True), devbranch) (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srcsubdir) initial_rev = stdout.rstrip() crd.setVar('PATCHTOOL', 'git') logger.info('Patching...') task_executor.exec_func('do_patch', False) bb.process.run('git tag -f devtool-patched', cwd=srcsubdir) if os.path.exists(patchdir): shutil.rmtree(patchdir) if haspatches: bb.process.run('git checkout patches', cwd=srcsubdir) # Move oe-local-files directory to srctree if os.path.exists(os.path.join(tempdir, 'oe-local-files')): logger.info('Adding local source files to srctree...') shutil.move(os.path.join(tempdir, 'oe-local-files'), srcsubdir) shutil.move(srcsubdir, srctree) finally: bb.logger.setLevel(origlevel) if keep_temp: logger.info('Preserving temporary directory %s' % tempdir) else: shutil.rmtree(tempdir) return initial_rev