summaryrefslogtreecommitdiffstats
path: root/scripts/lib/devtool/standard.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/devtool/standard.py')
-rw-r--r--scripts/lib/devtool/standard.py288
1 files changed, 108 insertions, 180 deletions
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py
index bd009f44b1..1fd5947c41 100644
--- a/scripts/lib/devtool/standard.py
+++ b/scripts/lib/devtool/standard.py
@@ -18,11 +18,13 @@ import argparse_oe
18import scriptutils 18import scriptutils
19import errno 19import errno
20import glob 20import glob
21import filecmp
22from collections import OrderedDict 21from collections import OrderedDict
22
23from devtool import exec_build_env_command, setup_tinfoil, check_workspace_recipe, use_external_build, setup_git_repo, recipe_to_append, get_bbclassextend_targets, update_unlockedsigs, check_prerelease_version, check_git_repo_dirty, check_git_repo_op, DevtoolError 23from devtool import exec_build_env_command, setup_tinfoil, check_workspace_recipe, use_external_build, setup_git_repo, recipe_to_append, get_bbclassextend_targets, update_unlockedsigs, check_prerelease_version, check_git_repo_dirty, check_git_repo_op, DevtoolError
24from devtool import parse_recipe 24from devtool import parse_recipe
25 25
26import bb.utils
27
26logger = logging.getLogger('devtool') 28logger = logging.getLogger('devtool')
27 29
28override_branch_prefix = 'devtool-override-' 30override_branch_prefix = 'devtool-override-'
@@ -30,7 +32,8 @@ override_branch_prefix = 'devtool-override-'
30 32
31def add(args, config, basepath, workspace): 33def add(args, config, basepath, workspace):
32 """Entry point for the devtool 'add' subcommand""" 34 """Entry point for the devtool 'add' subcommand"""
33 import bb 35 import bb.data
36 import bb.process
34 import oe.recipeutils 37 import oe.recipeutils
35 38
36 if not args.recipename and not args.srctree and not args.fetch and not args.fetchuri: 39 if not args.recipename and not args.srctree and not args.fetch and not args.fetchuri:
@@ -206,7 +209,7 @@ def add(args, config, basepath, workspace):
206 for fn in os.listdir(tempdir): 209 for fn in os.listdir(tempdir):
207 shutil.move(os.path.join(tempdir, fn), recipedir) 210 shutil.move(os.path.join(tempdir, fn), recipedir)
208 else: 211 else:
209 raise DevtoolError('Command \'%s\' did not create any recipe file:\n%s' % (e.command, e.stdout)) 212 raise DevtoolError(f'Failed to create a recipe file for source {source}')
210 attic_recipe = os.path.join(config.workspace_path, 'attic', recipename, os.path.basename(recipefile)) 213 attic_recipe = os.path.join(config.workspace_path, 'attic', recipename, os.path.basename(recipefile))
211 if os.path.exists(attic_recipe): 214 if os.path.exists(attic_recipe):
212 logger.warning('A modified recipe from a previous invocation exists in %s - you may wish to move this over the top of the new recipe if you had changes in it that you want to continue with' % attic_recipe) 215 logger.warning('A modified recipe from a previous invocation exists in %s - you may wish to move this over the top of the new recipe if you had changes in it that you want to continue with' % attic_recipe)
@@ -305,6 +308,7 @@ def add(args, config, basepath, workspace):
305 308
306def _check_compatible_recipe(pn, d): 309def _check_compatible_recipe(pn, d):
307 """Check if the recipe is supported by devtool""" 310 """Check if the recipe is supported by devtool"""
311 import bb.data
308 if pn == 'perf': 312 if pn == 'perf':
309 raise DevtoolError("The perf recipe does not actually check out " 313 raise DevtoolError("The perf recipe does not actually check out "
310 "source and thus cannot be supported by this tool", 314 "source and thus cannot be supported by this tool",
@@ -374,7 +378,7 @@ def _copy_file(src, dst, dry_run_outdir=None, base_outdir=None):
374 378
375def _git_ls_tree(repodir, treeish='HEAD', recursive=False): 379def _git_ls_tree(repodir, treeish='HEAD', recursive=False):
376 """List contents of a git treeish""" 380 """List contents of a git treeish"""
377 import bb 381 import bb.process
378 cmd = ['git', 'ls-tree', '-z', treeish] 382 cmd = ['git', 'ls-tree', '-z', treeish]
379 if recursive: 383 if recursive:
380 cmd.append('-r') 384 cmd.append('-r')
@@ -387,6 +391,19 @@ def _git_ls_tree(repodir, treeish='HEAD', recursive=False):
387 ret[split[3]] = split[0:3] 391 ret[split[3]] = split[0:3]
388 return ret 392 return ret
389 393
394def _git_modified(repodir):
395 """List the difference between HEAD and the index"""
396 import bb.process
397 cmd = ['git', 'status', '--porcelain']
398 out, _ = bb.process.run(cmd, cwd=repodir)
399 ret = []
400 if out:
401 for line in out.split("\n"):
402 if line and not line.startswith('??'):
403 ret.append(line[3:])
404 return ret
405
406
390def _git_exclude_path(srctree, path): 407def _git_exclude_path(srctree, path):
391 """Return pathspec (list of paths) that excludes certain path""" 408 """Return pathspec (list of paths) that excludes certain path"""
392 # NOTE: "Filtering out" files/paths in this way is not entirely reliable - 409 # NOTE: "Filtering out" files/paths in this way is not entirely reliable -
@@ -414,8 +431,6 @@ def _ls_tree(directory):
414 431
415def extract(args, config, basepath, workspace): 432def extract(args, config, basepath, workspace):
416 """Entry point for the devtool 'extract' subcommand""" 433 """Entry point for the devtool 'extract' subcommand"""
417 import bb
418
419 tinfoil = setup_tinfoil(basepath=basepath, tracking=True) 434 tinfoil = setup_tinfoil(basepath=basepath, tracking=True)
420 if not tinfoil: 435 if not tinfoil:
421 # Error already shown 436 # Error already shown
@@ -438,8 +453,6 @@ def extract(args, config, basepath, workspace):
438 453
439def sync(args, config, basepath, workspace): 454def sync(args, config, basepath, workspace):
440 """Entry point for the devtool 'sync' subcommand""" 455 """Entry point for the devtool 'sync' subcommand"""
441 import bb
442
443 tinfoil = setup_tinfoil(basepath=basepath, tracking=True) 456 tinfoil = setup_tinfoil(basepath=basepath, tracking=True)
444 if not tinfoil: 457 if not tinfoil:
445 # Error already shown 458 # Error already shown
@@ -460,37 +473,11 @@ def sync(args, config, basepath, workspace):
460 finally: 473 finally:
461 tinfoil.shutdown() 474 tinfoil.shutdown()
462 475
463def symlink_oelocal_files_srctree(rd, srctree):
464 import oe.patch
465 if os.path.abspath(rd.getVar('S')) == os.path.abspath(rd.getVar('WORKDIR')):
466 # If recipe extracts to ${WORKDIR}, symlink the files into the srctree
467 # (otherwise the recipe won't build as expected)
468 local_files_dir = os.path.join(srctree, 'oe-local-files')
469 addfiles = []
470 for root, _, files in os.walk(local_files_dir):
471 relpth = os.path.relpath(root, local_files_dir)
472 if relpth != '.':
473 bb.utils.mkdirhier(os.path.join(srctree, relpth))
474 for fn in files:
475 if fn == '.gitignore':
476 continue
477 destpth = os.path.join(srctree, relpth, fn)
478 if os.path.exists(destpth):
479 os.unlink(destpth)
480 if relpth != '.':
481 back_relpth = os.path.relpath(local_files_dir, root)
482 os.symlink('%s/oe-local-files/%s/%s' % (back_relpth, relpth, fn), destpth)
483 else:
484 os.symlink('oe-local-files/%s' % fn, destpth)
485 addfiles.append(os.path.join(relpth, fn))
486 if addfiles:
487 oe.patch.GitApplyTree.commitIgnored("Add local file symlinks", dir=srctree, files=addfiles, d=rd)
488
489def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, workspace, fixed_setup, d, tinfoil, no_overrides=False): 476def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, workspace, fixed_setup, d, tinfoil, no_overrides=False):
490 """Extract sources of a recipe""" 477 """Extract sources of a recipe"""
491 import oe.recipeutils
492 import oe.patch
493 import oe.path 478 import oe.path
479 import bb.data
480 import bb.process
494 481
495 pn = d.getVar('PN') 482 pn = d.getVar('PN')
496 483
@@ -555,6 +542,7 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
555 tempbasedir = d.getVar('WORKDIR') 542 tempbasedir = d.getVar('WORKDIR')
556 bb.utils.mkdirhier(tempbasedir) 543 bb.utils.mkdirhier(tempbasedir)
557 tempdir = tempfile.mkdtemp(prefix='devtooltmp-', dir=tempbasedir) 544 tempdir = tempfile.mkdtemp(prefix='devtooltmp-', dir=tempbasedir)
545 appendbackup = None
558 try: 546 try:
559 tinfoil.logger.setLevel(logging.WARNING) 547 tinfoil.logger.setLevel(logging.WARNING)
560 548
@@ -565,7 +553,6 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
565 appendbackup = os.path.join(tempdir, os.path.basename(appendfile) + '.bak') 553 appendbackup = os.path.join(tempdir, os.path.basename(appendfile) + '.bak')
566 shutil.copyfile(appendfile, appendbackup) 554 shutil.copyfile(appendfile, appendbackup)
567 else: 555 else:
568 appendbackup = None
569 bb.utils.mkdirhier(os.path.dirname(appendfile)) 556 bb.utils.mkdirhier(os.path.dirname(appendfile))
570 logger.debug('writing append file %s' % appendfile) 557 logger.debug('writing append file %s' % appendfile)
571 with open(appendfile, 'a') as f: 558 with open(appendfile, 'a') as f:
@@ -638,7 +625,7 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
638 srcsubdir = f.read() 625 srcsubdir = f.read()
639 except FileNotFoundError as e: 626 except FileNotFoundError as e:
640 raise DevtoolError('Something went wrong with source extraction - the devtool-source class was not active or did not function correctly:\n%s' % str(e)) 627 raise DevtoolError('Something went wrong with source extraction - the devtool-source class was not active or did not function correctly:\n%s' % str(e))
641 srcsubdir_rel = os.path.relpath(srcsubdir, os.path.join(tempdir, 'workdir')) 628 srcsubdir_rel = os.path.relpath(srcsubdir, os.path.join(tempdir, 'workdir', os.path.relpath(d.getVar('UNPACKDIR'), d.getVar('WORKDIR'))))
642 629
643 # Check if work-shared is empty, if yes 630 # Check if work-shared is empty, if yes
644 # find source and copy to work-shared 631 # find source and copy to work-shared
@@ -657,9 +644,6 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
657 elif not os.path.exists(workshareddir): 644 elif not os.path.exists(workshareddir):
658 oe.path.copyhardlinktree(srcsubdir, workshareddir) 645 oe.path.copyhardlinktree(srcsubdir, workshareddir)
659 646
660 tempdir_localdir = os.path.join(tempdir, 'oe-local-files')
661 srctree_localdir = os.path.join(srctree, 'oe-local-files')
662
663 if sync: 647 if sync:
664 try: 648 try:
665 logger.info('Backing up current %s branch as branch: %s.bak' % (devbranch, devbranch)) 649 logger.info('Backing up current %s branch as branch: %s.bak' % (devbranch, devbranch))
@@ -674,29 +658,8 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
674 except bb.process.ExecutionError as e: 658 except bb.process.ExecutionError as e:
675 raise DevtoolError("Error when syncing source files to local checkout: %s" % str(e)) 659 raise DevtoolError("Error when syncing source files to local checkout: %s" % str(e))
676 660
677 # Move the oe-local-files directory to srctree.
678 # As oe-local-files is not part of the constructed git tree,
679 # removing it directly during the synchronization might surprise
680 # the user. Instead, we move it to oe-local-files.bak and remind
681 # the user in the log message.
682 if os.path.exists(srctree_localdir + '.bak'):
683 shutil.rmtree(srctree_localdir + '.bak')
684
685 if os.path.exists(srctree_localdir):
686 logger.info('Backing up current local file directory %s' % srctree_localdir)
687 shutil.move(srctree_localdir, srctree_localdir + '.bak')
688
689 if os.path.exists(tempdir_localdir):
690 logger.info('Syncing local source files to srctree...')
691 shutil.copytree(tempdir_localdir, srctree_localdir)
692 else: 661 else:
693 # Move oe-local-files directory to srctree
694 if os.path.exists(tempdir_localdir):
695 logger.info('Adding local source files to srctree...')
696 shutil.move(tempdir_localdir, srcsubdir)
697
698 shutil.move(srcsubdir, srctree) 662 shutil.move(srcsubdir, srctree)
699 symlink_oelocal_files_srctree(d, srctree)
700 663
701 if is_kernel_yocto: 664 if is_kernel_yocto:
702 logger.info('Copying kernel config to srctree') 665 logger.info('Copying kernel config to srctree')
@@ -715,8 +678,6 @@ def _extract_source(srctree, keep_temp, devbranch, sync, config, basepath, works
715 678
716def _add_md5(config, recipename, filename): 679def _add_md5(config, recipename, filename):
717 """Record checksum of a file (or recursively for a directory) to the md5-file of the workspace""" 680 """Record checksum of a file (or recursively for a directory) to the md5-file of the workspace"""
718 import bb.utils
719
720 def addfile(fn): 681 def addfile(fn):
721 md5 = bb.utils.md5_file(fn) 682 md5 = bb.utils.md5_file(fn)
722 with open(os.path.join(config.workspace_path, '.devtool_md5'), 'a+') as f: 683 with open(os.path.join(config.workspace_path, '.devtool_md5'), 'a+') as f:
@@ -735,7 +696,6 @@ def _add_md5(config, recipename, filename):
735def _check_preserve(config, recipename): 696def _check_preserve(config, recipename):
736 """Check if a file was manually changed and needs to be saved in 'attic' 697 """Check if a file was manually changed and needs to be saved in 'attic'
737 directory""" 698 directory"""
738 import bb.utils
739 origfile = os.path.join(config.workspace_path, '.devtool_md5') 699 origfile = os.path.join(config.workspace_path, '.devtool_md5')
740 newfile = os.path.join(config.workspace_path, '.devtool_md5_new') 700 newfile = os.path.join(config.workspace_path, '.devtool_md5_new')
741 preservepath = os.path.join(config.workspace_path, 'attic', recipename) 701 preservepath = os.path.join(config.workspace_path, 'attic', recipename)
@@ -766,36 +726,36 @@ def _check_preserve(config, recipename):
766 726
767def get_staging_kver(srcdir): 727def get_staging_kver(srcdir):
768 # Kernel version from work-shared 728 # Kernel version from work-shared
769 kerver = [] 729 import itertools
770 staging_kerVer="" 730 try:
771 if os.path.exists(srcdir) and os.listdir(srcdir):
772 with open(os.path.join(srcdir, "Makefile")) as f: 731 with open(os.path.join(srcdir, "Makefile")) as f:
773 version = [next(f) for x in range(5)][1:4] 732 # Take VERSION, PATCHLEVEL, SUBLEVEL from lines 1, 2, 3
774 for word in version: 733 return ".".join(line.rstrip().split('= ')[1] for line in itertools.islice(f, 1, 4))
775 kerver.append(word.split('= ')[1].split('\n')[0]) 734 except FileNotFoundError:
776 staging_kerVer = ".".join(kerver) 735 return ""
777 return staging_kerVer
778 736
779def get_staging_kbranch(srcdir): 737def get_staging_kbranch(srcdir):
738 import bb.process
780 staging_kbranch = "" 739 staging_kbranch = ""
781 if os.path.exists(srcdir) and os.listdir(srcdir): 740 if os.path.exists(srcdir) and os.listdir(srcdir):
782 (branch, _) = bb.process.run('git branch | grep \\* | cut -d \' \' -f2', cwd=srcdir) 741 (branch, _) = bb.process.run('git branch | grep \\* | cut -d \' \' -f2', cwd=srcdir)
783 staging_kbranch = "".join(branch.split('\n')[0]) 742 staging_kbranch = "".join(branch.split('\n')[0])
784 return staging_kbranch 743 return staging_kbranch
785 744
786def get_real_srctree(srctree, s, workdir): 745def get_real_srctree(srctree, s, unpackdir):
787 # Check that recipe isn't using a shared workdir 746 # Check that recipe isn't using a shared workdir
788 s = os.path.abspath(s) 747 s = os.path.abspath(s)
789 workdir = os.path.abspath(workdir) 748 unpackdir = os.path.abspath(unpackdir)
790 if s.startswith(workdir) and s != workdir and os.path.dirname(s) != workdir: 749 if s.startswith(unpackdir) and s != unpackdir and os.path.dirname(s) != unpackdir:
791 # Handle if S is set to a subdirectory of the source 750 # Handle if S is set to a subdirectory of the source
792 srcsubdir = os.path.relpath(s, workdir).split(os.sep, 1)[1] 751 srcsubdir = os.path.relpath(s, unpackdir).split(os.sep, 1)[1]
793 srctree = os.path.join(srctree, srcsubdir) 752 srctree = os.path.join(srctree, srcsubdir)
794 return srctree 753 return srctree
795 754
796def modify(args, config, basepath, workspace): 755def modify(args, config, basepath, workspace):
797 """Entry point for the devtool 'modify' subcommand""" 756 """Entry point for the devtool 'modify' subcommand"""
798 import bb 757 import bb.data
758 import bb.process
799 import oe.recipeutils 759 import oe.recipeutils
800 import oe.patch 760 import oe.patch
801 import oe.path 761 import oe.path
@@ -851,35 +811,21 @@ def modify(args, config, basepath, workspace):
851 staging_kbranch = get_staging_kbranch(srcdir) 811 staging_kbranch = get_staging_kbranch(srcdir)
852 if (os.path.exists(srcdir) and os.listdir(srcdir)) and (kernelVersion in staging_kerVer and staging_kbranch == kbranch): 812 if (os.path.exists(srcdir) and os.listdir(srcdir)) and (kernelVersion in staging_kerVer and staging_kbranch == kbranch):
853 oe.path.copyhardlinktree(srcdir, srctree) 813 oe.path.copyhardlinktree(srcdir, srctree)
854 workdir = rd.getVar('WORKDIR') 814 unpackdir = rd.getVar('UNPACKDIR')
855 srcsubdir = rd.getVar('S') 815 srcsubdir = rd.getVar('S')
856 localfilesdir = os.path.join(srctree, 'oe-local-files')
857 # Move local source files into separate subdir
858 recipe_patches = [os.path.basename(patch) for patch in oe.recipeutils.get_recipe_patches(rd)]
859 local_files = oe.recipeutils.get_recipe_local_files(rd)
860 816
861 for key in local_files.copy(): 817 # Add locally copied files to gitignore as we add back to the metadata directly
862 if key.endswith('scc'): 818 local_files = oe.recipeutils.get_recipe_local_files(rd)
863 sccfile = open(local_files[key], 'r')
864 for l in sccfile:
865 line = l.split()
866 if line and line[0] in ('kconf', 'patch'):
867 cfg = os.path.join(os.path.dirname(local_files[key]), line[-1])
868 if not cfg in local_files.values():
869 local_files[line[-1]] = cfg
870 shutil.copy2(cfg, workdir)
871 sccfile.close()
872
873 # Ignore local files with subdir={BP}
874 srcabspath = os.path.abspath(srcsubdir) 819 srcabspath = os.path.abspath(srcsubdir)
875 local_files = [fname for fname in local_files if os.path.exists(os.path.join(workdir, fname)) and (srcabspath == workdir or not os.path.join(workdir, fname).startswith(srcabspath + os.sep))] 820 local_files = [fname for fname in local_files if
821 os.path.exists(os.path.join(unpackdir, fname)) and
822 srcabspath == unpackdir]
876 if local_files: 823 if local_files:
877 for fname in local_files: 824 with open(os.path.join(srctree, '.gitignore'), 'a+') as f:
878 _move_file(os.path.join(workdir, fname), os.path.join(srctree, 'oe-local-files', fname)) 825 f.write('# Ignore local files, by default. Remove following lines'
879 with open(os.path.join(srctree, 'oe-local-files', '.gitignore'), 'w') as f: 826 'if you want to commit the directory to Git\n')
880 f.write('# Ignore local files, by default. Remove this file if you want to commit the directory to Git\n*\n') 827 for fname in local_files:
881 828 f.write('%s\n' % fname)
882 symlink_oelocal_files_srctree(rd, srctree)
883 829
884 task = 'do_configure' 830 task = 'do_configure'
885 res = tinfoil.build_targets(pn, task, handle_events=True) 831 res = tinfoil.build_targets(pn, task, handle_events=True)
@@ -904,7 +850,10 @@ def modify(args, config, basepath, workspace):
904 (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_revs["."], cwd=srctree) 850 (stdout, _) = bb.process.run('git rev-list --reverse %s..HEAD' % initial_revs["."], cwd=srctree)
905 commits["."] = stdout.split() 851 commits["."] = stdout.split()
906 check_commits = True 852 check_commits = True
907 (stdout, _) = bb.process.run('git submodule --quiet foreach --recursive \'echo `git rev-parse devtool-base` $PWD\'', cwd=srctree) 853 try:
854 (stdout, _) = bb.process.run('git submodule --quiet foreach --recursive \'echo `git rev-parse devtool-base` $PWD\'', cwd=srctree)
855 except bb.process.ExecutionError:
856 stdout = ""
908 for line in stdout.splitlines(): 857 for line in stdout.splitlines():
909 (rev, submodule_path) = line.split() 858 (rev, submodule_path) = line.split()
910 submodule = os.path.relpath(submodule_path, srctree) 859 submodule = os.path.relpath(submodule_path, srctree)
@@ -958,7 +907,7 @@ def modify(args, config, basepath, workspace):
958 907
959 # Need to grab this here in case the source is within a subdirectory 908 # Need to grab this here in case the source is within a subdirectory
960 srctreebase = srctree 909 srctreebase = srctree
961 srctree = get_real_srctree(srctree, rd.getVar('S'), rd.getVar('WORKDIR')) 910 srctree = get_real_srctree(srctree, rd.getVar('S'), rd.getVar('UNPACKDIR'))
962 911
963 bb.utils.mkdirhier(os.path.dirname(appendfile)) 912 bb.utils.mkdirhier(os.path.dirname(appendfile))
964 with open(appendfile, 'w') as f: 913 with open(appendfile, 'w') as f:
@@ -998,13 +947,6 @@ def modify(args, config, basepath, workspace):
998 f.write('EXTERNALSRC_BUILD:pn-%s = "%s"\n' % (pn, srctree)) 947 f.write('EXTERNALSRC_BUILD:pn-%s = "%s"\n' % (pn, srctree))
999 948
1000 if bb.data.inherits_class('kernel', rd): 949 if bb.data.inherits_class('kernel', rd):
1001 f.write('SRCTREECOVEREDTASKS = "do_validate_branches do_kernel_checkout '
1002 'do_fetch do_unpack do_kernel_configcheck"\n')
1003 f.write('\ndo_patch[noexec] = "1"\n')
1004 f.write('\ndo_configure:append() {\n'
1005 ' cp ${B}/.config ${S}/.config.baseline\n'
1006 ' ln -sfT ${B}/.config ${S}/.config.new\n'
1007 '}\n')
1008 f.write('\ndo_kernel_configme:prepend() {\n' 950 f.write('\ndo_kernel_configme:prepend() {\n'
1009 ' if [ -e ${S}/.config ]; then\n' 951 ' if [ -e ${S}/.config ]; then\n'
1010 ' mv ${S}/.config ${S}/.config.old\n' 952 ' mv ${S}/.config ${S}/.config.old\n'
@@ -1028,6 +970,8 @@ def modify(args, config, basepath, workspace):
1028 if branch == args.branch: 970 if branch == args.branch:
1029 continue 971 continue
1030 f.write('# patches_%s: %s\n' % (branch, ','.join(branch_patches[branch]))) 972 f.write('# patches_%s: %s\n' % (branch, ','.join(branch_patches[branch])))
973 if args.debug_build:
974 f.write('\nDEBUG_BUILD = "1"\n')
1031 975
1032 update_unlockedsigs(basepath, workspace, args.fixed_setup, [pn]) 976 update_unlockedsigs(basepath, workspace, args.fixed_setup, [pn])
1033 977
@@ -1072,6 +1016,7 @@ def rename(args, config, basepath, workspace):
1072 origfnver = '' 1016 origfnver = ''
1073 1017
1074 recipefilemd5 = None 1018 recipefilemd5 = None
1019 newrecipefilemd5 = None
1075 tinfoil = setup_tinfoil(basepath=basepath, tracking=True) 1020 tinfoil = setup_tinfoil(basepath=basepath, tracking=True)
1076 try: 1021 try:
1077 rd = parse_recipe(config, tinfoil, args.recipename, True) 1022 rd = parse_recipe(config, tinfoil, args.recipename, True)
@@ -1149,6 +1094,7 @@ def rename(args, config, basepath, workspace):
1149 1094
1150 # Rename source tree if it's the default path 1095 # Rename source tree if it's the default path
1151 appendmd5 = None 1096 appendmd5 = None
1097 newappendmd5 = None
1152 if not args.no_srctree: 1098 if not args.no_srctree:
1153 srctree = workspace[args.recipename]['srctree'] 1099 srctree = workspace[args.recipename]['srctree']
1154 if os.path.abspath(srctree) == os.path.join(config.workspace_path, 'sources', args.recipename): 1100 if os.path.abspath(srctree) == os.path.join(config.workspace_path, 'sources', args.recipename):
@@ -1237,7 +1183,7 @@ def _get_patchset_revs(srctree, recipe_path, initial_rev=None, force_patch_refre
1237 """Get initial and update rev of a recipe. These are the start point of the 1183 """Get initial and update rev of a recipe. These are the start point of the
1238 whole patchset and start point for the patches to be re-generated/updated. 1184 whole patchset and start point for the patches to be re-generated/updated.
1239 """ 1185 """
1240 import bb 1186 import bb.process
1241 1187
1242 # Get current branch 1188 # Get current branch
1243 stdout, _ = bb.process.run('git rev-parse --abbrev-ref HEAD', 1189 stdout, _ = bb.process.run('git rev-parse --abbrev-ref HEAD',
@@ -1363,6 +1309,7 @@ def _export_patches(srctree, rd, start_revs, destdir, changed_revs=None):
1363 """ 1309 """
1364 import oe.recipeutils 1310 import oe.recipeutils
1365 from oe.patch import GitApplyTree 1311 from oe.patch import GitApplyTree
1312 import bb.process
1366 updated = OrderedDict() 1313 updated = OrderedDict()
1367 added = OrderedDict() 1314 added = OrderedDict()
1368 seqpatch_re = re.compile('^([0-9]{4}-)?(.+)') 1315 seqpatch_re = re.compile('^([0-9]{4}-)?(.+)')
@@ -1384,6 +1331,7 @@ def _export_patches(srctree, rd, start_revs, destdir, changed_revs=None):
1384 # values, but they ought to be anyway... 1331 # values, but they ought to be anyway...
1385 new_basename = seqpatch_re.match(new_patch).group(2) 1332 new_basename = seqpatch_re.match(new_patch).group(2)
1386 match_name = None 1333 match_name = None
1334 old_patch = None
1387 for old_patch in existing_patches: 1335 for old_patch in existing_patches:
1388 old_basename = seqpatch_re.match(old_patch).group(2) 1336 old_basename = seqpatch_re.match(old_patch).group(2)
1389 old_basename_splitext = os.path.splitext(old_basename) 1337 old_basename_splitext = os.path.splitext(old_basename)
@@ -1432,6 +1380,7 @@ def _export_patches(srctree, rd, start_revs, destdir, changed_revs=None):
1432 1380
1433def _create_kconfig_diff(srctree, rd, outfile): 1381def _create_kconfig_diff(srctree, rd, outfile):
1434 """Create a kconfig fragment""" 1382 """Create a kconfig fragment"""
1383 import bb.process
1435 # Only update config fragment if both config files exist 1384 # Only update config fragment if both config files exist
1436 orig_config = os.path.join(srctree, '.config.baseline') 1385 orig_config = os.path.join(srctree, '.config.baseline')
1437 new_config = os.path.join(srctree, '.config.new') 1386 new_config = os.path.join(srctree, '.config.new')
@@ -1469,12 +1418,15 @@ def _export_local_files(srctree, rd, destdir, srctreebase):
1469 - for removed dict, the absolute path to the existing file in recipe space 1418 - for removed dict, the absolute path to the existing file in recipe space
1470 """ 1419 """
1471 import oe.recipeutils 1420 import oe.recipeutils
1421 import bb.data
1422 import bb.process
1472 1423
1473 # Find out local files (SRC_URI files that exist in the "recipe space"). 1424 # Find out local files (SRC_URI files that exist in the "recipe space").
1474 # Local files that reside in srctree are not included in patch generation. 1425 # Local files that reside in srctree are not included in patch generation.
1475 # Instead they are directly copied over the original source files (in 1426 # Instead they are directly copied over the original source files (in
1476 # recipe space). 1427 # recipe space).
1477 existing_files = oe.recipeutils.get_recipe_local_files(rd) 1428 existing_files = oe.recipeutils.get_recipe_local_files(rd)
1429
1478 new_set = None 1430 new_set = None
1479 updated = OrderedDict() 1431 updated = OrderedDict()
1480 added = OrderedDict() 1432 added = OrderedDict()
@@ -1491,24 +1443,28 @@ def _export_local_files(srctree, rd, destdir, srctreebase):
1491 if branchname.startswith(override_branch_prefix): 1443 if branchname.startswith(override_branch_prefix):
1492 return (updated, added, removed) 1444 return (updated, added, removed)
1493 1445
1494 local_files_dir = os.path.join(srctreebase, 'oe-local-files') 1446 files = _git_modified(srctree)
1495 git_files = _git_ls_tree(srctree) 1447 #if not files:
1496 if 'oe-local-files' in git_files: 1448 # files = _ls_tree(srctree)
1497 # If tracked by Git, take the files from srctree HEAD. First get 1449 for f in files:
1498 # the tree object of the directory 1450 fullfile = os.path.join(srctree, f)
1499 tmp_index = os.path.join(srctree, '.git', 'index.tmp.devtool') 1451 if os.path.exists(os.path.join(fullfile, ".git")):
1500 tree = git_files['oe-local-files'][2] 1452 # submodules handled elsewhere
1501 bb.process.run(['git', 'checkout', tree, '--', '.'], cwd=srctree, 1453 continue
1502 env=dict(os.environ, GIT_WORK_TREE=destdir, 1454 if f not in existing_files:
1503 GIT_INDEX_FILE=tmp_index)) 1455 added[f] = {}
1504 new_set = list(_git_ls_tree(srctree, tree, True).keys()) 1456 if os.path.isdir(os.path.join(srctree, f)):
1505 elif os.path.isdir(local_files_dir): 1457 shutil.copytree(fullfile, os.path.join(destdir, f))
1506 # If not tracked by Git, just copy from working copy 1458 else:
1507 new_set = _ls_tree(local_files_dir) 1459 shutil.copy2(fullfile, os.path.join(destdir, f))
1508 bb.process.run(['cp', '-ax', 1460 elif not os.path.exists(fullfile):
1509 os.path.join(local_files_dir, '.'), destdir]) 1461 removed[f] = existing_files[f]
1510 else: 1462 elif f in existing_files:
1511 new_set = [] 1463 updated[f] = {'path' : existing_files[f]}
1464 if os.path.isdir(os.path.join(srctree, f)):
1465 shutil.copytree(fullfile, os.path.join(destdir, f))
1466 else:
1467 shutil.copy2(fullfile, os.path.join(destdir, f))
1512 1468
1513 # Special handling for kernel config 1469 # Special handling for kernel config
1514 if bb.data.inherits_class('kernel-yocto', rd): 1470 if bb.data.inherits_class('kernel-yocto', rd):
@@ -1516,17 +1472,14 @@ def _export_local_files(srctree, rd, destdir, srctreebase):
1516 fragment_path = os.path.join(destdir, fragment_fn) 1472 fragment_path = os.path.join(destdir, fragment_fn)
1517 if _create_kconfig_diff(srctree, rd, fragment_path): 1473 if _create_kconfig_diff(srctree, rd, fragment_path):
1518 if os.path.exists(fragment_path): 1474 if os.path.exists(fragment_path):
1519 if fragment_fn not in new_set: 1475 if fragment_fn in removed:
1520 new_set.append(fragment_fn) 1476 del removed[fragment_fn]
1521 # Copy fragment to local-files 1477 if fragment_fn not in updated and fragment_fn not in added:
1522 if os.path.isdir(local_files_dir): 1478 added[fragment_fn] = {}
1523 shutil.copy2(fragment_path, local_files_dir)
1524 else: 1479 else:
1525 if fragment_fn in new_set: 1480 if fragment_fn in updated:
1526 new_set.remove(fragment_fn) 1481 removed[fragment_fn] = updated[fragment_fn]
1527 # Remove fragment from local-files 1482 del updated[fragment_fn]
1528 if os.path.exists(os.path.join(local_files_dir, fragment_fn)):
1529 os.unlink(os.path.join(local_files_dir, fragment_fn))
1530 1483
1531 # Special handling for cml1, ccmake, etc bbclasses that generated 1484 # Special handling for cml1, ccmake, etc bbclasses that generated
1532 # configuration fragment files that are consumed as source files 1485 # configuration fragment files that are consumed as source files
@@ -1534,42 +1487,13 @@ def _export_local_files(srctree, rd, destdir, srctreebase):
1534 if bb.data.inherits_class(frag_class, rd): 1487 if bb.data.inherits_class(frag_class, rd):
1535 srcpath = os.path.join(rd.getVar('WORKDIR'), frag_name) 1488 srcpath = os.path.join(rd.getVar('WORKDIR'), frag_name)
1536 if os.path.exists(srcpath): 1489 if os.path.exists(srcpath):
1537 if frag_name not in new_set: 1490 if frag_name in removed:
1538 new_set.append(frag_name) 1491 del removed[frag_name]
1492 if frag_name not in updated:
1493 added[frag_name] = {}
1539 # copy fragment into destdir 1494 # copy fragment into destdir
1540 shutil.copy2(srcpath, destdir) 1495 shutil.copy2(srcpath, destdir)
1541 # copy fragment into local files if exists 1496
1542 if os.path.isdir(local_files_dir):
1543 shutil.copy2(srcpath, local_files_dir)
1544
1545 if new_set is not None:
1546 for fname in new_set:
1547 if fname in existing_files:
1548 origpath = existing_files.pop(fname)
1549 workpath = os.path.join(local_files_dir, fname)
1550 if not filecmp.cmp(origpath, workpath):
1551 updated[fname] = {'path' : origpath}
1552 elif fname != '.gitignore':
1553 added[fname] = {}
1554
1555 workdir = rd.getVar('WORKDIR')
1556 s = rd.getVar('S')
1557 if not s.endswith(os.sep):
1558 s += os.sep
1559
1560 if workdir != s:
1561 # Handle files where subdir= was specified
1562 for fname in list(existing_files.keys()):
1563 # FIXME handle both subdir starting with BP and not?
1564 fworkpath = os.path.join(workdir, fname)
1565 if fworkpath.startswith(s):
1566 fpath = os.path.join(srctree, os.path.relpath(fworkpath, s))
1567 if os.path.exists(fpath):
1568 origpath = existing_files.pop(fname)
1569 if not filecmp.cmp(origpath, fpath):
1570 updated[fpath] = {'path' : origpath}
1571
1572 removed = existing_files
1573 return (updated, added, removed) 1497 return (updated, added, removed)
1574 1498
1575 1499
@@ -1587,7 +1511,7 @@ def _determine_files_dir(rd):
1587 1511
1588def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, dry_run_outdir=None): 1512def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, dry_run_outdir=None):
1589 """Implement the 'srcrev' mode of update-recipe""" 1513 """Implement the 'srcrev' mode of update-recipe"""
1590 import bb 1514 import bb.process
1591 import oe.recipeutils 1515 import oe.recipeutils
1592 1516
1593 dry_run_suffix = ' (dry-run)' if dry_run_outdir else '' 1517 dry_run_suffix = ' (dry-run)' if dry_run_outdir else ''
@@ -1625,6 +1549,7 @@ def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wi
1625 local_files_dir = tempfile.mkdtemp(dir=tempdir) 1549 local_files_dir = tempfile.mkdtemp(dir=tempdir)
1626 srctreebase = workspace[recipename]['srctreebase'] 1550 srctreebase = workspace[recipename]['srctreebase']
1627 upd_f, new_f, del_f = _export_local_files(srctree, rd, local_files_dir, srctreebase) 1551 upd_f, new_f, del_f = _export_local_files(srctree, rd, local_files_dir, srctreebase)
1552 removedentries = {}
1628 if not no_remove: 1553 if not no_remove:
1629 # Find list of existing patches in recipe file 1554 # Find list of existing patches in recipe file
1630 patches_dir = tempfile.mkdtemp(dir=tempdir) 1555 patches_dir = tempfile.mkdtemp(dir=tempdir)
@@ -1688,7 +1613,6 @@ def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wi
1688 1613
1689def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev, dry_run_outdir=None, force_patch_refresh=False): 1614def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev, dry_run_outdir=None, force_patch_refresh=False):
1690 """Implement the 'patch' mode of update-recipe""" 1615 """Implement the 'patch' mode of update-recipe"""
1691 import bb
1692 import oe.recipeutils 1616 import oe.recipeutils
1693 1617
1694 recipefile = rd.getVar('FILE') 1618 recipefile = rd.getVar('FILE')
@@ -1802,6 +1726,7 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil
1802 for basepath, param in upd_p.items(): 1726 for basepath, param in upd_p.items():
1803 path = param['path'] 1727 path = param['path']
1804 patchdir = param.get('patchdir', ".") 1728 patchdir = param.get('patchdir', ".")
1729 patchdir_param = {}
1805 if patchdir != "." : 1730 if patchdir != "." :
1806 patchdir_param = dict(patchdir_params) 1731 patchdir_param = dict(patchdir_params)
1807 if patchdir_param: 1732 if patchdir_param:
@@ -1867,6 +1792,7 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil
1867 1792
1868def _guess_recipe_update_mode(srctree, rdata): 1793def _guess_recipe_update_mode(srctree, rdata):
1869 """Guess the recipe update mode to use""" 1794 """Guess the recipe update mode to use"""
1795 import bb.process
1870 src_uri = (rdata.getVar('SRC_URI') or '').split() 1796 src_uri = (rdata.getVar('SRC_URI') or '').split()
1871 git_uris = [uri for uri in src_uri if uri.startswith('git://')] 1797 git_uris = [uri for uri in src_uri if uri.startswith('git://')]
1872 if not git_uris: 1798 if not git_uris:
@@ -1888,6 +1814,8 @@ def _guess_recipe_update_mode(srctree, rdata):
1888 return 'patch' 1814 return 'patch'
1889 1815
1890def _update_recipe(recipename, workspace, rd, mode, appendlayerdir, wildcard_version, no_remove, initial_rev, no_report_remove=False, dry_run_outdir=None, no_overrides=False, force_patch_refresh=False): 1816def _update_recipe(recipename, workspace, rd, mode, appendlayerdir, wildcard_version, no_remove, initial_rev, no_report_remove=False, dry_run_outdir=None, no_overrides=False, force_patch_refresh=False):
1817 import bb.data
1818 import bb.process
1891 srctree = workspace[recipename]['srctree'] 1819 srctree = workspace[recipename]['srctree']
1892 if mode == 'auto': 1820 if mode == 'auto':
1893 mode = _guess_recipe_update_mode(srctree, rd) 1821 mode = _guess_recipe_update_mode(srctree, rd)
@@ -2010,6 +1938,7 @@ def status(args, config, basepath, workspace):
2010 1938
2011def _reset(recipes, no_clean, remove_work, config, basepath, workspace): 1939def _reset(recipes, no_clean, remove_work, config, basepath, workspace):
2012 """Reset one or more recipes""" 1940 """Reset one or more recipes"""
1941 import bb.process
2013 import oe.path 1942 import oe.path
2014 1943
2015 def clean_preferred_provider(pn, layerconf_path): 1944 def clean_preferred_provider(pn, layerconf_path):
@@ -2022,7 +1951,7 @@ def _reset(recipes, no_clean, remove_work, config, basepath, workspace):
2022 lines = f.readlines() 1951 lines = f.readlines()
2023 with open(new_layerconf_file, 'a') as nf: 1952 with open(new_layerconf_file, 'a') as nf:
2024 for line in lines: 1953 for line in lines:
2025 pprovider_exp = r'^PREFERRED_PROVIDER_.*? = "' + pn + r'"$' 1954 pprovider_exp = r'^PREFERRED_PROVIDER_.*? = "' + re.escape(pn) + r'"$'
2026 if not re.match(pprovider_exp, line): 1955 if not re.match(pprovider_exp, line):
2027 nf.write(line) 1956 nf.write(line)
2028 else: 1957 else:
@@ -2113,8 +2042,6 @@ def _reset(recipes, no_clean, remove_work, config, basepath, workspace):
2113 2042
2114def reset(args, config, basepath, workspace): 2043def reset(args, config, basepath, workspace):
2115 """Entry point for the devtool 'reset' subcommand""" 2044 """Entry point for the devtool 'reset' subcommand"""
2116 import bb
2117 import shutil
2118 2045
2119 recipes = "" 2046 recipes = ""
2120 2047
@@ -2393,6 +2320,7 @@ def register_commands(subparsers, context):
2393 parser_modify.add_argument('--branch', '-b', default="devtool", help='Name for development branch to checkout (when not using -n/--no-extract) (default "%(default)s")') 2320 parser_modify.add_argument('--branch', '-b', default="devtool", help='Name for development branch to checkout (when not using -n/--no-extract) (default "%(default)s")')
2394 parser_modify.add_argument('--no-overrides', '-O', action="store_true", help='Do not create branches for other override configurations') 2321 parser_modify.add_argument('--no-overrides', '-O', action="store_true", help='Do not create branches for other override configurations')
2395 parser_modify.add_argument('--keep-temp', help='Keep temporary directory (for debugging)', action="store_true") 2322 parser_modify.add_argument('--keep-temp', help='Keep temporary directory (for debugging)', action="store_true")
2323 parser_modify.add_argument('--debug-build', action="store_true", help='Add DEBUG_BUILD = "1" to the modified recipe')
2396 parser_modify.set_defaults(func=modify, fixed_setup=context.fixed_setup) 2324 parser_modify.set_defaults(func=modify, fixed_setup=context.fixed_setup)
2397 2325
2398 parser_extract = subparsers.add_parser('extract', help='Extract the source for an existing recipe', 2326 parser_extract = subparsers.add_parser('extract', help='Extract the source for an existing recipe',