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