patch.bbclass 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. oe.patch.GitApplyTree.commitIgnored("Add changes from %s" % func, dir=srcsubdir, files=['.'], d=d)
  71. }
  72. def src_patches(d, all=False, expand=True):
  73. import oe.patch
  74. return oe.patch.src_patches(d, all, expand)
  75. def should_apply(parm, d):
  76. """Determine if we should apply the given patch"""
  77. import oe.patch
  78. return oe.patch.should_apply(parm, d)
  79. should_apply[vardepsexclude] = "DATE SRCDATE"
  80. python patch_do_patch() {
  81. import oe.patch
  82. patchsetmap = {
  83. "patch": oe.patch.PatchTree,
  84. "quilt": oe.patch.QuiltTree,
  85. "git": oe.patch.GitApplyTree,
  86. }
  87. cls = patchsetmap[d.getVar('PATCHTOOL') or 'quilt']
  88. resolvermap = {
  89. "noop": oe.patch.NOOPResolver,
  90. "user": oe.patch.UserResolver,
  91. }
  92. rcls = resolvermap[d.getVar('PATCHRESOLVE') or 'user']
  93. classes = {}
  94. s = d.getVar('S')
  95. os.putenv('PATH', d.getVar('PATH'))
  96. # We must use one TMPDIR per process so that the "patch" processes
  97. # don't generate the same temp file name.
  98. import tempfile
  99. process_tmpdir = tempfile.mkdtemp()
  100. os.environ['TMPDIR'] = process_tmpdir
  101. for patch in src_patches(d):
  102. _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
  103. if "patchdir" in parm:
  104. patchdir = parm["patchdir"]
  105. if not os.path.isabs(patchdir):
  106. patchdir = os.path.join(s, patchdir)
  107. if not os.path.isdir(patchdir):
  108. bb.fatal("Target directory '%s' not found, patchdir '%s' is incorrect in patch file '%s'" %
  109. (patchdir, parm["patchdir"], parm['patchname']))
  110. else:
  111. patchdir = s
  112. if not patchdir in classes:
  113. patchset = cls(patchdir, d)
  114. resolver = rcls(patchset, oe_terminal)
  115. classes[patchdir] = (patchset, resolver)
  116. patchset.Clean()
  117. else:
  118. patchset, resolver = classes[patchdir]
  119. bb.note("Applying patch '%s' (%s)" % (parm['patchname'], oe.path.format_display(local, d)))
  120. try:
  121. patchset.Import({"file":local, "strippath": parm['striplevel']}, True)
  122. except Exception as exc:
  123. bb.utils.remove(process_tmpdir, True)
  124. bb.fatal("Importing patch '%s' with striplevel '%s'\n%s" % (parm['patchname'], parm['striplevel'], repr(exc).replace("\\n", "\n")))
  125. try:
  126. resolver.Resolve()
  127. except bb.BBHandledException as e:
  128. bb.utils.remove(process_tmpdir, True)
  129. bb.fatal("Applying patch '%s' on target directory '%s'\n%s" % (parm['patchname'], patchdir, repr(e).replace("\\n", "\n")))
  130. bb.utils.remove(process_tmpdir, True)
  131. del os.environ['TMPDIR']
  132. }
  133. patch_do_patch[vardepsexclude] = "PATCHRESOLVE"
  134. addtask patch after do_unpack
  135. do_patch[dirs] = "${WORKDIR}"
  136. do_patch[depends] = "${PATCHDEPENDENCY}"
  137. EXPORT_FUNCTIONS do_patch