xref: /OK3568_Linux_fs/yocto/poky/meta/classes/patch.bbclass (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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