DEVTOOL_TEMPDIR ?= ""
-DEVTOOL_PATCH_SRCDIR = "${DEVTOOL_TEMPDIR}/patchworkdir"
-
python() {
tempdir = d.getVar('DEVTOOL_TEMPDIR')
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,
tempdir = d.getVar('DEVTOOL_TEMPDIR')
workdir = d.getVar('WORKDIR')
+ unpackdir = d.getVar('UNPACKDIR')
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)]
+ # Add locally copied files to gitignore as we add back to the metadata directly
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))]
+ os.path.exists(os.path.join(unpackdir, fname)) and
+ srcabspath == unpackdir]
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:
+ with open(os.path.join(tempdir, '.gitignore'), 'a+') as f:
+ f.write('# Ignore local files, by default. Remove following lines'
+ 'if you want to commit the directory to Git\n')
+ for fname in local_files:
+ f.write('%s\n' % fname)
+
+ if 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])
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')
self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
- srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
- srclink = os.path.join(tempdir, 'share/dot.bashrc')
+ srcfile = os.path.join(tempdir, 'share/dot.bashrc')
self.assertExists(srcfile, 'Extracted source could not be found')
- if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
- correct_symlink = True
- self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
-
matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
self.assertTrue(matches, 'bbappend not created')
# Test devtool status
with open(bbappendfile, 'r') as f:
self.assertEqual(expectedlines, f.readlines())
# Drop new commit and check patch gets deleted
- result = runCmd('git reset HEAD^', cwd=tempsrcdir)
+ result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir)
result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
self.assertNotExists(patchfile, 'Patch file not deleted')
expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
self.assertEqual(expectedlines2, f.readlines())
# Put commit back and check we can run it if layer isn't in bblayers.conf
os.remove(bbappendfile)
+ result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
with open(bbappendfile, 'r') as f:
self.assertEqual(expectedlines, set(f.readlines()))
# Drop new commit and check SRCREV changes
- result = runCmd('git reset HEAD^', cwd=tempsrcdir)
+ result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir)
result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
self.assertEqual(expectedlines, set(f.readlines()))
# Put commit back and check we can run it if layer isn't in bblayers.conf
os.remove(bbappendfile)
+ result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
# Try building just to ensure we haven't broken that
bitbake("%s" % testrecipe)
# Edit / commit local source
- runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
- runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
+ runCmd('echo "/* Foobar */" >> makedevs.c', cwd=tempdir)
+ runCmd('echo "Foo" > new-local', cwd=tempdir)
runCmd('echo "Bar" > new-file', cwd=tempdir)
runCmd('git add new-file', cwd=tempdir)
runCmd('git commit -m "Add new file"', cwd=tempdir)
+ runCmd('git add new-local', cwd=tempdir)
runCmd('devtool update-recipe %s' % testrecipe)
expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
(' M', '.*/makedevs/makedevs.c$'),
self.assertExists(local_file, 'File makedevs.c not created')
self.assertExists(patchfile, 'File new_local not created')
- def test_devtool_update_recipe_local_files_2(self):
- """Check local source files support when oe-local-files is in Git"""
+ def _test_devtool_update_recipe_local_files_2(self):
+ """Check local source files support when editing local files in Git"""
testrecipe = 'devtool-test-local'
recipefile = get_bb_var('FILE', testrecipe)
recipedir = os.path.dirname(recipefile)
result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
# Check git repo
self._check_src_repo(tempdir)
- # Add oe-local-files to Git
- runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
- runCmd('git add oe-local-files', cwd=tempdir)
- runCmd('git commit -m "Add local sources"', cwd=tempdir)
# Edit / commit local sources
- runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
+ runCmd('echo "# Foobar" >> file1', cwd=tempdir)
runCmd('git commit -am "Edit existing file"', cwd=tempdir)
- runCmd('git rm oe-local-files/file2', cwd=tempdir)
+ runCmd('git rm file2', cwd=tempdir)
runCmd('git commit -m"Remove file"', cwd=tempdir)
- runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
- runCmd('git add oe-local-files/new-local', cwd=tempdir)
+ runCmd('echo "Foo" > new-local', cwd=tempdir)
+ runCmd('git add new-local', cwd=tempdir)
runCmd('git commit -m "Add new local file"', cwd=tempdir)
runCmd('echo "Gar" > new-file', cwd=tempdir)
runCmd('git add new-file', cwd=tempdir)
os.path.dirname(recipefile))
# Checkout unmodified file to working copy -> devtool should still pick
# the modified version from HEAD
- runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
+ runCmd('git checkout HEAD^ -- file1', cwd=tempdir)
runCmd('devtool update-recipe %s' % testrecipe)
expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
(' M', '.*/file1$'),
# (don't bother with cleaning the recipe on teardown, we won't be building it)
result = runCmd('devtool modify %s' % testrecipe)
# Modify one file
- runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
+ runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe))
self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
result = runCmd('devtool update-recipe %s' % testrecipe)
expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
ret[split[3]] = split[0:3]
return ret
+def _git_modified(repodir):
+ """List the difference between HEAD and the index"""
+ import bb
+ cmd = ['git', 'status', '--porcelain']
+ out, _ = bb.process.run(cmd, cwd=repodir)
+ ret = []
+ if out:
+ for line in out.split("\n"):
+ if line and not line.startswith('??'):
+ ret.append(line[3:])
+ return ret
+
+
def _git_exclude_path(srctree, path):
"""Return pathspec (list of paths) that excludes certain path"""
# NOTE: "Filtering out" files/paths in this way is not entirely reliable -
finally:
tinfoil.shutdown()
-def symlink_oelocal_files_srctree(rd, srctree):
- import oe.patch
- if os.path.abspath(rd.getVar('S')) == os.path.abspath(rd.getVar('WORKDIR')):
- # If recipe extracts to ${WORKDIR}, symlink the files into the srctree
- # (otherwise the recipe won't build as expected)
- local_files_dir = os.path.join(srctree, 'oe-local-files')
- addfiles = []
- for root, _, files in os.walk(local_files_dir):
- relpth = os.path.relpath(root, local_files_dir)
- if relpth != '.':
- bb.utils.mkdirhier(os.path.join(srctree, relpth))
- for fn in files:
- if fn == '.gitignore':
- continue
- destpth = os.path.join(srctree, relpth, fn)
- if os.path.exists(destpth):
- os.unlink(destpth)
- if relpth != '.':
- back_relpth = os.path.relpath(local_files_dir, root)
- os.symlink('%s/oe-local-files/%s/%s' % (back_relpth, relpth, fn), destpth)
- else:
- os.symlink('oe-local-files/%s' % fn, destpth)
- addfiles.append(os.path.join(relpth, fn))
- if addfiles:
- oe.patch.GitApplyTree.commitIgnored("Add local file symlinks", dir=srctree, files=addfiles, d=rd)
-
def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, workspace, fixed_setup, d, tinfoil, no_overrides=False):
"""Extract sources of a recipe"""
import oe.recipeutils
elif not os.path.exists(workshareddir):
oe.path.copyhardlinktree(srcsubdir, workshareddir)
- tempdir_localdir = os.path.join(tempdir, 'oe-local-files')
- srctree_localdir = os.path.join(srctree, 'oe-local-files')
-
if sync:
try:
logger.info('Backing up current %s branch as branch: %s.bak' % (devbranch, devbranch))
except bb.process.ExecutionError as e:
raise DevtoolError("Error when syncing source files to local checkout: %s" % str(e))
- # Move the oe-local-files directory to srctree.
- # As oe-local-files is not part of the constructed git tree,
- # removing it directly during the synchronization might surprise
- # the user. Instead, we move it to oe-local-files.bak and remind
- # the user in the log message.
- if os.path.exists(srctree_localdir + '.bak'):
- shutil.rmtree(srctree_localdir + '.bak')
-
- if os.path.exists(srctree_localdir):
- logger.info('Backing up current local file directory %s' % srctree_localdir)
- shutil.move(srctree_localdir, srctree_localdir + '.bak')
-
- if os.path.exists(tempdir_localdir):
- logger.info('Syncing local source files to srctree...')
- shutil.copytree(tempdir_localdir, srctree_localdir)
else:
- # Move oe-local-files directory to srctree
- if os.path.exists(tempdir_localdir):
- logger.info('Adding local source files to srctree...')
- shutil.move(tempdir_localdir, srcsubdir)
-
shutil.move(srcsubdir, srctree)
- symlink_oelocal_files_srctree(d, srctree)
if is_kernel_yocto:
logger.info('Copying kernel config to srctree')
if (os.path.exists(srcdir) and os.listdir(srcdir)) and (kernelVersion in staging_kerVer and staging_kbranch == kbranch):
oe.path.copyhardlinktree(srcdir, srctree)
workdir = rd.getVar('WORKDIR')
+ unpackdir = rd.getVar('UNPACKDIR')
srcsubdir = rd.getVar('S')
localfilesdir = os.path.join(srctree, 'oe-local-files')
- # Move local source files into separate subdir
- recipe_patches = [os.path.basename(patch) for patch in oe.recipeutils.get_recipe_patches(rd)]
- local_files = oe.recipeutils.get_recipe_local_files(rd)
- 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}
+ # Add locally copied files to gitignore as we add back to the metadata directly
+ local_files = oe.recipeutils.get_recipe_local_files(rd)
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))]
+ local_files = [fname for fname in local_files if
+ os.path.exists(os.path.join(unpackdir, fname)) and
+ srcabspath == unpackdir]
if local_files:
- for fname in local_files:
- _move_file(os.path.join(workdir, fname), os.path.join(srctree, 'oe-local-files', fname))
- with open(os.path.join(srctree, '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')
-
- symlink_oelocal_files_srctree(rd, srctree)
+ with open(os.path.join(srctree, '.gitignore'), 'a+') as f:
+ f.write('# Ignore local files, by default. Remove following lines'
+ 'if you want to commit the directory to Git\n')
+ for fname in local_files:
+ f.write('%s\n' % fname)
task = 'do_configure'
res = tinfoil.build_targets(pn, task, handle_events=True)
# Instead they are directly copied over the original source files (in
# recipe space).
existing_files = oe.recipeutils.get_recipe_local_files(rd)
+
new_set = None
updated = OrderedDict()
added = OrderedDict()
if branchname.startswith(override_branch_prefix):
return (updated, added, removed)
- local_files_dir = os.path.join(srctreebase, 'oe-local-files')
- git_files = _git_ls_tree(srctree)
- if 'oe-local-files' in git_files:
- # If tracked by Git, take the files from srctree HEAD. First get
- # the tree object of the directory
- tmp_index = os.path.join(srctree, '.git', 'index.tmp.devtool')
- tree = git_files['oe-local-files'][2]
- bb.process.run(['git', 'checkout', tree, '--', '.'], cwd=srctree,
- env=dict(os.environ, GIT_WORK_TREE=destdir,
- GIT_INDEX_FILE=tmp_index))
- new_set = list(_git_ls_tree(srctree, tree, True).keys())
- elif os.path.isdir(local_files_dir):
- # If not tracked by Git, just copy from working copy
- new_set = _ls_tree(local_files_dir)
- bb.process.run(['cp', '-ax',
- os.path.join(local_files_dir, '.'), destdir])
- else:
- new_set = []
+ files = _git_modified(srctree)
+ #if not files:
+ # files = _ls_tree(srctree)
+ for f in files:
+ fullfile = os.path.join(srctree, f)
+ if os.path.exists(os.path.join(fullfile, ".git")):
+ # submodules handled elsewhere
+ continue
+ if f not in existing_files:
+ added[f] = {}
+ if os.path.isdir(os.path.join(srctree, f)):
+ shutil.copytree(fullfile, os.path.join(destdir, f))
+ else:
+ shutil.copy2(fullfile, os.path.join(destdir, f))
+ elif not os.path.exists(fullfile):
+ removed[f] = existing_files[f]
+ elif f in existing_files:
+ updated[f] = {'path' : existing_files[f]}
+ if os.path.isdir(os.path.join(srctree, f)):
+ shutil.copytree(fullfile, os.path.join(destdir, f))
+ else:
+ shutil.copy2(fullfile, os.path.join(destdir, f))
# Special handling for kernel config
if bb.data.inherits_class('kernel-yocto', rd):
fragment_path = os.path.join(destdir, fragment_fn)
if _create_kconfig_diff(srctree, rd, fragment_path):
if os.path.exists(fragment_path):
- if fragment_fn not in new_set:
- new_set.append(fragment_fn)
- # Copy fragment to local-files
- if os.path.isdir(local_files_dir):
- shutil.copy2(fragment_path, local_files_dir)
+ if fragment_fn in removed:
+ del removed[fragment_fn]
+ if fragment_fn not in updated and fragment_fn not in added:
+ added[fragment_fn] = {}
else:
- if fragment_fn in new_set:
- new_set.remove(fragment_fn)
- # Remove fragment from local-files
- if os.path.exists(os.path.join(local_files_dir, fragment_fn)):
- os.unlink(os.path.join(local_files_dir, fragment_fn))
+ if fragment_fn in updated:
+ revoved[fragment_fn] = updated[fragment_fn]
+ del updated[fragment_fn]
# Special handling for cml1, ccmake, etc bbclasses that generated
# configuration fragment files that are consumed as source files
if bb.data.inherits_class(frag_class, rd):
srcpath = os.path.join(rd.getVar('WORKDIR'), frag_name)
if os.path.exists(srcpath):
- if frag_name not in new_set:
- new_set.append(frag_name)
+ if frag_name in removed:
+ del removed[frag_name]
+ if frag_name not in updated:
+ added[frag_name] = {}
# copy fragment into destdir
shutil.copy2(srcpath, destdir)
- # copy fragment into local files if exists
- if os.path.isdir(local_files_dir):
- shutil.copy2(srcpath, local_files_dir)
-
- if new_set is not None:
- for fname in new_set:
- if fname in existing_files:
- origpath = existing_files.pop(fname)
- workpath = os.path.join(local_files_dir, fname)
- if not filecmp.cmp(origpath, workpath):
- updated[fname] = {'path' : origpath}
- elif fname != '.gitignore':
- added[fname] = {}
-
- workdir = rd.getVar('WORKDIR')
- s = rd.getVar('S')
- if not s.endswith(os.sep):
- s += os.sep
-
- if workdir != s:
- # Handle files where subdir= was specified
- for fname in list(existing_files.keys()):
- # FIXME handle both subdir starting with BP and not?
- fworkpath = os.path.join(workdir, fname)
- if fworkpath.startswith(s):
- fpath = os.path.join(srctree, os.path.relpath(fworkpath, s))
- if os.path.exists(fpath):
- origpath = existing_files.pop(fname)
- if not filecmp.cmp(origpath, fpath):
- updated[fpath] = {'path' : origpath}
-
- removed = existing_files
+
return (updated, added, removed)