blob: a02b1e9b0ec90441479b2039e1ee0895c1166070 [file] [log] [blame]
#
# Copyright OpenEmbedded Contributors
#
# SPDX-License-Identifier: MIT
#
# 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 [f for f in local_files if f.endswith('scc')]:
with open(local_files[key], 'r') as sccfile:
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 cfg not in local_files.values():
local_files[line[-1]] = cfg
shutil.copy2(cfg, workdir)
# 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))
localdata.setVar('FILESOVERRIDES', ':'.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.setVar('OVERRIDES', ':'.join(no_overrides + [override]))
localdata.setVar('FILESOVERRIDES', ':'.join(no_overrides + [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)
}