summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb')
-rw-r--r--bitbake/lib/bb/cooker.py5
-rw-r--r--bitbake/lib/bb/tests/setup.py358
-rw-r--r--bitbake/lib/bb/ui/knotty.py5
-rw-r--r--bitbake/lib/bb/ui/uihelper.py3
4 files changed, 363 insertions, 8 deletions
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index fb87368f17..03f262ac16 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -320,7 +320,10 @@ class BBCooker:
320 except ImportError as e: 320 except ImportError as e:
321 bb.fatal(""""Unable to use hash equivalence server at '%s' due to missing or incorrect python module: 321 bb.fatal(""""Unable to use hash equivalence server at '%s' due to missing or incorrect python module:
322%s 322%s
323Please install the needed module on the build host, or use an environment containing it (e.g a pip venv or OpenEmbedded's buildtools tarball). 323Please install the needed module on the build host, or use an environment containing it:
324 - if you are using bitbake-setup, run 'bitbake-setup install-buildtools'
325 - openembedded-core layer contains 'scripts/install-buildtools' that can also be used
326 - or set up pip venv
324You can also remove the BB_HASHSERVE_UPSTREAM setting, but this may result in significantly longer build times as bitbake will be unable to reuse prebuilt sstate artefacts.""" 327You can also remove the BB_HASHSERVE_UPSTREAM setting, but this may result in significantly longer build times as bitbake will be unable to reuse prebuilt sstate artefacts."""
325 % (upstream, repr(e))) 328 % (upstream, repr(e)))
326 except ConnectionError as e: 329 except ConnectionError as e:
diff --git a/bitbake/lib/bb/tests/setup.py b/bitbake/lib/bb/tests/setup.py
new file mode 100644
index 0000000000..e320cdf56f
--- /dev/null
+++ b/bitbake/lib/bb/tests/setup.py
@@ -0,0 +1,358 @@
1#
2# Copyright BitBake Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7from bb.tests.fetch import FetcherTest
8import json
9
10class BitbakeSetupTest(FetcherTest):
11 def setUp(self):
12 super(BitbakeSetupTest, self).setUp()
13
14 self.registrypath = os.path.join(self.tempdir, "bitbake-setup-configurations")
15
16 os.makedirs(self.registrypath)
17 self.git_init(cwd=self.registrypath)
18 self.git('commit --allow-empty -m "Initial commit"', cwd=self.registrypath)
19
20 self.testrepopath = os.path.join(self.tempdir, "test-repo")
21 os.makedirs(self.testrepopath)
22 self.git_init(cwd=self.testrepopath)
23 self.git('commit --allow-empty -m "Initial commit"', cwd=self.testrepopath)
24
25 oeinitbuildenv = """BBPATH=$1
26export BBPATH
27PATH={}:$PATH
28""".format(os.path.join(self.testrepopath, 'scripts'))
29 self.add_file_to_testrepo('oe-init-build-env',oeinitbuildenv, script=True)
30
31 oesetupbuild = """#!/usr/bin/env python3
32import getopt
33import sys
34import os
35import shutil
36opts, args = getopt.getopt(sys.argv[2:], "c:b:", ["no-shell"])
37for option, value in opts:
38 if option == '-c':
39 template = value
40 if option == '-b':
41 builddir = value
42confdir = os.path.join(builddir, 'conf')
43os.makedirs(confdir, exist_ok=True)
44with open(os.path.join(confdir, 'conf-summary.txt'), 'w') as f:
45 f.write(template)
46shutil.copy(os.path.join(os.path.dirname(__file__), 'test-repo/test-file'), confdir)
47with open(os.path.join(builddir, 'init-build-env'), 'w') as f:
48 f.write("BBPATH={}\\nexport BBPATH\\nPATH={}:$PATH".format(builddir, os.path.join(os.path.dirname(__file__), 'test-repo/scripts')))
49"""
50 self.add_file_to_testrepo('scripts/oe-setup-build', oesetupbuild, script=True)
51
52 installbuildtools = """#!/usr/bin/env python3
53import getopt
54import sys
55import os
56
57opts, args = getopt.getopt(sys.argv[1:], "d:", ["downloads-directory="])
58for option, value in opts:
59 if option == '-d':
60 installdir = value
61
62print("Buildtools installed into {}".format(installdir))
63os.makedirs(installdir)
64"""
65 self.add_file_to_testrepo('scripts/install-buildtools', installbuildtools, script=True)
66
67 bitbakeconfigbuild = """#!/usr/bin/env python3
68import os
69import sys
70confdir = os.path.join(os.environ['BBPATH'], 'conf')
71fragment = sys.argv[2]
72with open(os.path.join(confdir, fragment), 'w') as f:
73 f.write('')
74"""
75 self.add_file_to_testrepo('scripts/bitbake-config-build', bitbakeconfigbuild, script=True)
76
77 sometargetexecutable_template = """#!/usr/bin/env python3
78import os
79print("This is {}")
80print("BBPATH is {{}}".format(os.environ["BBPATH"]))
81"""
82 for e_name in ("some-target-executable-1", "some-target-executable-2"):
83 sometargetexecutable = sometargetexecutable_template.format(e_name)
84 self.add_file_to_testrepo('scripts/{}'.format(e_name), sometargetexecutable, script=True)
85
86 def runbbsetup(self, cmd):
87 bbsetup = os.path.abspath(os.path.dirname(__file__) + "/../../../bin/bitbake-setup")
88 return bb.process.run("{} --global-settings {} {}".format(bbsetup, os.path.join(self.tempdir, 'global-config'), cmd))
89
90 def add_json_config_to_registry(self, name, rev, branch):
91 config = """
92{
93 "sources": {
94 "test-repo": {
95 "git-remote": {
96 "remotes": {
97 "origin": {
98 "uri": "file://%s"
99 }
100 },
101 "branch": "%s",
102 "rev": "%s"
103 },
104 "path": "test-repo"
105 }
106 },
107 "description": "Test configuration",
108 "bitbake-setup": {
109 "configurations": [
110 {
111 "name": "gadget",
112 "description": "Gadget build configuration",
113 "oe-template": "test-configuration-gadget",
114 "oe-fragments": ["test-fragment-1"]
115 },
116 {
117 "name": "gizmo",
118 "description": "Gizmo build configuration",
119 "oe-template": "test-configuration-gizmo",
120 "oe-fragments": ["test-fragment-2"]
121 },
122 {
123 "name": "gizmo-env-passthrough",
124 "description": "Gizmo build configuration with environment-passthrough",
125 "bb-layers": ["layerC","layerD/meta-layer"],
126 "oe-fragments": ["test-fragment-1"],
127 "bb-env-passthrough-additions": [
128 "BUILD_ID",
129 "BUILD_DATE",
130 "BUILD_SERVER"
131 ]
132 },
133 {
134 "name": "gizmo-no-fragment",
135 "description": "Gizmo no-fragment template-only build configuration",
136 "oe-template": "test-configuration-gizmo"
137 },
138 {
139 "name": "gadget-notemplate",
140 "description": "Gadget notemplate build configuration",
141 "bb-layers": ["layerA","layerB/meta-layer"],
142 "oe-fragments": ["test-fragment-1"]
143 },
144 {
145 "name": "gizmo-notemplate",
146 "description": "Gizmo notemplate build configuration",
147 "bb-layers": ["layerC","layerD/meta-layer"],
148 "oe-fragments": ["test-fragment-2"]
149 },
150 {
151 "name": "gizmo-notemplate-with-thisdir",
152 "description": "Gizmo notemplate build configuration using THISDIR",
153 "bb-layers": ["layerC","layerD/meta-layer","{THISDIR}/layerE/meta-layer"],
154 "oe-fragments": ["test-fragment-2"]
155 }
156 ]
157 },
158 "version": "1.0"
159}
160""" % (self.testrepopath, branch, rev)
161 os.makedirs(os.path.join(self.registrypath, os.path.dirname(name)), exist_ok=True)
162 with open(os.path.join(self.registrypath, name), 'w') as f:
163 f.write(config)
164 self.git('add {}'.format(name), cwd=self.registrypath)
165 self.git('commit -m "Adding {}"'.format(name), cwd=self.registrypath)
166 return json.loads(config)
167
168 def add_file_to_testrepo(self, name, content, script=False):
169 fullname = os.path.join(self.testrepopath, name)
170 os.makedirs(os.path.join(self.testrepopath, os.path.dirname(name)), exist_ok=True)
171 with open(fullname, 'w') as f:
172 f.write(content)
173 if script:
174 import stat
175 st = os.stat(fullname)
176 os.chmod(fullname, st.st_mode | stat.S_IEXEC)
177 self.git('add {}'.format(name), cwd=self.testrepopath)
178 self.git('commit -m "Adding {}"'.format(name), cwd=self.testrepopath)
179
180 def check_builddir_files(self, buildpath, test_file_content, json_config):
181 with open(os.path.join(buildpath, 'layers', 'test-repo', 'test-file')) as f:
182 self.assertEqual(f.read(), test_file_content)
183 bitbake_config = json_config["bitbake-config"]
184 bb_build_path = os.path.join(buildpath, 'build')
185 bb_conf_path = os.path.join(bb_build_path, 'conf')
186 self.assertTrue(os.path.exists(os.path.join(bb_build_path, 'init-build-env')))
187
188 if "oe-template" in bitbake_config:
189 with open(os.path.join(bb_conf_path, 'conf-summary.txt')) as f:
190 self.assertEqual(f.read(), bitbake_config["oe-template"])
191 with open(os.path.join(bb_conf_path, 'test-file')) as f:
192 self.assertEqual(f.read(), test_file_content)
193 else:
194 with open(os.path.join(bb_conf_path, 'conf-summary.txt')) as f:
195 self.assertIn(bitbake_config["description"], f.read())
196 with open(os.path.join(bb_conf_path, 'bblayers.conf')) as f:
197 bblayers = f.read()
198 for l in bitbake_config["bb-layers"]:
199 if l.startswith('{THISDIR}/'):
200 thisdir_layer = os.path.join(
201 os.path.dirname(json_config["path"]),
202 l.removeprefix("{THISDIR}/"),
203 )
204 self.assertIn(thisdir_layer, bblayers)
205 else:
206 self.assertIn(os.path.join(buildpath, "layers", l), bblayers)
207
208 if 'oe-fragment' in bitbake_config.keys():
209 for f in bitbake_config["oe-fragments"]:
210 self.assertTrue(os.path.exists(os.path.join(bb_conf_path, f)))
211
212 if 'bb-environment-passthrough' in bitbake_config.keys():
213 with open(os.path.join(bb_build_path, 'init-build-env'), 'r') as f:
214 init_build_env = f.read()
215 self.assertTrue('BB_ENV_PASSTHROUGH_ADDITIONS' in init_build_env)
216 self.assertTrue('BUILD_ID' in init_build_env)
217 self.assertTrue('BUILD_DATE' in init_build_env)
218 self.assertTrue('BUILD_SERVER' in init_build_env)
219 # a more throrough test could be to initialize a bitbake build-env, export FOO to the shell environment, set the env-passthrough on it and finally check against 'bitbake-getvar FOO'
220
221
222 def test_setup(self):
223 # unset BBPATH to ensure tests run in isolation from the existing bitbake environment
224 import os
225 if 'BBPATH' in os.environ:
226 del os.environ['BBPATH']
227
228 # check that no arguments works
229 self.runbbsetup("")
230
231 # check that --help works
232 self.runbbsetup("--help")
233
234 # set up global location for top-dir-prefix
235 out = self.runbbsetup("settings set --global default top-dir-prefix {}".format(self.tempdir))
236 settings_path = "{}/global-config".format(self.tempdir)
237 self.assertIn(settings_path, out[0])
238 self.assertIn("From section 'default' the setting 'top-dir-prefix' was changed to", out[0])
239 self.assertIn("Settings written to".format(settings_path), out[0])
240 out = self.runbbsetup("settings set --global default dl-dir {}".format(os.path.join(self.tempdir, 'downloads')))
241 self.assertIn("From section 'default' the setting 'dl-dir' was changed to", out[0])
242 self.assertIn("Settings written to".format(settings_path), out[0])
243
244 # check that writing settings works and then adjust them to point to
245 # test registry repo
246 out = self.runbbsetup("settings set default registry 'git://{};protocol=file;branch=master;rev=master'".format(self.registrypath))
247 settings_path = "{}/bitbake-builds/settings.conf".format(self.tempdir)
248 self.assertIn(settings_path, out[0])
249 self.assertIn("From section 'default' the setting 'registry' was changed to", out[0])
250 self.assertIn("Settings written to".format(settings_path), out[0])
251
252 # check that listing settings works
253 out = self.runbbsetup("settings list")
254 self.assertIn("default top-dir-prefix {}".format(self.tempdir), out[0])
255 self.assertIn("default dl-dir {}".format(os.path.join(self.tempdir, 'downloads')), out[0])
256 self.assertIn("default registry {}".format('git://{};protocol=file;branch=master;rev=master'.format(self.registrypath)), out[0])
257
258 # check that 'list' produces correct output with no configs, one config and two configs
259 out = self.runbbsetup("list")
260 self.assertNotIn("test-config-1", out[0])
261 self.assertNotIn("test-config-2", out[0])
262
263 json_1 = self.add_json_config_to_registry('test-config-1.conf.json', 'master', 'master')
264 out = self.runbbsetup("list")
265 self.assertIn("test-config-1", out[0])
266 self.assertNotIn("test-config-2", out[0])
267
268 json_2 = self.add_json_config_to_registry('config-2/test-config-2.conf.json', 'master', 'master')
269 out = self.runbbsetup("list --write-json={}".format(os.path.join(self.tempdir, "test-configs.json")))
270 self.assertIn("test-config-1", out[0])
271 self.assertIn("test-config-2", out[0])
272 with open(os.path.join(self.tempdir, "test-configs.json")) as f:
273 json_configs = json.load(f)
274 self.assertIn("test-config-1", json_configs)
275 self.assertIn("test-config-2", json_configs)
276
277 # check that init/status/update work
278 # (the latter two should do nothing and say that config hasn't changed)
279 test_file_content = 'initial\n'
280 self.add_file_to_testrepo('test-file', test_file_content)
281
282 # test-config-1 is tested as a registry config, test-config-2 as a local file
283 test_configurations = {'test-config-1': {'cmdline': 'test-config-1',
284 'buildconfigs':('gadget','gizmo',
285 'gizmo-env-passthrough',
286 'gizmo-no-fragment',
287 'gadget-notemplate','gizmo-notemplate')},
288 'test-config-2': {'cmdline': os.path.join(self.registrypath,'config-2/test-config-2.conf.json'),
289 'buildconfigs': ('gadget','gizmo',
290 'gizmo-env-passthrough',
291 'gizmo-no-fragment',
292 'gadget-notemplate','gizmo-notemplate',
293 'gizmo-notemplate-with-thisdir')}
294 }
295 for cf, v in test_configurations.items():
296 for c in v['buildconfigs']:
297 out = self.runbbsetup("init --non-interactive {} {}".format(v['cmdline'], c))
298 buildpath = os.path.join(self.tempdir, 'bitbake-builds', '{}-{}'.format(cf, c))
299 with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
300 config_upstream = json.load(f)
301 self.check_builddir_files(buildpath, test_file_content, config_upstream)
302 os.environ['BBPATH'] = os.path.join(buildpath, 'build')
303 out = self.runbbsetup("status")
304 self.assertIn("Configuration in {} has not changed".format(buildpath), out[0])
305 out = self.runbbsetup("update")
306 self.assertIn("Configuration in {} has not changed".format(buildpath), out[0])
307
308 # install buildtools
309 out = self.runbbsetup("install-buildtools")
310 self.assertIn("Buildtools installed into", out[0])
311 self.assertTrue(os.path.exists(os.path.join(buildpath, 'buildtools')))
312
313 # change a file in the test layer repo, make a new commit and
314 # test that status/update correctly report the change and update the config
315 prev_test_file_content = test_file_content
316 test_file_content = 'modified\n'
317 self.add_file_to_testrepo('test-file', test_file_content)
318 for c in ('gadget', 'gizmo',
319 'gizmo-env-passthrough',
320 'gizmo-no-fragment',
321 'gadget-notemplate', 'gizmo-notemplate'):
322 buildpath = os.path.join(self.tempdir, 'bitbake-builds', 'test-config-1-{}'.format(c))
323 os.environ['BBPATH'] = os.path.join(buildpath, 'build')
324 out = self.runbbsetup("status")
325 self.assertIn("Layer repository file://{} checked out into {}/layers/test-repo updated revision master from".format(self.testrepopath, buildpath), out[0])
326 out = self.runbbsetup("update")
327 if c in ('gadget', 'gizmo'):
328 self.assertIn("Existing bitbake configuration directory renamed to {}/build/conf-backup.".format(buildpath), out[0])
329 self.assertIn('-{}+{}'.format(prev_test_file_content, test_file_content), out[0])
330 with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
331 config_upstream = json.load(f)
332 self.check_builddir_files(buildpath, test_file_content, config_upstream)
333
334 # make a new branch in the test layer repo, change a file on that branch,
335 # make a new commit, update the top level json config to refer to that branch,
336 # and test that status/update correctly report the change and update the config
337 prev_test_file_content = test_file_content
338 test_file_content = 'modified-in-branch\n'
339 branch = "another-branch"
340 self.git('checkout -b {}'.format(branch), cwd=self.testrepopath)
341 self.add_file_to_testrepo('test-file', test_file_content)
342 json_1 = self.add_json_config_to_registry('test-config-1.conf.json', branch, branch)
343 for c in ('gadget', 'gizmo',
344 'gizmo-env-passthrough',
345 'gizmo-no-fragment',
346 'gadget-notemplate', 'gizmo-notemplate'):
347 buildpath = os.path.join(self.tempdir, 'bitbake-builds', 'test-config-1-{}'.format(c))
348 os.environ['BBPATH'] = os.path.join(buildpath, 'build')
349 out = self.runbbsetup("status")
350 self.assertIn("Configuration in {} has changed:".format(buildpath), out[0])
351 self.assertIn('- "rev": "master"\n+ "rev": "another-branch"', out[0])
352 out = self.runbbsetup("update")
353 if c in ('gadget', 'gizmo'):
354 self.assertIn("Existing bitbake configuration directory renamed to {}/build/conf-backup.".format(buildpath), out[0])
355 self.assertIn('-{}+{}'.format(prev_test_file_content, test_file_content), out[0])
356 with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
357 config_upstream = json.load(f)
358 self.check_builddir_files(buildpath, test_file_content, config_upstream)
diff --git a/bitbake/lib/bb/ui/knotty.py b/bitbake/lib/bb/ui/knotty.py
index 492ea20763..00258c80ff 100644
--- a/bitbake/lib/bb/ui/knotty.py
+++ b/bitbake/lib/bb/ui/knotty.py
@@ -169,7 +169,6 @@ class TerminalFilter(object):
169 self.stdinbackup = None 169 self.stdinbackup = None
170 self.interactive = sys.stdout.isatty() 170 self.interactive = sys.stdout.isatty()
171 self.footer_present = False 171 self.footer_present = False
172 self.lastpids = []
173 self.lasttime = time.time() 172 self.lasttime = time.time()
174 self.quiet = quiet 173 self.quiet = quiet
175 174
@@ -254,7 +253,6 @@ class TerminalFilter(object):
254 return 253 return
255 activetasks = self.helper.running_tasks 254 activetasks = self.helper.running_tasks
256 failedtasks = self.helper.failed_tasks 255 failedtasks = self.helper.failed_tasks
257 runningpids = self.helper.running_pids
258 currenttime = time.time() 256 currenttime = time.time()
259 deltatime = currenttime - self.lasttime 257 deltatime = currenttime - self.lasttime
260 258
@@ -283,7 +281,7 @@ class TerminalFilter(object):
283 self._footer_buf.seek(0) 281 self._footer_buf.seek(0)
284 282
285 tasks = [] 283 tasks = []
286 for t in runningpids: 284 for t in activetasks.keys():
287 start_time = activetasks[t].get("starttime", None) 285 start_time = activetasks[t].get("starttime", None)
288 if start_time: 286 if start_time:
289 msg = "%s - %s (pid %s)" % (activetasks[t]["title"], self.elapsed(currenttime - start_time), activetasks[t]["pid"]) 287 msg = "%s - %s (pid %s)" % (activetasks[t]["title"], self.elapsed(currenttime - start_time), activetasks[t]["pid"])
@@ -358,7 +356,6 @@ class TerminalFilter(object):
358 content = "%s: %s" % (tasknum, task) 356 content = "%s: %s" % (tasknum, task)
359 print(content, file=self._footer_buf) 357 print(content, file=self._footer_buf)
360 lines = lines + self.getlines(content) 358 lines = lines + self.getlines(content)
361 self.lastpids = runningpids[:]
362 self.lastcount = self.helper.tasknumber_current 359 self.lastcount = self.helper.tasknumber_current
363 360
364 # Clear footer and Print buffer. 361 # Clear footer and Print buffer.
diff --git a/bitbake/lib/bb/ui/uihelper.py b/bitbake/lib/bb/ui/uihelper.py
index e6983bd559..a223632471 100644
--- a/bitbake/lib/bb/ui/uihelper.py
+++ b/bitbake/lib/bb/ui/uihelper.py
@@ -13,7 +13,6 @@ class BBUIHelper:
13 self.needUpdate = False 13 self.needUpdate = False
14 self.running_tasks = {} 14 self.running_tasks = {}
15 # Running PIDs preserves the order tasks were executed in 15 # Running PIDs preserves the order tasks were executed in
16 self.running_pids = []
17 self.failed_tasks = [] 16 self.failed_tasks = []
18 self.pidmap = {} 17 self.pidmap = {}
19 self.tasknumber_current = 0 18 self.tasknumber_current = 0
@@ -23,7 +22,6 @@ class BBUIHelper:
23 # PIDs are a bad idea as they can be reused before we process all UI events. 22 # PIDs are a bad idea as they can be reused before we process all UI events.
24 # We maintain a 'fuzzy' match for TaskProgress since there is no other way to match 23 # We maintain a 'fuzzy' match for TaskProgress since there is no other way to match
25 def removetid(pid, tid): 24 def removetid(pid, tid):
26 self.running_pids.remove(tid)
27 del self.running_tasks[tid] 25 del self.running_tasks[tid]
28 if self.pidmap[pid] == tid: 26 if self.pidmap[pid] == tid:
29 del self.pidmap[pid] 27 del self.pidmap[pid]
@@ -35,7 +33,6 @@ class BBUIHelper:
35 self.running_tasks[tid] = { 'title' : "mc:%s:%s %s" % (event._mc, event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid } 33 self.running_tasks[tid] = { 'title' : "mc:%s:%s %s" % (event._mc, event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid }
36 else: 34 else:
37 self.running_tasks[tid] = { 'title' : "%s %s" % (event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid } 35 self.running_tasks[tid] = { 'title' : "%s %s" % (event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid }
38 self.running_pids.append(tid)
39 self.pidmap[event.pid] = tid 36 self.pidmap[event.pid] = tid
40 self.needUpdate = True 37 self.needUpdate = True
41 elif isinstance(event, bb.build.TaskSucceeded): 38 elif isinstance(event, bb.build.TaskSucceeded):