blob: 4158c20c7e830f4f0652255e6a5cac4e33900494 [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
Brad Bishopd7bf8c12018-02-25 22:55:05 -05007# Development tool - source extraction helper class
8#
9# NOTE: this class is intended for use by devtool and should not be
10# inherited manually.
11#
12# Copyright (C) 2014-2017 Intel Corporation
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License version 2 as
16# published by the Free Software Foundation.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License along
24# with this program; if not, write to the Free Software Foundation, Inc.,
25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26
27
28DEVTOOL_TEMPDIR ?= ""
29DEVTOOL_PATCH_SRCDIR = "${DEVTOOL_TEMPDIR}/patchworkdir"
30
31
32python() {
33 tempdir = d.getVar('DEVTOOL_TEMPDIR')
34
35 if not tempdir:
36 bb.fatal('devtool-source class is for internal use by devtool only')
37
38 # Make a subdir so we guard against WORKDIR==S
39 workdir = os.path.join(tempdir, 'workdir')
40 d.setVar('WORKDIR', workdir)
41 if not d.getVar('S').startswith(workdir):
42 # Usually a shared workdir recipe (kernel, gcc)
43 # Try to set a reasonable default
44 if bb.data.inherits_class('kernel', d):
45 d.setVar('S', '${WORKDIR}/source')
46 else:
47 d.setVar('S', '${WORKDIR}/%s' % os.path.basename(d.getVar('S')))
48 if bb.data.inherits_class('kernel', d):
49 # We don't want to move the source to STAGING_KERNEL_DIR here
50 d.setVar('STAGING_KERNEL_DIR', '${S}')
51
52 d.setVar('STAMPS_DIR', os.path.join(tempdir, 'stamps'))
53 d.setVar('T', os.path.join(tempdir, 'temp'))
54
55 # Hook in pre/postfuncs
56 is_kernel_yocto = bb.data.inherits_class('kernel-yocto', d)
57 if is_kernel_yocto:
58 unpacktask = 'do_kernel_checkout'
59 d.appendVarFlag('do_configure', 'postfuncs', ' devtool_post_configure')
60 else:
61 unpacktask = 'do_unpack'
62 d.appendVarFlag(unpacktask, 'postfuncs', ' devtool_post_unpack')
63 d.prependVarFlag('do_patch', 'prefuncs', ' devtool_pre_patch')
64 d.appendVarFlag('do_patch', 'postfuncs', ' devtool_post_patch')
65
66 # NOTE: in order for the patch stuff to be fully functional,
67 # PATCHTOOL and PATCH_COMMIT_FUNCTIONS need to be set; we can't
68 # do that here because we can't guarantee the order of the anonymous
69 # functions, so it gets done in the bbappend we create.
70}
71
72
73python devtool_post_unpack() {
74 import oe.recipeutils
75 import shutil
76 sys.path.insert(0, os.path.join(d.getVar('COREBASE'), 'scripts', 'lib'))
77 import scriptutils
78 from devtool import setup_git_repo
79
80 tempdir = d.getVar('DEVTOOL_TEMPDIR')
81 workdir = d.getVar('WORKDIR')
82 srcsubdir = d.getVar('S')
83
84 def _move_file(src, dst):
85 """Move a file. Creates all the directory components of destination path."""
86 dst_d = os.path.dirname(dst)
87 if dst_d:
88 bb.utils.mkdirhier(dst_d)
89 shutil.move(src, dst)
90
91 def _ls_tree(directory):
92 """Recursive listing of files in a directory"""
93 ret = []
94 for root, dirs, files in os.walk(directory):
95 ret.extend([os.path.relpath(os.path.join(root, fname), directory) for
96 fname in files])
97 return ret
98
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080099 is_kernel_yocto = bb.data.inherits_class('kernel-yocto', d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500100 # Move local source files into separate subdir
101 recipe_patches = [os.path.basename(patch) for patch in
102 oe.recipeutils.get_recipe_patches(d)]
103 local_files = oe.recipeutils.get_recipe_local_files(d)
104
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800105 if is_kernel_yocto:
Brad Bishop64c979e2019-11-04 13:55:29 -0500106 for key in [f for f in local_files if f.endswith('scc')]:
107 with open(local_files[key], 'r') as sccfile:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800108 for l in sccfile:
109 line = l.split()
110 if line and line[0] in ('kconf', 'patch'):
Brad Bishop19323692019-04-05 15:28:33 -0400111 cfg = os.path.join(os.path.dirname(local_files[key]), line[-1])
Brad Bishop64c979e2019-11-04 13:55:29 -0500112 if cfg not in local_files.values():
Brad Bishop19323692019-04-05 15:28:33 -0400113 local_files[line[-1]] = cfg
114 shutil.copy2(cfg, workdir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800115
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500116 # Ignore local files with subdir={BP}
117 srcabspath = os.path.abspath(srcsubdir)
118 local_files = [fname for fname in local_files if
119 os.path.exists(os.path.join(workdir, fname)) and
120 (srcabspath == workdir or not
121 os.path.join(workdir, fname).startswith(srcabspath +
122 os.sep))]
123 if local_files:
124 for fname in local_files:
125 _move_file(os.path.join(workdir, fname),
126 os.path.join(tempdir, 'oe-local-files', fname))
127 with open(os.path.join(tempdir, 'oe-local-files', '.gitignore'),
128 'w') as f:
129 f.write('# Ignore local files, by default. Remove this file '
130 'if you want to commit the directory to Git\n*\n')
131
132 if srcsubdir == workdir:
133 # Find non-patch non-local sources that were "unpacked" to srctree
134 # directory
135 src_files = [fname for fname in _ls_tree(workdir) if
136 os.path.basename(fname) not in recipe_patches]
137 srcsubdir = d.getVar('DEVTOOL_PATCH_SRCDIR')
138 # Move source files to S
139 for path in src_files:
140 _move_file(os.path.join(workdir, path),
141 os.path.join(srcsubdir, path))
142 elif os.path.dirname(srcsubdir) != workdir:
143 # Handle if S is set to a subdirectory of the source
144 srcsubdir = os.path.join(workdir, os.path.relpath(srcsubdir, workdir).split(os.sep)[0])
145
146 scriptutils.git_convert_standalone_clone(srcsubdir)
147
148 # Make sure that srcsubdir exists
149 bb.utils.mkdirhier(srcsubdir)
150 if not os.listdir(srcsubdir):
151 bb.warn("No source unpacked to S - either the %s recipe "
152 "doesn't use any source or the correct source "
153 "directory could not be determined" % d.getVar('PN'))
154
155 devbranch = d.getVar('DEVTOOL_DEVBRANCH')
156 setup_git_repo(srcsubdir, d.getVar('PV'), devbranch, d=d)
157
158 (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srcsubdir)
159 initial_rev = stdout.rstrip()
160 with open(os.path.join(tempdir, 'initial_rev'), 'w') as f:
161 f.write(initial_rev)
162
163 with open(os.path.join(tempdir, 'srcsubdir'), 'w') as f:
164 f.write(srcsubdir)
165}
166
167python devtool_pre_patch() {
168 if d.getVar('S') == d.getVar('WORKDIR'):
169 d.setVar('S', '${DEVTOOL_PATCH_SRCDIR}')
170}
171
172python devtool_post_patch() {
Brad Bishop316dfdd2018-06-25 12:45:53 -0400173 import shutil
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500174 tempdir = d.getVar('DEVTOOL_TEMPDIR')
175 with open(os.path.join(tempdir, 'srcsubdir'), 'r') as f:
176 srcsubdir = f.read()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400177 with open(os.path.join(tempdir, 'initial_rev'), 'r') as f:
178 initial_rev = f.read()
179
180 def rm_patches():
181 patches_dir = os.path.join(srcsubdir, 'patches')
182 if os.path.exists(patches_dir):
183 shutil.rmtree(patches_dir)
184 # Restore any "patches" directory that was actually part of the source tree
185 try:
186 bb.process.run('git checkout -- patches', cwd=srcsubdir)
187 except bb.process.ExecutionError:
188 pass
189
190 extra_overrides = d.getVar('DEVTOOL_EXTRA_OVERRIDES')
191 if extra_overrides:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800192 extra_overrides = set(extra_overrides.split(':'))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400193 devbranch = d.getVar('DEVTOOL_DEVBRANCH')
194 default_overrides = d.getVar('OVERRIDES').split(':')
195 no_overrides = []
196 # First, we may have some overrides that are referred to in the recipe set in
197 # our configuration, so we need to make a branch that excludes those
198 for override in default_overrides:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800199 if override not in extra_overrides:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400200 no_overrides.append(override)
201 if default_overrides != no_overrides:
202 # Some overrides are active in the current configuration, so
203 # we need to create a branch where none of the overrides are active
204 bb.process.run('git checkout %s -b devtool-no-overrides' % initial_rev, cwd=srcsubdir)
205 # Run do_patch function with the override applied
206 localdata = bb.data.createCopy(d)
207 localdata.setVar('OVERRIDES', ':'.join(no_overrides))
Andrew Geisslerf0343792020-11-18 10:42:21 -0600208 localdata.setVar('FILESOVERRIDES', ':'.join(no_overrides))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400209 bb.build.exec_func('do_patch', localdata)
210 rm_patches()
211 # Now we need to reconcile the dev branch with the no-overrides one
212 # (otherwise we'd likely be left with identical commits that have different hashes)
213 bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir)
214 bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir)
215 else:
216 bb.process.run('git checkout %s -b devtool-no-overrides' % devbranch, cwd=srcsubdir)
217
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800218 for override in extra_overrides:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400219 localdata = bb.data.createCopy(d)
220 if override in default_overrides:
221 bb.process.run('git branch devtool-override-%s %s' % (override, devbranch), cwd=srcsubdir)
222 else:
223 # Reset back to the initial commit on a new branch
224 bb.process.run('git checkout %s -b devtool-override-%s' % (initial_rev, override), cwd=srcsubdir)
225 # Run do_patch function with the override applied
Andrew Geisslerf0343792020-11-18 10:42:21 -0600226 localdata.setVar('OVERRIDES', ':'.join(no_overrides + [override]))
227 localdata.setVar('FILESOVERRIDES', ':'.join(no_overrides + [override]))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400228 bb.build.exec_func('do_patch', localdata)
229 rm_patches()
230 # Now we need to reconcile the new branch with the no-overrides one
231 # (otherwise we'd likely be left with identical commits that have different hashes)
232 bb.process.run('git rebase devtool-no-overrides', cwd=srcsubdir)
233 bb.process.run('git checkout %s' % devbranch, cwd=srcsubdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500234 bb.process.run('git tag -f devtool-patched', cwd=srcsubdir)
Patrick Williamsda295312023-12-05 16:48:56 -0600235 if os.path.exists(os.path.join(srcsubdir, '.gitmodules')):
236 bb.process.run('git submodule foreach --recursive "git tag -f devtool-patched"', cwd=srcsubdir)
237
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500238}
239
240python devtool_post_configure() {
241 import shutil
242 tempdir = d.getVar('DEVTOOL_TEMPDIR')
243 shutil.copy2(os.path.join(d.getVar('B'), '.config'), tempdir)
244}