patch.bbclass 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # Copyright (C) 2006 OpenedHand LTD
  2. #
  3. # SPDX-License-Identifier: MIT
  4. # Point to an empty file so any user's custom settings don't break things
  5. QUILTRCFILE ?= "${STAGING_ETCDIR_NATIVE}/quiltrc"
  6. PATCHDEPENDENCY = "${PATCHTOOL}-native:do_populate_sysroot"
  7. # There is a bug in patch 2.7.3 and earlier where index lines
  8. # in patches can change file modes when they shouldn't:
  9. # http://git.savannah.gnu.org/cgit/patch.git/patch/?id=82b800c9552a088a241457948219d25ce0a407a4
  10. # This leaks into debug sources in particular. Add the dependency
  11. # to target recipes to avoid this problem until we can rely on 2.7.4 or later.
  12. PATCHDEPENDENCY:append:class-target = " patch-replacement-native:do_populate_sysroot"
  13. PATCH_GIT_USER_NAME ?= "OpenEmbedded"
  14. PATCH_GIT_USER_EMAIL ?= "oe.patch@oe"
  15. inherit terminal
  16. python () {
  17. if d.getVar('PATCHTOOL') == 'git' and d.getVar('PATCH_COMMIT_FUNCTIONS') == '1':
  18. extratasks = bb.build.tasksbetween('do_unpack', 'do_patch', d)
  19. try:
  20. extratasks.remove('do_unpack')
  21. except ValueError:
  22. # For some recipes do_unpack doesn't exist, ignore it
  23. pass
  24. d.appendVarFlag('do_patch', 'prefuncs', ' patch_task_patch_prefunc')
  25. for task in extratasks:
  26. d.appendVarFlag(task, 'postfuncs', ' patch_task_postfunc')
  27. }
  28. python patch_task_patch_prefunc() {
  29. # Prefunc for do_patch
  30. srcsubdir = d.getVar('S')
  31. workdir = os.path.abspath(d.getVar('WORKDIR'))
  32. testsrcdir = os.path.abspath(srcsubdir)
  33. if (testsrcdir + os.sep).startswith(workdir + os.sep):
  34. # Double-check that either workdir or S or some directory in-between is a git repository
  35. found = False
  36. while testsrcdir != workdir:
  37. if os.path.exists(os.path.join(testsrcdir, '.git')):
  38. found = True
  39. break
  40. if testsrcdir == workdir:
  41. break
  42. testsrcdir = os.path.dirname(testsrcdir)
  43. if not found:
  44. bb.fatal('PATCHTOOL = "git" set for source tree that is not a git repository. Refusing to continue as that may result in commits being made in your metadata repository.')
  45. patchdir = os.path.join(srcsubdir, 'patches')
  46. if os.path.exists(patchdir):
  47. if os.listdir(patchdir):
  48. d.setVar('PATCH_HAS_PATCHES_DIR', '1')
  49. else:
  50. os.rmdir(patchdir)
  51. }
  52. python patch_task_postfunc() {
  53. # Prefunc for task functions between do_unpack and do_patch
  54. import oe.patch
  55. import shutil
  56. func = d.getVar('BB_RUNTASK')
  57. srcsubdir = d.getVar('S')
  58. if os.path.exists(srcsubdir):
  59. if func == 'do_patch':
  60. haspatches = (d.getVar('PATCH_HAS_PATCHES_DIR') == '1')
  61. patchdir = os.path.join(srcsubdir, 'patches')
  62. if os.path.exists(patchdir):
  63. shutil.rmtree(patchdir)
  64. if haspatches:
  65. stdout, _ = bb.process.run('git status --porcelain patches', cwd=srcsubdir)
  66. if stdout:
  67. bb.process.run('git checkout patches', cwd=srcsubdir)
  68. stdout, _ = bb.process.run('git status --porcelain .', cwd=srcsubdir)
  69. if stdout:
  70. useroptions = []
  71. oe.patch.GitApplyTree.gitCommandUserOptions(useroptions, d=d)
  72. bb.process.run('git add .; git %s commit -a -m "Committing changes from %s\n\n%s"' % (' '.join(useroptions), func, oe.patch.GitApplyTree.ignore_commit_prefix + ' - from %s' % func), cwd=srcsubdir)
  73. }
  74. def src_patches(d, all=False, expand=True):
  75. import oe.patch
  76. return oe.patch.src_patches(d, all, expand)
  77. def should_apply(parm, d):
  78. """Determine if we should apply the given patch"""
  79. import oe.patch
  80. return oe.patch.should_apply(parm, d)
  81. should_apply[vardepsexclude] = "DATE SRCDATE"
  82. python patch_do_patch() {
  83. import oe.patch
  84. patchsetmap = {
  85. "patch": oe.patch.PatchTree,
  86. "quilt": oe.patch.QuiltTree,
  87. "git": oe.patch.GitApplyTree,
  88. }
  89. cls = patchsetmap[d.getVar('PATCHTOOL') or 'quilt']
  90. resolvermap = {
  91. "noop": oe.patch.NOOPResolver,
  92. "user": oe.patch.UserResolver,
  93. }
  94. rcls = resolvermap[d.getVar('PATCHRESOLVE') or 'user']
  95. classes = {}
  96. s = d.getVar('S')
  97. os.putenv('PATH', d.getVar('PATH'))
  98. # We must use one TMPDIR per process so that the "patch" processes
  99. # don't generate the same temp file name.
  100. import tempfile
  101. process_tmpdir = tempfile.mkdtemp()
  102. os.environ['TMPDIR'] = process_tmpdir
  103. for patch in src_patches(d):
  104. _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
  105. if "patchdir" in parm:
  106. patchdir = parm["patchdir"]
  107. if not os.path.isabs(patchdir):
  108. patchdir = os.path.join(s, patchdir)
  109. if not os.path.isdir(patchdir):
  110. bb.fatal("Target directory '%s' not found, patchdir '%s' is incorrect in patch file '%s'" %
  111. (patchdir, parm["patchdir"], parm['patchname']))
  112. else:
  113. patchdir = s
  114. if not patchdir in classes:
  115. patchset = cls(patchdir, d)
  116. resolver = rcls(patchset, oe_terminal)
  117. classes[patchdir] = (patchset, resolver)
  118. patchset.Clean()
  119. else:
  120. patchset, resolver = classes[patchdir]
  121. bb.note("Applying patch '%s' (%s)" % (parm['patchname'], oe.path.format_display(local, d)))
  122. try:
  123. patchset.Import({"file":local, "strippath": parm['striplevel']}, True)
  124. except Exception as exc:
  125. bb.utils.remove(process_tmpdir, True)
  126. bb.fatal("Importing patch '%s' with striplevel '%s'\n%s" % (parm['patchname'], parm['striplevel'], repr(exc).replace("\\n", "\n")))
  127. try:
  128. resolver.Resolve()
  129. except bb.BBHandledException as e:
  130. bb.utils.remove(process_tmpdir, True)
  131. bb.fatal("Applying patch '%s' on target directory '%s'\n%s" % (parm['patchname'], patchdir, repr(e).replace("\\n", "\n")))
  132. bb.utils.remove(process_tmpdir, True)
  133. del os.environ['TMPDIR']
  134. }
  135. patch_do_patch[vardepsexclude] = "PATCHRESOLVE"
  136. addtask patch after do_unpack
  137. do_patch[dirs] = "${WORKDIR}"
  138. do_patch[depends] = "${PATCHDEPENDENCY}"
  139. EXPORT_FUNCTIONS do_patch