summaryrefslogtreecommitdiffstats
path: root/scripts/lib
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2015-05-18 16:15:08 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-05-20 21:41:04 +0100
commit7539c1f8892e5f7467e3fe8cf8cf7a5a23033e4d (patch)
tree02fa87af1b254a594c339871d54eaf665417e82f /scripts/lib
parentfbfc06a969200e582a059c9943e6fd17aca70e30 (diff)
downloadpoky-7539c1f8892e5f7467e3fe8cf8cf7a5a23033e4d.tar.gz
devtool: update-recipe: add option to write changes to bbappend
Quite often what you want to do having made customisations to a piece of software is to apply those customisations in your own layer rather than in the original recipe. Thus, add a -a/--append option to the update-recipe subcommand which allows you to specify the layer to write a bbappend into. The bbappend will be created at the appropriate path within the specified layer directory (which may or may not be in your bblayers.conf) or if one already exists it will be updated appropriately. (This re-uses code written for recipetool appendfile.) Implements [YOCTO #7587]. (From OE-Core rev: 87d487ea4fdfb6cd30e3b3fad47732db12e86f23) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib')
-rw-r--r--scripts/lib/devtool/standard.py148
1 files changed, 107 insertions, 41 deletions
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py
index 122121aedb..c5b32d81db 100644
--- a/scripts/lib/devtool/standard.py
+++ b/scripts/lib/devtool/standard.py
@@ -24,6 +24,7 @@ import tempfile
24import logging 24import logging
25import argparse 25import argparse
26import scriptutils 26import scriptutils
27import errno
27from devtool import exec_build_env_command, setup_tinfoil 28from devtool import exec_build_env_command, setup_tinfoil
28 29
29logger = logging.getLogger('devtool') 30logger = logging.getLogger('devtool')
@@ -510,6 +511,14 @@ def update_recipe(args, config, basepath, workspace):
510 logger.error("no recipe named %s in your workspace" % args.recipename) 511 logger.error("no recipe named %s in your workspace" % args.recipename)
511 return -1 512 return -1
512 513
514 if args.append:
515 if not os.path.exists(args.append):
516 logger.error('bbappend destination layer directory "%s" does not exist' % args.append)
517 return 2
518 if not os.path.exists(os.path.join(args.append, 'conf', 'layer.conf')):
519 logger.error('conf/layer.conf not found in bbappend destination layer "%s"' % args.append)
520 return 2
521
513 tinfoil = setup_tinfoil() 522 tinfoil = setup_tinfoil()
514 import bb 523 import bb
515 from oe.patch import GitApplyTree 524 from oe.patch import GitApplyTree
@@ -535,22 +544,19 @@ def update_recipe(args, config, basepath, workspace):
535 else: 544 else:
536 mode = args.mode 545 mode = args.mode
537 546
538 def remove_patches(srcuri, patchlist): 547 def remove_patch_entries(srcuri, patchlist):
539 """Remove patches""" 548 """Remove patch entries from SRC_URI"""
540 updated = False 549 remaining = patchlist[:]
550 entries = []
541 for patch in patchlist: 551 for patch in patchlist:
542 patchfile = os.path.basename(patch) 552 patchfile = os.path.basename(patch)
543 for i in xrange(len(srcuri)): 553 for i in xrange(len(srcuri)):
544 if srcuri[i].startswith('file://') and os.path.basename(srcuri[i]).split(';')[0] == patchfile: 554 if srcuri[i].startswith('file://') and os.path.basename(srcuri[i].split(';')[0]) == patchfile:
545 logger.info('Removing patch %s' % patchfile) 555 entries.append(srcuri[i])
556 remaining.remove(patch)
546 srcuri.pop(i) 557 srcuri.pop(i)
547 # FIXME "git rm" here would be nice if the file in question is tracked
548 # FIXME there's a chance that this file is referred to by another recipe, in which case deleting wouldn't be the right thing to do
549 if patch.startswith(os.path.dirname(recipefile)):
550 os.remove(patch)
551 updated = True
552 break 558 break
553 return updated 559 return entries, remaining
554 560
555 srctree = workspace[args.recipename] 561 srctree = workspace[args.recipename]
556 562
@@ -565,8 +571,11 @@ def update_recipe(args, config, basepath, workspace):
565 logger.error('Invalid hash returned by git: %s' % stdout) 571 logger.error('Invalid hash returned by git: %s' % stdout)
566 return 1 572 return 1
567 573
574 removepatches = []
575 destpath = None
568 if mode == 'srcrev': 576 if mode == 'srcrev':
569 logger.info('Updating SRCREV in recipe %s' % os.path.basename(recipefile)) 577 logger.info('Updating SRCREV in recipe %s' % os.path.basename(recipefile))
578 removevalues = None
570 patchfields = {} 579 patchfields = {}
571 patchfields['SRCREV'] = srcrev 580 patchfields['SRCREV'] = srcrev
572 if not args.no_remove: 581 if not args.no_remove:
@@ -575,7 +584,6 @@ def update_recipe(args, config, basepath, workspace):
575 584
576 old_srcrev = (rd.getVar('SRCREV', False) or '') 585 old_srcrev = (rd.getVar('SRCREV', False) or '')
577 tempdir = tempfile.mkdtemp(prefix='devtool') 586 tempdir = tempfile.mkdtemp(prefix='devtool')
578 removepatches = []
579 try: 587 try:
580 GitApplyTree.extractPatches(srctree, old_srcrev, tempdir) 588 GitApplyTree.extractPatches(srctree, old_srcrev, tempdir)
581 newpatches = os.listdir(tempdir) 589 newpatches = os.listdir(tempdir)
@@ -587,10 +595,14 @@ def update_recipe(args, config, basepath, workspace):
587 shutil.rmtree(tempdir) 595 shutil.rmtree(tempdir)
588 if removepatches: 596 if removepatches:
589 srcuri = (rd.getVar('SRC_URI', False) or '').split() 597 srcuri = (rd.getVar('SRC_URI', False) or '').split()
590 if remove_patches(srcuri, removepatches): 598 removedentries, _ = remove_patch_entries(srcuri, removepatches)
599 if removedentries:
591 patchfields['SRC_URI'] = ' '.join(srcuri) 600 patchfields['SRC_URI'] = ' '.join(srcuri)
592 601
593 oe.recipeutils.patch_recipe(tinfoil.config_data, recipefile, patchfields) 602 if args.append:
603 (appendfile, destpath) = oe.recipeutils.bbappend_recipe(rd, args.append, None, wildcardver=args.wildcard_version, extralines=patchfields)
604 else:
605 oe.recipeutils.patch_recipe(tinfoil.config_data, recipefile, patchfields)
594 606
595 if not 'git://' in orig_src_uri: 607 if not 'git://' in orig_src_uri:
596 logger.info('You will need to update SRC_URI within the recipe to point to a git repository where you have pushed your changes') 608 logger.info('You will need to update SRC_URI within the recipe to point to a git repository where you have pushed your changes')
@@ -628,6 +640,7 @@ def update_recipe(args, config, basepath, workspace):
628 existing_patches = oe.recipeutils.get_recipe_patches(rd) 640 existing_patches = oe.recipeutils.get_recipe_patches(rd)
629 641
630 removepatches = [] 642 removepatches = []
643 seqpatch_re = re.compile('^[0-9]{4}-')
631 if not args.no_remove: 644 if not args.no_remove:
632 # Get all patches from source tree and check if any should be removed 645 # Get all patches from source tree and check if any should be removed
633 tempdir = tempfile.mkdtemp(prefix='devtool') 646 tempdir = tempfile.mkdtemp(prefix='devtool')
@@ -635,8 +648,18 @@ def update_recipe(args, config, basepath, workspace):
635 GitApplyTree.extractPatches(srctree, initial_rev, tempdir) 648 GitApplyTree.extractPatches(srctree, initial_rev, tempdir)
636 newpatches = os.listdir(tempdir) 649 newpatches = os.listdir(tempdir)
637 for patch in existing_patches: 650 for patch in existing_patches:
651 # If it's a git sequence named patch, the numbers might not match up
652 # since we are starting from a different revision
653 # This does assume that people are using unique shortlog values, but
654 # they ought to be anyway...
638 patchfile = os.path.basename(patch) 655 patchfile = os.path.basename(patch)
639 if patchfile not in newpatches: 656 if seqpatch_re.search(patchfile):
657 for newpatch in newpatches:
658 if seqpatch_re.search(newpatch) and patchfile[5:] == newpatch[5:]:
659 break
660 else:
661 removepatches.append(patch)
662 elif patchfile not in newpatches:
640 removepatches.append(patch) 663 removepatches.append(patch)
641 finally: 664 finally:
642 shutil.rmtree(tempdir) 665 shutil.rmtree(tempdir)
@@ -650,33 +673,56 @@ def update_recipe(args, config, basepath, workspace):
650 updatepatches = False 673 updatepatches = False
651 updaterecipe = False 674 updaterecipe = False
652 newpatches = os.listdir(tempdir) 675 newpatches = os.listdir(tempdir)
653 for patch in existing_patches: 676 if args.append:
654 patchfile = os.path.basename(patch) 677 patchfiles = {}
655 if patchfile in newpatches: 678 for patch in existing_patches:
656 logger.info('Updating patch %s' % patchfile) 679 patchfile = os.path.basename(patch)
657 shutil.move(os.path.join(tempdir, patchfile), patch) 680 if patchfile in newpatches:
658 newpatches.remove(patchfile) 681 patchfiles[os.path.join(tempdir, patchfile)] = patchfile
659 updatepatches = True 682 newpatches.remove(patchfile)
660 srcuri = (rd.getVar('SRC_URI', False) or '').split()
661 if newpatches:
662 # Add any patches left over
663 patchdir = os.path.join(os.path.dirname(recipefile), rd.getVar('BPN', True))
664 bb.utils.mkdirhier(patchdir)
665 for patchfile in newpatches: 683 for patchfile in newpatches:
666 logger.info('Adding new patch %s' % patchfile) 684 patchfiles[os.path.join(tempdir, patchfile)] = None
667 shutil.move(os.path.join(tempdir, patchfile), os.path.join(patchdir, patchfile)) 685
668 srcuri.append('file://%s' % patchfile) 686 if patchfiles or removepatches:
669 updaterecipe = True 687 removevalues = None
670 if removepatches: 688 if removepatches:
671 if remove_patches(srcuri, removepatches): 689 srcuri = (rd.getVar('SRC_URI', False) or '').split()
672 updaterecipe = True 690 removedentries, remaining = remove_patch_entries(srcuri, removepatches)
673 if updaterecipe: 691 if removedentries or remaining:
674 logger.info('Updating recipe %s' % os.path.basename(recipefile)) 692 removevalues = {'SRC_URI': removedentries + ['file://' + os.path.basename(item) for item in remaining]}
675 oe.recipeutils.patch_recipe(tinfoil.config_data, 693 (appendfile, destpath) = oe.recipeutils.bbappend_recipe(rd, args.append, patchfiles, removevalues=removevalues)
676 recipefile, {'SRC_URI': ' '.join(srcuri)}) 694 else:
677 elif not updatepatches: 695 logger.info('No patches needed updating')
678 # Neither patches nor recipe were updated 696 else:
679 logger.info('No patches need updating') 697 for patch in existing_patches:
698 patchfile = os.path.basename(patch)
699 if patchfile in newpatches:
700 logger.info('Updating patch %s' % patchfile)
701 shutil.move(os.path.join(tempdir, patchfile), patch)
702 newpatches.remove(patchfile)
703 updatepatches = True
704 srcuri = (rd.getVar('SRC_URI', False) or '').split()
705 if newpatches:
706 # Add any patches left over
707 patchdir = os.path.join(os.path.dirname(recipefile), rd.getVar('BPN', True))
708 bb.utils.mkdirhier(patchdir)
709 for patchfile in newpatches:
710 logger.info('Adding new patch %s' % patchfile)
711 shutil.move(os.path.join(tempdir, patchfile), os.path.join(patchdir, patchfile))
712 srcuri.append('file://%s' % patchfile)
713 updaterecipe = True
714 if removepatches:
715 removedentries, _ = remove_patch_entries(srcuri, removepatches)
716 if removedentries:
717 updaterecipe = True
718 if updaterecipe:
719 logger.info('Updating recipe %s' % os.path.basename(recipefile))
720 oe.recipeutils.patch_recipe(tinfoil.config_data,
721 recipefile, {'SRC_URI': ' '.join(srcuri)})
722 elif not updatepatches:
723 # Neither patches nor recipe were updated
724 logger.info('No patches need updating')
725
680 finally: 726 finally:
681 shutil.rmtree(tempdir) 727 shutil.rmtree(tempdir)
682 728
@@ -684,6 +730,24 @@ def update_recipe(args, config, basepath, workspace):
684 logger.error('update_recipe: invalid mode %s' % mode) 730 logger.error('update_recipe: invalid mode %s' % mode)
685 return 1 731 return 1
686 732
733 if removepatches:
734 for patchfile in removepatches:
735 if args.append:
736 if not destpath:
737 raise Exception('destpath should be set here')
738 patchfile = os.path.join(destpath, os.path.basename(patchfile))
739
740 if os.path.exists(patchfile):
741 logger.info('Removing patch %s' % patchfile)
742 # FIXME "git rm" here would be nice if the file in question is tracked
743 # FIXME there's a chance that this file is referred to by another recipe, in which case deleting wouldn't be the right thing to do
744 os.remove(patchfile)
745 # Remove directory if empty
746 try:
747 os.rmdir(os.path.dirname(patchfile))
748 except OSError as ose:
749 if ose.errno != errno.ENOTEMPTY:
750 raise
687 return 0 751 return 0
688 752
689 753
@@ -797,6 +861,8 @@ def register_commands(subparsers, context):
797 parser_update_recipe.add_argument('recipename', help='Name of recipe to update') 861 parser_update_recipe.add_argument('recipename', help='Name of recipe to update')
798 parser_update_recipe.add_argument('--mode', '-m', choices=['patch', 'srcrev', 'auto'], default='auto', help='Update mode (where %(metavar)s is %(choices)s; default is %(default)s)', metavar='MODE') 862 parser_update_recipe.add_argument('--mode', '-m', choices=['patch', 'srcrev', 'auto'], default='auto', help='Update mode (where %(metavar)s is %(choices)s; default is %(default)s)', metavar='MODE')
799 parser_update_recipe.add_argument('--initial-rev', help='Starting revision for patches') 863 parser_update_recipe.add_argument('--initial-rev', help='Starting revision for patches')
864 parser_update_recipe.add_argument('--append', '-a', help='Write changes to a bbappend in the specified layer instead of the recipe', metavar='LAYERDIR')
865 parser_update_recipe.add_argument('--wildcard-version', '-w', help='In conjunction with -a/--append, use a wildcard to make the bbappend apply to any recipe version', action='store_true')
800 parser_update_recipe.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update') 866 parser_update_recipe.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update')
801 parser_update_recipe.set_defaults(func=update_recipe) 867 parser_update_recipe.set_defaults(func=update_recipe)
802 868