diff options
author | Markus Lehtonen <markus.lehtonen@linux.intel.com> | 2015-04-23 17:11:42 +0300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-10-01 07:43:32 +0100 |
commit | e9bae506e520a47e797c405a76f330d041289918 (patch) | |
tree | fb8bb6695d4083c31d35768999ca1591c0f627cb | |
parent | a74fa38365ab91d3143d8b7d6414c97cd3862794 (diff) | |
download | poky-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.py | 71 | ||||
-rw-r--r-- | scripts/lib/devtool/__init__.py | 10 | ||||
-rw-r--r-- | scripts/lib/devtool/standard.py | 314 |
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 | ||
184 | def _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 | |||
198 | def _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 | |||
184 | def _ls_tree(directory): | 214 | def _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 | ||
563 | def _remove_patch_entries(srcuri, patchlist): | 614 | def _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 | ||
577 | def _remove_patch_files(args, patches, destpath): | 629 | def _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 | ||
698 | def _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 | |||
645 | def _update_recipe_srcrev(args, srctree, rd, config_data): | 744 | def _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 | ||
702 | def _update_recipe_patch(args, config, srctree, rd, config_data): | 821 | def _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 | ||
797 | def _guess_recipe_update_mode(srctree, rdata): | 919 | def _guess_recipe_update_mode(srctree, rdata): |
798 | """Guess the recipe update mode to use""" | 920 | """Guess the recipe update mode to use""" |