summaryrefslogtreecommitdiffstats
path: root/scripts/lib
diff options
context:
space:
mode:
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