devtool-source.bbclass 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #
  2. # Copyright OpenEmbedded Contributors
  3. #
  4. # SPDX-License-Identifier: MIT
  5. #
  6. # Development tool - source extraction helper class
  7. #
  8. # NOTE: this class is intended for use by devtool and should not be
  9. # inherited manually.
  10. #
  11. # Copyright (C) 2014-2017 Intel Corporation
  12. #
  13. # This program is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License version 2 as
  15. # published by the Free Software Foundation.
  16. #
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License along
  23. # with this program; if not, write to the Free Software Foundation, Inc.,
  24. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  25. DEVTOOL_TEMPDIR ?= ""
  26. python() {
  27. tempdir = d.getVar('DEVTOOL_TEMPDIR')
  28. if not tempdir:
  29. bb.fatal('devtool-source class is for internal use by devtool only')
  30. # Make a subdir so we guard against WORKDIR==S
  31. workdir = os.path.join(tempdir, 'workdir')
  32. d.setVar('WORKDIR', workdir)
  33. if not d.getVar('S').startswith(workdir):
  34. # Usually a shared workdir recipe (kernel, gcc)
  35. # Try to set a reasonable default
  36. if bb.data.inherits_class('kernel', d):
  37. d.setVar('S', '${WORKDIR}/source')
  38. else:
  39. d.setVar('S', '${WORKDIR}/%s' % os.path.basename(d.getVar('S')))
  40. if bb.data.inherits_class('kernel', d):
  41. # We don't want to move the source to STAGING_KERNEL_DIR here
  42. d.setVar('STAGING_KERNEL_DIR', '${S}')
  43. d.setVar('STAMPS_DIR', os.path.join(tempdir, 'stamps'))
  44. d.setVar('T', os.path.join(tempdir, 'temp'))
  45. # Hook in pre/postfuncs
  46. is_kernel_yocto = bb.data.inherits_class('kernel-yocto', d)
  47. if is_kernel_yocto:
  48. unpacktask = 'do_kernel_checkout'
  49. d.appendVarFlag('do_configure', 'postfuncs', ' devtool_post_configure')
  50. else:
  51. unpacktask = 'do_unpack'
  52. d.appendVarFlag(unpacktask, 'postfuncs', ' devtool_post_unpack')
  53. d.appendVarFlag('do_patch', 'postfuncs', ' devtool_post_patch')
  54. # NOTE: in order for the patch stuff to be fully functional,
  55. # PATCHTOOL and PATCH_COMMIT_FUNCTIONS need to be set; we can't
  56. # do that here because we can't guarantee the order of the anonymous
  57. # functions, so it gets done in the bbappend we create.
  58. }
  59. python devtool_post_unpack() {
  60. import oe.recipeutils
  61. import shutil
  62. sys.path.insert(0, os.path.join(d.getVar('COREBASE'), 'scripts', 'lib'))
  63. import scriptutils
  64. from devtool import setup_git_repo
  65. tempdir = d.getVar('DEVTOOL_TEMPDIR')
  66. workdir = d.getVar('WORKDIR')
  67. unpackdir = d.getVar('UNPACKDIR')
  68. srcsubdir = d.getVar('S')
  69. # Add locally copied files to gitignore as we add back to the metadata directly
  70. local_files = oe.recipeutils.get_recipe_local_files(d)
  71. srcabspath = os.path.abspath(srcsubdir)
  72. local_files = [fname for fname in local_files if
  73. os.path.exists(os.path.join(unpackdir, fname)) and
  74. srcabspath == unpackdir]
  75. if local_files:
  76. with open(os.path.join(tempdir, '.gitignore'), 'a+') as f:
  77. f.write('# Ignore local files, by default. Remove following lines'
  78. 'if you want to commit the directory to Git\n')
  79. for fname in local_files:
  80. f.write('%s\n' % fname)
  81. if os.path.dirname(srcsubdir) != workdir:
  82. # Handle if S is set to a subdirectory of the source
  83. srcsubdir = os.path.join(workdir, os.path.relpath(srcsubdir, workdir).split(os.sep)[0])
  84. scriptutils.git_convert_standalone_clone(srcsubdir)
  85. # Make sure that srcsubdir exists
  86. bb.utils.mkdirhier(srcsubdir)
  87. if not os.listdir(srcsubdir):
  88. bb.warn("No source unpacked to S - either the %s recipe "
  89. "doesn't use any source or the correct source "
  90. "directory could not be determined" % d.getVar('PN'))
  91. devbranch = d.getVar('DEVTOOL_DEVBRANCH')
  92. setup_git_repo(srcsubdir, d.getVar('PV'), devbranch, d=d)
  93. (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srcsubdir)
  94. initial_rev = stdout.rstrip()
  95. with open(os.path.join(tempdir, 'initial_rev'), 'w') as f:
  96. f.write(initial_rev)
  97. with open(os.path.join(tempdir, 'srcsubdir'), 'w') as f:
  98. f.write(srcsubdir)
  99. }
  100. python devtool_post_patch() {
  101. import shutil
  102. tempdir = d.getVar('DEVTOOL_TEMPDIR')
  103. with open(os.path.join(tempdir, 'srcsubdir'), 'r') as f:
  104. srcsubdir = f.read()
  105. with open(os.path.join(tempdir, 'initial_rev'), 'r') as f:
  106. initial_rev = f.read()
  107. def rm_patches():
  108. patches_dir = os.path.join(srcsubdir, 'patches')
  109. if os.path.exists(patches_dir):
  110. shutil.rmtree(patches_dir)
  111. # Restore any "patches" directory that was actually part of the source tree
  112. try:
  113. bb.process.run('git checkout -- patches', cwd=srcsubdir)
  114. except bb.process.ExecutionError:
  115. pass
  116. extra_overrides = d.getVar('DEVTOOL_EXTRA_OVERRIDES')
  117. if extra_overrides:
  118. extra_overrides = set(extra_overrides.split(':'))
  119. devbranch = d.getVar('DEVTOOL_DEVBRANCH')
  120. default_overrides = d.getVar('OVERRIDES').split(':')
  121. no_overrides = []
  122. # First, we may have some overrides that are referred to in the recipe set in
  123. # our configuration, so we need to make a branch that excludes those
  124. for override in default_overrides:
  125. if override not in extra_overrides:
  126. no_overrides.append(override)
  127. if default_overrides != no_overrides:
  128. # Some overrides are active in the current configuration, so
  129. # we need to create a branch where none of the overrides are active
  130. bb.process.run('git checkout %s -b devtool-no-overrides' % initial_rev, cwd=srcsubdir)
  131. # Run do_patch function with the override applied
  132. localdata = bb.data.createCopy(d)
  133. localdata.setVar('OVERRIDES', ':'.join(no_overrides))
  134. localdata.setVar('FILESOVERRIDES', ':'.join(no_overrides))
  135. bb.build.exec_func('do_patch', localdata)
  136. rm_patches()
  137. # Now we need to reconcile the dev branch with the no-overrides one
  138. # (otherwise we'd likely be left with identical commits that have different hashes)
  139. bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir)
  140. bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir)
  141. else:
  142. bb.process.run('git checkout %s -b devtool-no-overrides' % devbranch, cwd=srcsubdir)
  143. for override in extra_overrides:
  144. localdata = bb.data.createCopy(d)
  145. if override in default_overrides:
  146. bb.process.run('git branch devtool-override-%s %s' % (override, devbranch), cwd=srcsubdir)
  147. else:
  148. # Reset back to the initial commit on a new branch
  149. bb.process.run('git checkout %s -b devtool-override-%s' % (initial_rev, override), cwd=srcsubdir)
  150. # Run do_patch function with the override applied
  151. localdata.setVar('OVERRIDES', ':'.join(no_overrides + [override]))
  152. localdata.setVar('FILESOVERRIDES', ':'.join(no_overrides + [override]))
  153. bb.build.exec_func('do_patch', localdata)
  154. rm_patches()
  155. # Now we need to reconcile the new branch with the no-overrides one
  156. # (otherwise we'd likely be left with identical commits that have different hashes)
  157. bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir)
  158. bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir)
  159. bb.process.run('git tag -f --no-sign devtool-patched', cwd=srcsubdir)
  160. if os.path.exists(os.path.join(srcsubdir, '.gitmodules')):
  161. bb.process.run('git submodule foreach --recursive "git tag -f --no-sign devtool-patched"', cwd=srcsubdir)
  162. }
  163. python devtool_post_configure() {
  164. import shutil
  165. tempdir = d.getVar('DEVTOOL_TEMPDIR')
  166. shutil.copy2(os.path.join(d.getVar('B'), '.config'), tempdir)
  167. }