summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>2015-04-23 17:11:42 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-10-01 07:43:32 +0100
commite9bae506e520a47e797c405a76f330d041289918 (patch)
treefb8bb6695d4083c31d35768999ca1591c0f627cb
parenta74fa38365ab91d3143d8b7d6414c97cd3862794 (diff)
downloadpoky-e9bae506e520a47e797c405a76f330d041289918.tar.gz
devtool: better support for local source files
* extract: Copy all local source files (i.e. non-compressed/non-arcived SRC_URI files that have file:// URI prefix) - excluding patches - to the srctree repository. The files will be placed in a subdirectory called 'oe-local-files'. The oe-local-files directory is not committed to the Git repository, but, marked to be ignored by a .gitignore file. The developer can manually add and commit the files to Git if the changes to them need to be tracked. Before this patch, local source files (were copied (and committed) to the srctree repository only in some special cases (basically when S=WORKDIR) when doing devtool-extract. For most of the packages local files were not copied at all. * update-recipe: This patch causes the local files to be 'synced' from the srctree (i.e. from the 'oe-local-files' subdirectory) to the layer. Being 'synced' means that in addition to copying modified files over the original sources, devtool will also handle removing and adding local source files and updating the recipe accordingly. We don't want to create patches against the local source files but rather update them directly. Thus, 'oe-local-file' directory is ignored in patch generation when doing update-recipe, even if committed to Git. This functionality is only enabled if the 'oe-local-files' directory is present in srctree. [YOCTO #7602] (From OE-Core rev: a3bb5bd25b72bd1bcc156dabd0ffa2d9184bb160) Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/lib/oeqa/selftest/devtool.py71
-rw-r--r--scripts/lib/devtool/__init__.py10
-rw-r--r--scripts/lib/devtool/standard.py314
3 files changed, 297 insertions, 98 deletions
diff --git a/meta/lib/oeqa/selftest/devtool.py b/meta/lib/oeqa/selftest/devtool.py
index 92cd0e230d..baa56d6dc1 100644
--- a/meta/lib/oeqa/selftest/devtool.py
+++ b/meta/lib/oeqa/selftest/devtool.py
@@ -723,6 +723,77 @@ class DevtoolTests(DevtoolBase):
723 self.assertEqual(expectedlines, f.readlines()) 723 self.assertEqual(expectedlines, f.readlines())
724 # Deleting isn't expected to work under these circumstances 724 # Deleting isn't expected to work under these circumstances
725 725
726 @testcase(1173)
727 def test_devtool_update_recipe_local_files(self):
728 """Check that local source files are copied over instead of patched"""
729 testrecipe = 'makedevs'
730 recipefile = get_bb_var('FILE', testrecipe)
731 # Setup srctree for modifying the recipe
732 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
733 self.track_for_cleanup(tempdir)
734 self.track_for_cleanup(self.workspacedir)
735 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
736 # (don't bother with cleaning the recipe on teardown, we won't be
737 # building it)
738 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
739 # Check git repo
740 self._check_src_repo(tempdir)
741 # Edit / commit local source
742 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
743 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
744 runCmd('echo "Bar" > new-file', cwd=tempdir)
745 runCmd('git add new-file', cwd=tempdir)
746 runCmd('git commit -m "Add new file"', cwd=tempdir)
747 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
748 os.path.dirname(recipefile))
749 runCmd('devtool update-recipe %s' % testrecipe)
750 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
751 (' M', '.*/makedevs/makedevs.c$'),
752 ('??', '.*/makedevs/new-local$'),
753 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
754 self._check_repo_status(os.path.dirname(recipefile), expected_status)
755
756 @testcase(1174)
757 def test_devtool_update_recipe_local_files_2(self):
758 """Check local source files support when oe-local-files is in Git"""
759 testrecipe = 'lzo'
760 recipefile = get_bb_var('FILE', testrecipe)
761 # Setup srctree for modifying the recipe
762 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
763 self.track_for_cleanup(tempdir)
764 self.track_for_cleanup(self.workspacedir)
765 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
766 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
767 # Check git repo
768 self._check_src_repo(tempdir)
769 # Add oe-local-files to Git
770 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
771 runCmd('git add oe-local-files', cwd=tempdir)
772 runCmd('git commit -m "Add local sources"', cwd=tempdir)
773 # Edit / commit local sources
774 runCmd('echo "# Foobar" >> oe-local-files/acinclude.m4', cwd=tempdir)
775 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
776 runCmd('git rm oe-local-files/run-ptest', cwd=tempdir)
777 runCmd('git commit -m"Remove file"', cwd=tempdir)
778 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
779 runCmd('git add oe-local-files/new-local', cwd=tempdir)
780 runCmd('git commit -m "Add new local file"', cwd=tempdir)
781 runCmd('echo "Gar" > new-file', cwd=tempdir)
782 runCmd('git add new-file', cwd=tempdir)
783 runCmd('git commit -m "Add new file"', cwd=tempdir)
784 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
785 os.path.dirname(recipefile))
786 # Checkout unmodified file to working copy -> devtool should still pick
787 # the modified version from HEAD
788 runCmd('git checkout HEAD^ -- oe-local-files/acinclude.m4', cwd=tempdir)
789 runCmd('devtool update-recipe %s' % testrecipe)
790 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
791 (' M', '.*/acinclude.m4$'),
792 (' D', '.*/run-ptest$'),
793 ('??', '.*/new-local$'),
794 ('??', '.*/0001-Add-new-file.patch$')]
795 self._check_repo_status(os.path.dirname(recipefile), expected_status)
796
726 @testcase(1163) 797 @testcase(1163)
727 def test_devtool_extract(self): 798 def test_devtool_extract(self):
728 tempdir = tempfile.mkdtemp(prefix='devtoolqa') 799 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
diff --git a/scripts/lib/devtool/__init__.py b/scripts/lib/devtool/__init__.py
index 7b1ab1110d..c8c30202b1 100644
--- a/scripts/lib/devtool/__init__.py
+++ b/scripts/lib/devtool/__init__.py
@@ -183,11 +183,17 @@ def setup_git_repo(repodir, version, devbranch, basetag='devtool-base'):
183 if not os.path.exists(os.path.join(repodir, '.git')): 183 if not os.path.exists(os.path.join(repodir, '.git')):
184 bb.process.run('git init', cwd=repodir) 184 bb.process.run('git init', cwd=repodir)
185 bb.process.run('git add .', cwd=repodir) 185 bb.process.run('git add .', cwd=repodir)
186 if version: 186 commit_cmd = ['git', 'commit', '-q']
187 stdout, _ = bb.process.run('git status --porcelain', cwd=repodir)
188 if not stdout:
189 commit_cmd.append('--allow-empty')
190 commitmsg = "Initial empty commit with no upstream sources"
191 elif version:
187 commitmsg = "Initial commit from upstream at version %s" % version 192 commitmsg = "Initial commit from upstream at version %s" % version
188 else: 193 else:
189 commitmsg = "Initial commit from upstream" 194 commitmsg = "Initial commit from upstream"
190 bb.process.run('git commit -q -m "%s"' % commitmsg, cwd=repodir) 195 commit_cmd += ['-m', commitmsg]
196 bb.process.run(commit_cmd, cwd=repodir)
191 197
192 bb.process.run('git checkout -b %s' % devbranch, cwd=repodir) 198 bb.process.run('git checkout -b %s' % devbranch, cwd=repodir)
193 bb.process.run('git tag -f %s' % basetag, cwd=repodir) 199 bb.process.run('git tag -f %s' % basetag, cwd=repodir)
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py
index e4e90a7160..0c67c131a8 100644
--- a/scripts/lib/devtool/standard.py
+++ b/scripts/lib/devtool/standard.py
@@ -181,6 +181,36 @@ def _move_file(src, dst):
181 bb.utils.mkdirhier(dst_d) 181 bb.utils.mkdirhier(dst_d)
182 shutil.move(src, dst) 182 shutil.move(src, dst)
183 183
184def _git_ls_tree(repodir, treeish='HEAD', recursive=False):
185 """List contents of a git treeish"""
186 import bb
187 cmd = ['git', 'ls-tree', '-z', treeish]
188 if recursive:
189 cmd.append('-r')
190 out, _ = bb.process.run(cmd, cwd=repodir)
191 ret = {}
192 for line in out.split('\0'):
193 if line:
194 split = line.split(None, 4)
195 ret[split[3]] = split[0:3]
196 return ret
197
198def _git_exclude_path(srctree, path):
199 """Return pathspec (list of paths) that excludes certain path"""
200 # NOTE: "Filtering out" files/paths in this way is not entirely reliable -
201 # we don't catch files that are deleted, for example. A more reliable way
202 # to implement this would be to use "negative pathspecs" which were
203 # introduced in Git v1.9.0. Revisit this when/if the required Git version
204 # becomes greater than that.
205 path = os.path.normpath(path)
206 recurse = True if len(path.split(os.path.sep)) > 1 else False
207 git_files = _git_ls_tree(srctree, 'HEAD', recurse).keys()
208 if path in git_files:
209 git_files.remove(path)
210 return git_files
211 else:
212 return ['.']
213
184def _ls_tree(directory): 214def _ls_tree(directory):
185 """Recursive listing of files in a directory""" 215 """Recursive listing of files in a directory"""
186 ret = [] 216 ret = []
@@ -326,10 +356,25 @@ def _extract_source(srctree, keep_temp, devbranch, d):
326 logger.info('Doing kernel checkout...') 356 logger.info('Doing kernel checkout...')
327 task_executor.exec_func('do_kernel_checkout', False) 357 task_executor.exec_func('do_kernel_checkout', False)
328 srcsubdir = crd.getVar('S', True) 358 srcsubdir = crd.getVar('S', True)
359
360 # Move local source files into separate subdir
361 recipe_patches = [os.path.basename(patch) for patch in
362 oe.recipeutils.get_recipe_patches(crd)]
363 local_files = oe.recipeutils.get_recipe_local_files(crd)
364 local_files = [fname for fname in local_files if
365 os.path.exists(os.path.join(workdir, fname))]
366 if local_files:
367 for fname in local_files:
368 _move_file(os.path.join(workdir, fname),
369 os.path.join(tempdir, 'oe-local-files', fname))
370 with open(os.path.join(tempdir, 'oe-local-files', '.gitignore'),
371 'w') as f:
372 f.write('# Ignore local files, by default. Remove this file '
373 'if you want to commit the directory to Git\n*\n')
374
329 if srcsubdir == workdir: 375 if srcsubdir == workdir:
330 # Find non-patch sources that were "unpacked" to srctree directory 376 # Find non-patch non-local sources that were "unpacked" to srctree
331 recipe_patches = [os.path.basename(patch) for patch in 377 # directory
332 oe.recipeutils.get_recipe_patches(crd)]
333 src_files = [fname for fname in _ls_tree(workdir) if 378 src_files = [fname for fname in _ls_tree(workdir) if
334 os.path.basename(fname) not in recipe_patches] 379 os.path.basename(fname) not in recipe_patches]
335 # Force separate S so that patch files can be left out from srctree 380 # Force separate S so that patch files can be left out from srctree
@@ -352,12 +397,12 @@ def _extract_source(srctree, keep_temp, devbranch, d):
352 haspatches = True 397 haspatches = True
353 else: 398 else:
354 os.rmdir(patchdir) 399 os.rmdir(patchdir)
355 400 # Make sure that srcsubdir exists
401 bb.utils.mkdirhier(srcsubdir)
356 if not os.path.exists(srcsubdir) or not os.listdir(srcsubdir): 402 if not os.path.exists(srcsubdir) or not os.listdir(srcsubdir):
357 raise DevtoolError("no source unpacked to S, either the %s " 403 logger.warning("no source unpacked to S, either the %s recipe "
358 "recipe doesn't use any source or the " 404 "doesn't use any source or the correct source "
359 "correct source directory could not be " 405 "directory could not be determined" % pn)
360 "determined" % pn)
361 406
362 setup_git_repo(srcsubdir, crd.getVar('PV', True), devbranch) 407 setup_git_repo(srcsubdir, crd.getVar('PV', True), devbranch)
363 408
@@ -376,6 +421,12 @@ def _extract_source(srctree, keep_temp, devbranch, d):
376 if haspatches: 421 if haspatches:
377 bb.process.run('git checkout patches', cwd=srcsubdir) 422 bb.process.run('git checkout patches', cwd=srcsubdir)
378 423
424 # Move oe-local-files directory to srctree
425 if os.path.exists(os.path.join(tempdir, 'oe-local-files')):
426 logger.info('Adding local source files to srctree...')
427 shutil.move(os.path.join(tempdir, 'oe-local-files'), srcsubdir)
428
429
379 shutil.move(srcsubdir, srctree) 430 shutil.move(srcsubdir, srctree)
380 finally: 431 finally:
381 bb.logger.setLevel(origlevel) 432 bb.logger.setLevel(origlevel)
@@ -560,39 +611,40 @@ def _get_patchset_revs(args, srctree, recipe_path):
560 611
561 return initial_rev, update_rev 612 return initial_rev, update_rev
562 613
563def _remove_patch_entries(srcuri, patchlist): 614def _remove_file_entries(srcuri, filelist):
564 """Remove patch entries from SRC_URI""" 615 """Remove file:// entries from SRC_URI"""
565 remaining = patchlist[:] 616 remaining = filelist[:]
566 entries = [] 617 entries = []
567 for patch in patchlist: 618 for fname in filelist:
568 patchfile = os.path.basename(patch) 619 basename = os.path.basename(fname)
569 for i in xrange(len(srcuri)): 620 for i in xrange(len(srcuri)):
570 if srcuri[i].startswith('file://') and os.path.basename(srcuri[i].split(';')[0]) == patchfile: 621 if (srcuri[i].startswith('file://') and
622 os.path.basename(srcuri[i].split(';')[0]) == basename):
571 entries.append(srcuri[i]) 623 entries.append(srcuri[i])
572 remaining.remove(patch) 624 remaining.remove(fname)
573 srcuri.pop(i) 625 srcuri.pop(i)
574 break 626 break
575 return entries, remaining 627 return entries, remaining
576 628
577def _remove_patch_files(args, patches, destpath): 629def _remove_source_files(args, files, destpath):
578 """Unlink existing patch files""" 630 """Unlink existing patch files"""
579 for patchfile in patches: 631 for path in files:
580 if args.append: 632 if args.append:
581 if not destpath: 633 if not destpath:
582 raise Exception('destpath should be set here') 634 raise Exception('destpath should be set here')
583 patchfile = os.path.join(destpath, os.path.basename(patchfile)) 635 path = os.path.join(destpath, os.path.basename(path))
584 636
585 if os.path.exists(patchfile): 637 if os.path.exists(path):
586 logger.info('Removing patch %s' % patchfile) 638 logger.info('Removing file %s' % path)
587 # FIXME "git rm" here would be nice if the file in question is 639 # FIXME "git rm" here would be nice if the file in question is
588 # tracked 640 # tracked
589 # FIXME there's a chance that this file is referred to by 641 # FIXME there's a chance that this file is referred to by
590 # another recipe, in which case deleting wouldn't be the 642 # another recipe, in which case deleting wouldn't be the
591 # right thing to do 643 # right thing to do
592 os.remove(patchfile) 644 os.remove(path)
593 # Remove directory if empty 645 # Remove directory if empty
594 try: 646 try:
595 os.rmdir(os.path.dirname(patchfile)) 647 os.rmdir(os.path.dirname(path))
596 except OSError as ose: 648 except OSError as ose:
597 if ose.errno != errno.ENOTEMPTY: 649 if ose.errno != errno.ENOTEMPTY:
598 raise 650 raise
@@ -616,8 +668,9 @@ def _export_patches(srctree, rd, start_rev, destdir):
616 existing_patches = dict((os.path.basename(path), path) for path in 668 existing_patches = dict((os.path.basename(path), path) for path in
617 oe.recipeutils.get_recipe_patches(rd)) 669 oe.recipeutils.get_recipe_patches(rd))
618 670
619 # Generate patches from Git 671 # Generate patches from Git, exclude local files directory
620 GitApplyTree.extractPatches(srctree, start_rev, destdir) 672 patch_pathspec = _git_exclude_path(srctree, 'oe-local-files')
673 GitApplyTree.extractPatches(srctree, start_rev, destdir, patch_pathspec)
621 674
622 new_patches = sorted(os.listdir(destdir)) 675 new_patches = sorted(os.listdir(destdir))
623 for new_patch in new_patches: 676 for new_patch in new_patches:
@@ -642,6 +695,52 @@ def _export_patches(srctree, rd, start_rev, destdir):
642 return (updated, added, existing_patches) 695 return (updated, added, existing_patches)
643 696
644 697
698def _export_local_files(srctree, rd, destdir):
699 """Copy local files from srctree to given location.
700 Returns three-tuple of dicts:
701 1. updated - files that already exist in SRCURI
702 2. added - new files files that don't exist in SRCURI
703 3 removed - files that exist in SRCURI but not in exported files
704 In each dict the key is the 'basepath' of the URI and value is the
705 absolute path to the existing file in recipe space (if any).
706 """
707 import oe.recipeutils
708
709 # Find out local files (SRC_URI files that exist in the "recipe space").
710 # Local files that reside in srctree are not included in patch generation.
711 # Instead they are directly copied over the original source files (in
712 # recipe space).
713 existing_files = oe.recipeutils.get_recipe_local_files(rd)
714 new_set = None
715 updated = OrderedDict()
716 added = OrderedDict()
717 removed = OrderedDict()
718 git_files = _git_ls_tree(srctree)
719 if 'oe-local-files' in git_files:
720 # If tracked by Git, take the files from srctree HEAD. First get
721 # the tree object of the directory
722 tmp_index = os.path.join(srctree, '.git', 'index.tmp.devtool')
723 tree = git_files['oe-local-files'][2]
724 bb.process.run(['git', 'checkout', tree, '--', '.'], cwd=srctree,
725 env=dict(os.environ, GIT_WORK_TREE=destdir,
726 GIT_INDEX_FILE=tmp_index))
727 new_set = _git_ls_tree(srctree, tree, True).keys()
728 elif os.path.isdir(os.path.join(srctree, 'oe-local-files')):
729 # If not tracked by Git, just copy from working copy
730 new_set = _ls_tree(os.path.join(srctree, 'oe-local-files'))
731 bb.process.run(['cp', '-ax',
732 os.path.join(srctree, 'oe-local-files', '.'), destdir])
733 if new_set is not None:
734 for fname in new_set:
735 if fname in existing_files:
736 updated[fname] = existing_files.pop(fname)
737 elif fname != '.gitignore':
738 added[fname] = None
739
740 removed = existing_files
741 return (updated, added, removed)
742
743
645def _update_recipe_srcrev(args, srctree, rd, config_data): 744def _update_recipe_srcrev(args, srctree, rd, config_data):
646 """Implement the 'srcrev' mode of update-recipe""" 745 """Implement the 'srcrev' mode of update-recipe"""
647 import bb 746 import bb
@@ -661,43 +760,63 @@ def _update_recipe_srcrev(args, srctree, rd, config_data):
661 raise DevtoolError('Invalid hash returned by git: %s' % stdout) 760 raise DevtoolError('Invalid hash returned by git: %s' % stdout)
662 761
663 destpath = None 762 destpath = None
664 removepatches = [] 763 remove_files = []
665 patchfields = {} 764 patchfields = {}
666 patchfields['SRCREV'] = srcrev 765 patchfields['SRCREV'] = srcrev
667 orig_src_uri = rd.getVar('SRC_URI', False) or '' 766 orig_src_uri = rd.getVar('SRC_URI', False) or ''
668 if not args.no_remove: 767 srcuri = orig_src_uri.split()
669 # Find list of existing patches in recipe file 768 tempdir = tempfile.mkdtemp(prefix='devtool')
670 existing_patches = oe.recipeutils.get_recipe_patches(rd) 769 update_srcuri = False
671 770 try:
672 old_srcrev = (rd.getVar('SRCREV', False) or '') 771 local_files_dir = tempfile.mkdtemp(dir=tempdir)
673 tempdir = tempfile.mkdtemp(prefix='devtool') 772 upd_f, new_f, del_f = _export_local_files(srctree, rd, local_files_dir)
674 try: 773 if not args.no_remove:
774 # Find list of existing patches in recipe file
775 patches_dir = tempfile.mkdtemp(dir=tempdir)
776 old_srcrev = (rd.getVar('SRCREV', False) or '')
675 upd_p, new_p, del_p = _export_patches(srctree, rd, old_srcrev, 777 upd_p, new_p, del_p = _export_patches(srctree, rd, old_srcrev,
676 tempdir) 778 patches_dir)
677 # Remove "overlapping" patches
678 removepatches = upd_p.values()
679 finally:
680 shutil.rmtree(tempdir)
681
682 if removepatches:
683 srcuri = orig_src_uri.split()
684 removedentries, _ = _remove_patch_entries(srcuri, removepatches)
685 if removedentries:
686 patchfields['SRC_URI'] = ' '.join(srcuri)
687 779
688 if args.append: 780 # Remove deleted local files and "overlapping" patches
689 _, destpath = oe.recipeutils.bbappend_recipe( 781 remove_files = del_f.values() + upd_p.values()
690 rd, args.append, None, wildcardver=args.wildcard_version, 782 if remove_files:
691 extralines=patchfields) 783 removedentries = _remove_file_entries(srcuri, remove_files)[0]
692 else: 784 update_srcuri = True
693 oe.recipeutils.patch_recipe(rd, recipefile, patchfields)
694 785
786 if args.append:
787 files = dict((os.path.join(local_files_dir, key), val) for
788 key, val in upd_f.items() + new_f.items())
789 removevalues = {}
790 if update_srcuri:
791 removevalues = {'SRC_URI': removedentries}
792 patchfields['SRC_URI'] = '\\\n '.join(srcuri)
793 _, destpath = oe.recipeutils.bbappend_recipe(
794 rd, args.append, files, wildcardver=args.wildcard_version,
795 extralines=patchfields, removevalues=removevalues)
796 else:
797 files_dir = os.path.join(os.path.dirname(recipefile),
798 rd.getVar('BPN', True))
799 for basepath, path in upd_f.iteritems():
800 logger.info('Updating file %s' % basepath)
801 _move_file(os.path.join(local_files_dir, basepath), path)
802 update_srcuri= True
803 for basepath, path in new_f.iteritems():
804 logger.info('Adding new file %s' % basepath)
805 _move_file(os.path.join(local_files_dir, basepath),
806 os.path.join(files_dir, basepath))
807 srcuri.append('file://%s' % basepath)
808 update_srcuri = True
809 if update_srcuri:
810 patchfields['SRC_URI'] = ' '.join(srcuri)
811 oe.recipeutils.patch_recipe(rd, recipefile, patchfields)
812 finally:
813 shutil.rmtree(tempdir)
695 if not 'git://' in orig_src_uri: 814 if not 'git://' in orig_src_uri:
696 logger.info('You will need to update SRC_URI within the recipe to ' 815 logger.info('You will need to update SRC_URI within the recipe to '
697 'point to a git repository where you have pushed your ' 816 'point to a git repository where you have pushed your '
698 'changes') 817 'changes')
699 818
700 _remove_patch_files(args, removepatches, destpath) 819 _remove_source_files(args, remove_files, destpath)
701 820
702def _update_recipe_patch(args, config, srctree, rd, config_data): 821def _update_recipe_patch(args, config, srctree, rd, config_data):
703 """Implement the 'patch' mode of update-recipe""" 822 """Implement the 'patch' mode of update-recipe"""
@@ -716,83 +835,86 @@ def _update_recipe_patch(args, config, srctree, rd, config_data):
716 raise DevtoolError('Unable to find initial revision - please specify ' 835 raise DevtoolError('Unable to find initial revision - please specify '
717 'it with --initial-rev') 836 'it with --initial-rev')
718 837
719 # Find list of existing patches in recipe file 838 tempdir = tempfile.mkdtemp(prefix='devtool')
720 existing_patches = oe.recipeutils.get_recipe_patches(rd) 839 try:
840 local_files_dir = tempfile.mkdtemp(dir=tempdir)
841 upd_f, new_f, del_f = _export_local_files(srctree, rd, local_files_dir)
721 842
722 removepatches = [] 843 remove_files = []
723 seqpatch_re = re.compile('^([0-9]{4}-)?(.+)') 844 if not args.no_remove:
724 if not args.no_remove:
725 # Get all patches from source tree and check if any should be removed
726 tempdir = tempfile.mkdtemp(prefix='devtool')
727 try:
728 # Get all patches from source tree and check if any should be removed 845 # Get all patches from source tree and check if any should be removed
846 all_patches_dir = tempfile.mkdtemp(dir=tempdir)
729 upd_p, new_p, del_p = _export_patches(srctree, rd, initial_rev, 847 upd_p, new_p, del_p = _export_patches(srctree, rd, initial_rev,
730 tempdir) 848 all_patches_dir)
731 # Remove deleted patches 849 # Remove deleted local files and patches
732 removepatches = del_p.values() 850 remove_files = del_f.values() + del_p.values()
733 finally:
734 shutil.rmtree(tempdir)
735 851
736 # Get updated patches from source tree 852 # Get updated patches from source tree
737 tempdir = tempfile.mkdtemp(prefix='devtool') 853 patches_dir = tempfile.mkdtemp(dir=tempdir)
738 try:
739 upd_p, new_p, del_p = _export_patches(srctree, rd, update_rev, 854 upd_p, new_p, del_p = _export_patches(srctree, rd, update_rev,
740 tempdir) 855 patches_dir)
741 856 updatefiles = False
742 # Match up and replace existing patches with corresponding new patches
743 updatepatches = False
744 updaterecipe = False 857 updaterecipe = False
745 destpath = None 858 destpath = None
859 srcuri = (rd.getVar('SRC_URI', False) or '').split()
746 if args.append: 860 if args.append:
747 patchfiles = dict((os.path.join(tempdir, key), val) for 861 files = dict((os.path.join(local_files_dir, key), val) for
748 key, val in upd_p.items() + new_p.items()) 862 key, val in upd_f.items() + new_f.items())
749 863 files.update(dict((os.path.join(patches_dir, key), val) for
750 if patchfiles or removepatches: 864 key, val in upd_p.items() + new_p.items()))
865 if files or remove_files:
751 removevalues = None 866 removevalues = None
752 if removepatches: 867 if remove_files:
753 srcuri = (rd.getVar('SRC_URI', False) or '').split() 868 removedentries, remaining = _remove_file_entries(
754 removedentries, remaining = _remove_patch_entries( 869 srcuri, remove_files)
755 srcuri, removepatches)
756 if removedentries or remaining: 870 if removedentries or remaining:
757 remaining = ['file://' + os.path.basename(item) for 871 remaining = ['file://' + os.path.basename(item) for
758 item in remaining] 872 item in remaining]
759 removevalues = {'SRC_URI': removedentries + remaining} 873 removevalues = {'SRC_URI': removedentries + remaining}
760 _, destpath = oe.recipeutils.bbappend_recipe( 874 _, destpath = oe.recipeutils.bbappend_recipe(
761 rd, args.append, patchfiles, 875 rd, args.append, files,
762 removevalues=removevalues) 876 removevalues=removevalues)
763 else: 877 else:
764 logger.info('No patches needed updating') 878 logger.info('No patches or local source files needed updating')
765 else: 879 else:
880 # Update existing files
881 for basepath, path in upd_f.iteritems():
882 logger.info('Updating file %s' % basepath)
883 _move_file(os.path.join(local_files_dir, basepath), path)
884 updatefiles = True
766 for basepath, path in upd_p.iteritems(): 885 for basepath, path in upd_p.iteritems():
767 logger.info('Updating patch %s' % basepath) 886 logger.info('Updating patch %s' % basepath)
768 shutil.move(os.path.join(tempdir, basepath), path) 887 _move_file(os.path.join(patches_dir, basepath), path)
769 updatepatches = True 888 updatefiles = True
770 srcuri = (rd.getVar('SRC_URI', False) or '').split() 889 # Add any new files
771 patchdir = os.path.join(os.path.dirname(recipefile), 890 files_dir = os.path.join(os.path.dirname(recipefile),
772 rd.getVar('BPN', True)) 891 rd.getVar('BPN', True))
773 bb.utils.mkdirhier(patchdir) 892 for basepath, path in new_f.iteritems():
893 logger.info('Adding new file %s' % basepath)
894 _move_file(os.path.join(local_files_dir, basepath),
895 os.path.join(files_dir, basepath))
896 srcuri.append('file://%s' % basepath)
897 updaterecipe = True
774 for basepath, path in new_p.iteritems(): 898 for basepath, path in new_p.iteritems():
775 logger.info('Adding new patch %s' % basepath) 899 logger.info('Adding new patch %s' % basepath)
776 bb.utils.mkdirhier(patchdir) 900 _move_file(os.path.join(patches_dir, basepath),
777 shutil.move(os.path.join(tempdir, basepath), 901 os.path.join(files_dir, basepath))
778 os.path.join(patchdir, basepath))
779 srcuri.append('file://%s' % basepath) 902 srcuri.append('file://%s' % basepath)
780 updaterecipe = True 903 updaterecipe = True
781 if removepatches: 904 # Update recipe, if needed
782 removedentries, _ = _remove_patch_entries(srcuri, removepatches) 905 if _remove_file_entries(srcuri, remove_files)[0]:
783 if removedentries: 906 updaterecipe = True
784 updaterecipe = True
785 if updaterecipe: 907 if updaterecipe:
786 logger.info('Updating recipe %s' % os.path.basename(recipefile)) 908 logger.info('Updating recipe %s' % os.path.basename(recipefile))
787 oe.recipeutils.patch_recipe(rd, recipefile, 909 oe.recipeutils.patch_recipe(rd, recipefile,
788 {'SRC_URI': ' '.join(srcuri)}) 910 {'SRC_URI': ' '.join(srcuri)})
789 elif not updatepatches: 911 elif not updatefiles:
790 # Neither patches nor recipe were updated 912 # Neither patches nor recipe were updated
791 logger.info('No patches need updating') 913 logger.info('No patches or files need updating')
792 finally: 914 finally:
793 shutil.rmtree(tempdir) 915 shutil.rmtree(tempdir)
794 916
795 _remove_patch_files(args, removepatches, destpath) 917 _remove_source_files(args, remove_files, destpath)
796 918
797def _guess_recipe_update_mode(srctree, rdata): 919def _guess_recipe_update_mode(srctree, rdata):
798 """Guess the recipe update mode to use""" 920 """Guess the recipe update mode to use"""