diff options
Diffstat (limited to 'scripts/lib/devtool/standard.py')
-rw-r--r-- | scripts/lib/devtool/standard.py | 230 |
1 files changed, 144 insertions, 86 deletions
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py index 9b5a0855b2..3a8c66c131 100644 --- a/scripts/lib/devtool/standard.py +++ b/scripts/lib/devtool/standard.py | |||
@@ -359,104 +359,162 @@ def update_recipe(args, config, basepath, workspace): | |||
359 | from oe.patch import GitApplyTree | 359 | from oe.patch import GitApplyTree |
360 | import oe.recipeutils | 360 | import oe.recipeutils |
361 | 361 | ||
362 | srctree = workspace[args.recipename] | ||
363 | commits = [] | ||
364 | update_rev = None | ||
365 | if args.initial_rev: | ||
366 | initial_rev = args.initial_rev | ||
367 | else: | ||
368 | initial_rev = None | ||
369 | with open(appends[0], 'r') as f: | ||
370 | for line in f: | ||
371 | if line.startswith('# initial_rev:'): | ||
372 | initial_rev = line.split(':')[-1].strip() | ||
373 | elif line.startswith('# commit:'): | ||
374 | commits.append(line.split(':')[-1].strip()) | ||
375 | |||
376 | if initial_rev: | ||
377 | # Find first actually changed revision | ||
378 | (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=srctree) | ||
379 | newcommits = stdout.split() | ||
380 | for i in xrange(min(len(commits), len(newcommits))): | ||
381 | if newcommits[i] == commits[i]: | ||
382 | update_rev = commits[i] | ||
383 | |||
384 | if not initial_rev: | ||
385 | logger.error('Unable to find initial revision - please specify it with --initial-rev') | ||
386 | return -1 | ||
387 | |||
388 | if not update_rev: | ||
389 | update_rev = initial_rev | ||
390 | |||
391 | # Find list of existing patches in recipe file | ||
392 | recipefile = _get_recipe_file(tinfoil.cooker, args.recipename) | 362 | recipefile = _get_recipe_file(tinfoil.cooker, args.recipename) |
393 | if not recipefile: | 363 | if not recipefile: |
394 | # Error already logged | 364 | # Error already logged |
395 | return -1 | 365 | return -1 |
396 | rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data) | 366 | rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data) |
397 | existing_patches = oe.recipeutils.get_recipe_patches(rd) | ||
398 | 367 | ||
399 | removepatches = [] | 368 | orig_src_uri = rd.getVar('SRC_URI', False) or '' |
400 | if not args.no_remove: | 369 | if args.mode == 'auto': |
401 | # Get all patches from source tree and check if any should be removed | 370 | if 'git://' in orig_src_uri: |
371 | mode = 'srcrev' | ||
372 | else: | ||
373 | mode = 'patch' | ||
374 | else: | ||
375 | mode = args.mode | ||
376 | |||
377 | def remove_patches(srcuri, patchlist): | ||
378 | # Remove any patches that we don't need | ||
379 | updated = False | ||
380 | for patch in patchlist: | ||
381 | patchfile = os.path.basename(patch) | ||
382 | for i in xrange(len(srcuri)): | ||
383 | if srcuri[i].startswith('file://') and os.path.basename(srcuri[i]).split(';')[0] == patchfile: | ||
384 | logger.info('Removing patch %s' % patchfile) | ||
385 | srcuri.pop(i) | ||
386 | # FIXME "git rm" here would be nice if the file in question is tracked | ||
387 | # 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 | ||
388 | if patch.startswith(os.path.dirname(recipefile)): | ||
389 | os.remove(patch) | ||
390 | updated = True | ||
391 | break | ||
392 | return updated | ||
393 | |||
394 | srctree = workspace[args.recipename] | ||
395 | if mode == 'srcrev': | ||
396 | (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree) | ||
397 | srcrev = stdout.strip() | ||
398 | if len(srcrev) != 40: | ||
399 | logger.error('Invalid hash returned by git: %s' % stdout) | ||
400 | return 1 | ||
401 | |||
402 | logger.info('Updating SRCREV in recipe %s' % os.path.basename(recipefile)) | ||
403 | patchfields = {} | ||
404 | patchfields['SRCREV'] = srcrev | ||
405 | if not args.no_remove: | ||
406 | # Find list of existing patches in recipe file | ||
407 | existing_patches = oe.recipeutils.get_recipe_patches(rd) | ||
408 | |||
409 | old_srcrev = (rd.getVar('SRCREV', False) or '') | ||
410 | tempdir = tempfile.mkdtemp(prefix='devtool') | ||
411 | removepatches = [] | ||
412 | try: | ||
413 | GitApplyTree.extractPatches(srctree, old_srcrev, tempdir) | ||
414 | newpatches = os.listdir(tempdir) | ||
415 | for patch in existing_patches: | ||
416 | patchfile = os.path.basename(patch) | ||
417 | if patchfile in newpatches: | ||
418 | removepatches.append(patch) | ||
419 | finally: | ||
420 | shutil.rmtree(tempdir) | ||
421 | if removepatches: | ||
422 | srcuri = (rd.getVar('SRC_URI', False) or '').split() | ||
423 | if remove_patches(srcuri, removepatches): | ||
424 | patchfields['SRC_URI'] = ' '.join(srcuri) | ||
425 | |||
426 | oe.recipeutils.patch_recipe(rd, recipefile, patchfields) | ||
427 | |||
428 | if not 'git://' in orig_src_uri: | ||
429 | logger.info('You will need to update SRC_URI within the recipe to point to a git repository where you have pushed your changes') | ||
430 | |||
431 | elif mode == 'patch': | ||
432 | commits = [] | ||
433 | update_rev = None | ||
434 | if args.initial_rev: | ||
435 | initial_rev = args.initial_rev | ||
436 | else: | ||
437 | initial_rev = None | ||
438 | with open(appends[0], 'r') as f: | ||
439 | for line in f: | ||
440 | if line.startswith('# initial_rev:'): | ||
441 | initial_rev = line.split(':')[-1].strip() | ||
442 | elif line.startswith('# commit:'): | ||
443 | commits.append(line.split(':')[-1].strip()) | ||
444 | |||
445 | if initial_rev: | ||
446 | # Find first actually changed revision | ||
447 | (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_rev, cwd=srctree) | ||
448 | newcommits = stdout.split() | ||
449 | for i in xrange(min(len(commits), len(newcommits))): | ||
450 | if newcommits[i] == commits[i]: | ||
451 | update_rev = commits[i] | ||
452 | |||
453 | if not initial_rev: | ||
454 | logger.error('Unable to find initial revision - please specify it with --initial-rev') | ||
455 | return -1 | ||
456 | |||
457 | if not update_rev: | ||
458 | update_rev = initial_rev | ||
459 | |||
460 | # Find list of existing patches in recipe file | ||
461 | existing_patches = oe.recipeutils.get_recipe_patches(rd) | ||
462 | |||
463 | removepatches = [] | ||
464 | if not args.no_remove: | ||
465 | # Get all patches from source tree and check if any should be removed | ||
466 | tempdir = tempfile.mkdtemp(prefix='devtool') | ||
467 | try: | ||
468 | GitApplyTree.extractPatches(srctree, initial_rev, tempdir) | ||
469 | newpatches = os.listdir(tempdir) | ||
470 | for patch in existing_patches: | ||
471 | patchfile = os.path.basename(patch) | ||
472 | if patchfile not in newpatches: | ||
473 | removepatches.append(patch) | ||
474 | finally: | ||
475 | shutil.rmtree(tempdir) | ||
476 | |||
477 | # Get updated patches from source tree | ||
402 | tempdir = tempfile.mkdtemp(prefix='devtool') | 478 | tempdir = tempfile.mkdtemp(prefix='devtool') |
403 | try: | 479 | try: |
404 | GitApplyTree.extractPatches(srctree, initial_rev, tempdir) | 480 | GitApplyTree.extractPatches(srctree, update_rev, tempdir) |
481 | |||
482 | # Match up and replace existing patches with corresponding new patches | ||
483 | updatepatches = False | ||
484 | updaterecipe = False | ||
405 | newpatches = os.listdir(tempdir) | 485 | newpatches = os.listdir(tempdir) |
406 | for patch in existing_patches: | 486 | for patch in existing_patches: |
407 | patchfile = os.path.basename(patch) | 487 | patchfile = os.path.basename(patch) |
408 | if patchfile not in newpatches: | 488 | if patchfile in newpatches: |
409 | removepatches.append(patch) | 489 | logger.info('Updating patch %s' % patchfile) |
490 | shutil.move(os.path.join(tempdir, patchfile), patch) | ||
491 | newpatches.remove(patchfile) | ||
492 | updatepatches = True | ||
493 | srcuri = (rd.getVar('SRC_URI', False) or '').split() | ||
494 | if newpatches: | ||
495 | # Add any patches left over | ||
496 | patchdir = os.path.join(os.path.dirname(recipefile), rd.getVar('BPN', True)) | ||
497 | bb.utils.mkdirhier(patchdir) | ||
498 | for patchfile in newpatches: | ||
499 | logger.info('Adding new patch %s' % patchfile) | ||
500 | shutil.move(os.path.join(tempdir, patchfile), os.path.join(patchdir, patchfile)) | ||
501 | srcuri.append('file://%s' % patchfile) | ||
502 | updaterecipe = True | ||
503 | if removepatches: | ||
504 | if remove_patches(srcuri, removepatches): | ||
505 | updaterecipe = True | ||
506 | if updaterecipe: | ||
507 | logger.info('Updating recipe %s' % os.path.basename(recipefile)) | ||
508 | oe.recipeutils.patch_recipe(rd, recipefile, {'SRC_URI': ' '.join(srcuri)}) | ||
509 | elif not updatepatches: | ||
510 | # Neither patches nor recipe were updated | ||
511 | logger.info('No patches need updating') | ||
410 | finally: | 512 | finally: |
411 | shutil.rmtree(tempdir) | 513 | shutil.rmtree(tempdir) |
412 | 514 | ||
413 | # Get updated patches from source tree | 515 | else: |
414 | tempdir = tempfile.mkdtemp(prefix='devtool') | 516 | logger.error('update_recipe: invalid mode %s' % mode) |
415 | try: | 517 | return 1 |
416 | GitApplyTree.extractPatches(srctree, update_rev, tempdir) | ||
417 | |||
418 | # Match up and replace existing patches with corresponding new patches | ||
419 | updatepatches = False | ||
420 | updaterecipe = False | ||
421 | newpatches = os.listdir(tempdir) | ||
422 | for patch in existing_patches: | ||
423 | patchfile = os.path.basename(patch) | ||
424 | if patchfile in newpatches: | ||
425 | logger.info('Updating patch %s' % patchfile) | ||
426 | shutil.move(os.path.join(tempdir, patchfile), patch) | ||
427 | newpatches.remove(patchfile) | ||
428 | updatepatches = True | ||
429 | srcuri = (rd.getVar('SRC_URI', False) or '').split() | ||
430 | if newpatches: | ||
431 | # Add any patches left over | ||
432 | patchdir = os.path.join(os.path.dirname(recipefile), rd.getVar('BPN', True)) | ||
433 | bb.utils.mkdirhier(patchdir) | ||
434 | for patchfile in newpatches: | ||
435 | logger.info('Adding new patch %s' % patchfile) | ||
436 | shutil.move(os.path.join(tempdir, patchfile), os.path.join(patchdir, patchfile)) | ||
437 | srcuri.append('file://%s' % patchfile) | ||
438 | updaterecipe = True | ||
439 | if removepatches: | ||
440 | # Remove any patches that we don't need | ||
441 | for patch in removepatches: | ||
442 | patchfile = os.path.basename(patch) | ||
443 | for i in xrange(len(srcuri)): | ||
444 | if srcuri[i].startswith('file://') and os.path.basename(srcuri[i]).split(';')[0] == patchfile: | ||
445 | logger.info('Removing patch %s' % patchfile) | ||
446 | srcuri.pop(i) | ||
447 | # FIXME "git rm" here would be nice if the file in question is tracked | ||
448 | # 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 | ||
449 | os.remove(patch) | ||
450 | updaterecipe = True | ||
451 | break | ||
452 | if updaterecipe: | ||
453 | logger.info('Updating recipe %s' % os.path.basename(recipefile)) | ||
454 | oe.recipeutils.patch_recipe(rd, recipefile, {'SRC_URI': ' '.join(srcuri)}) | ||
455 | elif not updatepatches: | ||
456 | # Neither patches nor recipe were updated | ||
457 | logger.info('No patches need updating') | ||
458 | finally: | ||
459 | shutil.rmtree(tempdir) | ||
460 | 518 | ||
461 | return 0 | 519 | return 0 |
462 | 520 | ||
@@ -539,9 +597,9 @@ def register_commands(subparsers, context): | |||
539 | parser_add.set_defaults(func=extract) | 597 | parser_add.set_defaults(func=extract) |
540 | 598 | ||
541 | parser_add = subparsers.add_parser('update-recipe', help='Apply changes from external source tree to recipe', | 599 | parser_add = subparsers.add_parser('update-recipe', help='Apply changes from external source tree to recipe', |
542 | description='Applies changes from external source tree to a recipe (updating/adding/removing patches as necessary)', | 600 | description='Applies changes from external source tree to a recipe (updating/adding/removing patches as necessary, or by updating SRCREV)') |
543 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
544 | parser_add.add_argument('recipename', help='Name of recipe to update') | 601 | parser_add.add_argument('recipename', help='Name of recipe to update') |
602 | parser_add.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') | ||
545 | parser_add.add_argument('--initial-rev', help='Starting revision for patches') | 603 | parser_add.add_argument('--initial-rev', help='Starting revision for patches') |
546 | parser_add.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update') | 604 | parser_add.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update') |
547 | parser_add.set_defaults(func=update_recipe) | 605 | parser_add.set_defaults(func=update_recipe) |