# Development tool - source extraction helper class # # NOTE: this class is intended for use by devtool and should not be # inherited manually. # # Copyright (C) 2014-2017 Intel Corporation # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. DEVTOOL_TEMPDIR ?= "" DEVTOOL_PATCH_SRCDIR = "${DEVTOOL_TEMPDIR}/patchworkdir" python() { tempdir = d.getVar('DEVTOOL_TEMPDIR') if not tempdir: bb.fatal('devtool-source class is for internal use by devtool only') # Make a subdir so we guard against WORKDIR==S workdir = os.path.join(tempdir, 'workdir') d.setVar('WORKDIR', workdir) if not d.getVar('S').startswith(workdir): # Usually a shared workdir recipe (kernel, gcc) # Try to set a reasonable default if bb.data.inherits_class('kernel', d): d.setVar('S', '${WORKDIR}/source') else: d.setVar('S', '${WORKDIR}/%s' % os.path.basename(d.getVar('S'))) if bb.data.inherits_class('kernel', d): # We don't want to move the source to STAGING_KERNEL_DIR here d.setVar('STAGING_KERNEL_DIR', '${S}') d.setVar('STAMPS_DIR', os.path.join(tempdir, 'stamps')) d.setVar('T', os.path.join(tempdir, 'temp')) # Hook in pre/postfuncs is_kernel_yocto = bb.data.inherits_class('kernel-yocto', d) if is_kernel_yocto: unpacktask = 'do_kernel_checkout' d.appendVarFlag('do_configure', 'postfuncs', ' devtool_post_configure') else: unpacktask = 'do_unpack' d.appendVarFlag(unpacktask, 'postfuncs', ' devtool_post_unpack') d.prependVarFlag('do_patch', 'prefuncs', ' devtool_pre_patch') d.appendVarFlag('do_patch', 'postfuncs', ' devtool_post_patch') # NOTE: in order for the patch stuff to be fully functional, # PATCHTOOL and PATCH_COMMIT_FUNCTIONS need to be set; we can't # do that here because we can't guarantee the order of the anonymous # functions, so it gets done in the bbappend we create. } python devtool_post_unpack() { import oe.recipeutils import shutil sys.path.insert(0, os.path.join(d.getVar('COREBASE'), 'scripts', 'lib')) import scriptutils from devtool import setup_git_repo tempdir = d.getVar('DEVTOOL_TEMPDIR') workdir = d.getVar('WORKDIR') srcsubdir = d.getVar('S') def _move_file(src, dst): """Move a file. Creates all the directory components of destination path.""" dst_d = os.path.dirname(dst) if dst_d: bb.utils.mkdirhier(dst_d) shutil.move(src, dst) def _ls_tree(directory): """Recursive listing of files in a directory""" ret = [] for root, dirs, files in os.walk(directory): ret.extend([os.path.relpath(os.path.join(root, fname), directory) for fname in files]) return ret is_kernel_yocto = bb.data.inherits_class('kernel-yocto', d) # Move local source files into separate subdir recipe_patches = [os.path.basename(patch) for patch in oe.recipeutils.get_recipe_patches(d)] local_files = oe.recipeutils.get_recipe_local_files(d) if is_kernel_yocto: for key in local_files.copy(): if key.endswith('scc'): sccfile = open(local_files[key], 'r') for l in sccfile: line = l.split() if line and line[0] in ('kconf', 'patch'): cfg = os.path.join(os.path.dirname(local_files[key]), line[-1]) if not cfg in local_files.values(): local_files[line[-1]] = cfg shutil.copy2(cfg, workdir) sccfile.close() # Ignore local files with subdir={BP} srcabspath = os.path.abspath(srcsubdir) local_files = [fname for fname in local_files if os.path.exists(os.path.join(workdir, fname)) and (srcabspath == workdir or not os.path.join(workdir, fname).startswith(srcabspath + os.sep))] 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] srcsubdir = d.getVar('DEVTOOL_PATCH_SRCDIR') # 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) # Make sure that srcsubdir exists bb.utils.mkdirhier(srcsubdir) if not os.listdir(srcsubdir): bb.warn("No source unpacked to S - either the %s recipe " "doesn't use any source or the correct source " "directory could not be determined" % d.getVar('PN')) devbranch = d.getVar('DEVTOOL_DEVBRANCH') setup_git_repo(srcsubdir, d.getVar('PV'), devbranch, d=d) (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srcsubdir) initial_rev = stdout.rstrip() with open(os.path.join(tempdir, 'initial_rev'), 'w') as f: f.write(initial_rev) with open(os.path.join(tempdir, 'srcsubdir'), 'w') as f: f.write(srcsubdir) } python devtool_pre_patch() { if d.getVar('S') == d.getVar('WORKDIR'): d.setVar('S', '${DEVTOOL_PATCH_SRCDIR}') } python devtool_post_patch() { import shutil tempdir = d.getVar('DEVTOOL_TEMPDIR') with open(os.path.join(tempdir, 'srcsubdir'), 'r') as f: srcsubdir = f.read() with open(os.path.join(tempdir, 'initial_rev'), 'r') as f: initial_rev = f.read() def rm_patches(): patches_dir = os.path.join(srcsubdir, 'patches') if os.path.exists(patches_dir): shutil.rmtree(patches_dir) # Restore any "patches" directory that was actually part of the source tree try: bb.process.run('git checkout -- patches', cwd=srcsubdir) except bb.process.ExecutionError: pass extra_overrides = d.getVar('DEVTOOL_EXTRA_OVERRIDES') if extra_overrides: extra_overrides = set(extra_overrides.split(':')) devbranch = d.getVar('DEVTOOL_DEVBRANCH') default_overrides = d.getVar('OVERRIDES').split(':') no_overrides = [] # First, we may have some overrides that are referred to in the recipe set in # our configuration, so we need to make a branch that excludes those for override in default_overrides: if override not in extra_overrides: no_overrides.append(override) if default_overrides != no_overrides: # Some overrides are active in the current configuration, so # we need to create a branch where none of the overrides are active bb.process.run('git checkout %s -b devtool-no-overrides' % initial_rev, cwd=srcsubdir) # Run do_patch function with the override applied localdata = bb.data.createCopy(d) localdata.setVar('OVERRIDES', ':'.join(no_overrides)) bb.build.exec_func('do_patch', localdata) rm_patches() # Now we need to reconcile the dev branch with the no-overrides one # (otherwise we'd likely be left with identical commits that have different hashes) bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir) bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir) else: bb.process.run('git checkout %s -b devtool-no-overrides' % devbranch, cwd=srcsubdir) for override in extra_overrides: localdata = bb.data.createCopy(d) if override in default_overrides: bb.process.run('git branch devtool-override-%s %s' % (override, devbranch), cwd=srcsubdir) else: # Reset back to the initial commit on a new branch bb.process.run('git checkout %s -b devtool-override-%s' % (initial_rev, override), cwd=srcsubdir) # Run do_patch function with the override applied localdata.appendVar('OVERRIDES', ':%s' % override) bb.build.exec_func('do_patch', localdata) rm_patches() # Now we need to reconcile the new branch with the no-overrides one # (otherwise we'd likely be left with identical commits that have different hashes) bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir) bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir) bb.process.run('git tag -f devtool-patched', cwd=srcsubdir) } python devtool_post_configure() { import shutil tempdir = d.getVar('DEVTOOL_TEMPDIR') shutil.copy2(os.path.join(d.getVar('B'), '.config'), tempdir) }