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