setup.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #
  2. # Copyright BitBake Contributors
  3. #
  4. # SPDX-License-Identifier: GPL-2.0-only
  5. #
  6. from bb.tests.fetch import FetcherTest
  7. import json
  8. class BitbakeSetupTest(FetcherTest):
  9. def setUp(self):
  10. super(BitbakeSetupTest, self).setUp()
  11. self.registrypath = os.path.join(self.tempdir, "bitbake-setup-configurations")
  12. os.makedirs(self.registrypath)
  13. self.git_init(cwd=self.registrypath)
  14. self.git('commit --allow-empty -m "Initial commit"', cwd=self.registrypath)
  15. self.testrepopath = os.path.join(self.tempdir, "test-repo")
  16. os.makedirs(self.testrepopath)
  17. self.git_init(cwd=self.testrepopath)
  18. self.git('commit --allow-empty -m "Initial commit"', cwd=self.testrepopath)
  19. oeinitbuildenv = """BBPATH=$1
  20. export BBPATH
  21. PATH={}:$PATH
  22. """.format(os.path.join(self.testrepopath, 'scripts'))
  23. self.add_file_to_testrepo('oe-init-build-env',oeinitbuildenv, script=True)
  24. oesetupbuild = """#!/usr/bin/env python3
  25. import getopt
  26. import sys
  27. import os
  28. import shutil
  29. opts, args = getopt.getopt(sys.argv[2:], "c:b:", ["no-shell"])
  30. for option, value in opts:
  31. if option == '-c':
  32. template = value
  33. if option == '-b':
  34. builddir = value
  35. confdir = os.path.join(builddir, 'conf')
  36. os.makedirs(confdir, exist_ok=True)
  37. with open(os.path.join(confdir, 'conf-summary.txt'), 'w') as f:
  38. f.write(template)
  39. shutil.copy(os.path.join(os.path.dirname(__file__), 'test-repo/test-file'), confdir)
  40. with open(os.path.join(builddir, 'init-build-env'), 'w') as f:
  41. f.write("BBPATH={}\\nexport BBPATH\\nPATH={}:$PATH".format(builddir, os.path.join(os.path.dirname(__file__), 'test-repo/scripts')))
  42. """
  43. self.add_file_to_testrepo('scripts/oe-setup-build', oesetupbuild, script=True)
  44. installbuildtools = """#!/usr/bin/env python3
  45. import getopt
  46. import sys
  47. import os
  48. opts, args = getopt.getopt(sys.argv[1:], "d:", ["downloads-directory="])
  49. for option, value in opts:
  50. if option == '-d':
  51. installdir = value
  52. print("Buildtools installed into {}".format(installdir))
  53. os.makedirs(installdir)
  54. """
  55. self.add_file_to_testrepo('scripts/install-buildtools', installbuildtools, script=True)
  56. bitbakeconfigbuild = """#!/usr/bin/env python3
  57. import os
  58. import sys
  59. confdir = os.path.join(os.environ['BBPATH'], 'conf')
  60. fragment = sys.argv[2]
  61. with open(os.path.join(confdir, fragment), 'w') as f:
  62. f.write('')
  63. """
  64. self.add_file_to_testrepo('scripts/bitbake-config-build', bitbakeconfigbuild, script=True)
  65. sometargetexecutable_template = """#!/usr/bin/env python3
  66. import os
  67. print("This is {}")
  68. print("BBPATH is {{}}".format(os.environ["BBPATH"]))
  69. """
  70. for e_name in ("some-target-executable-1", "some-target-executable-2"):
  71. sometargetexecutable = sometargetexecutable_template.format(e_name)
  72. self.add_file_to_testrepo('scripts/{}'.format(e_name), sometargetexecutable, script=True)
  73. def runbbsetup(self, cmd):
  74. bbsetup = os.path.abspath(os.path.dirname(__file__) + "/../../../bin/bitbake-setup")
  75. return bb.process.run("{} --global-settings {} {}".format(bbsetup, os.path.join(self.tempdir, 'global-config'), cmd))
  76. def add_json_config_to_registry(self, name, rev, branch):
  77. config = """
  78. {
  79. "sources": {
  80. "test-repo": {
  81. "git-remote": {
  82. "remotes": {
  83. "origin": {
  84. "uri": "file://%s"
  85. }
  86. },
  87. "branch": "%s",
  88. "rev": "%s"
  89. },
  90. "path": "test-repo"
  91. }
  92. },
  93. "description": "Test configuration",
  94. "bitbake-setup": {
  95. "configurations": [
  96. {
  97. "name": "gadget",
  98. "description": "Gadget build configuration",
  99. "oe-template": "test-configuration-gadget",
  100. "oe-fragments": ["test-fragment-1"]
  101. },
  102. {
  103. "name": "gizmo",
  104. "description": "Gizmo build configuration",
  105. "oe-template": "test-configuration-gizmo",
  106. "oe-fragments": ["test-fragment-2"]
  107. },
  108. {
  109. "name": "gizmo-env-passthrough",
  110. "description": "Gizmo build configuration with environment-passthrough",
  111. "bb-layers": ["layerC","layerD/meta-layer"],
  112. "oe-fragments": ["test-fragment-1"],
  113. "bb-env-passthrough-additions": [
  114. "BUILD_ID",
  115. "BUILD_DATE",
  116. "BUILD_SERVER"
  117. ]
  118. },
  119. {
  120. "name": "gizmo-no-fragment",
  121. "description": "Gizmo no-fragment template-only build configuration",
  122. "oe-template": "test-configuration-gizmo"
  123. },
  124. {
  125. "name": "gadget-notemplate",
  126. "description": "Gadget notemplate build configuration",
  127. "bb-layers": ["layerA","layerB/meta-layer"],
  128. "oe-fragments": ["test-fragment-1"]
  129. },
  130. {
  131. "name": "gizmo-notemplate",
  132. "description": "Gizmo notemplate build configuration",
  133. "bb-layers": ["layerC","layerD/meta-layer"],
  134. "oe-fragments": ["test-fragment-2"]
  135. },
  136. {
  137. "name": "gizmo-notemplate-with-thisdir",
  138. "description": "Gizmo notemplate build configuration using THISDIR",
  139. "bb-layers": ["layerC","layerD/meta-layer","{THISDIR}/layerE/meta-layer"],
  140. "oe-fragments": ["test-fragment-2"]
  141. }
  142. ]
  143. },
  144. "version": "1.0"
  145. }
  146. """ % (self.testrepopath, branch, rev)
  147. os.makedirs(os.path.join(self.registrypath, os.path.dirname(name)), exist_ok=True)
  148. with open(os.path.join(self.registrypath, name), 'w') as f:
  149. f.write(config)
  150. self.git('add {}'.format(name), cwd=self.registrypath)
  151. self.git('commit -m "Adding {}"'.format(name), cwd=self.registrypath)
  152. return json.loads(config)
  153. def add_file_to_testrepo(self, name, content, script=False):
  154. fullname = os.path.join(self.testrepopath, name)
  155. os.makedirs(os.path.join(self.testrepopath, os.path.dirname(name)), exist_ok=True)
  156. with open(fullname, 'w') as f:
  157. f.write(content)
  158. if script:
  159. import stat
  160. st = os.stat(fullname)
  161. os.chmod(fullname, st.st_mode | stat.S_IEXEC)
  162. self.git('add {}'.format(name), cwd=self.testrepopath)
  163. self.git('commit -m "Adding {}"'.format(name), cwd=self.testrepopath)
  164. def check_builddir_files(self, buildpath, test_file_content, json_config):
  165. with open(os.path.join(buildpath, 'layers', 'test-repo', 'test-file')) as f:
  166. self.assertEqual(f.read(), test_file_content)
  167. bitbake_config = json_config["bitbake-config"]
  168. bb_build_path = os.path.join(buildpath, 'build')
  169. bb_conf_path = os.path.join(bb_build_path, 'conf')
  170. self.assertTrue(os.path.exists(os.path.join(bb_build_path, 'init-build-env')))
  171. if "oe-template" in bitbake_config:
  172. with open(os.path.join(bb_conf_path, 'conf-summary.txt')) as f:
  173. self.assertEqual(f.read(), bitbake_config["oe-template"])
  174. with open(os.path.join(bb_conf_path, 'test-file')) as f:
  175. self.assertEqual(f.read(), test_file_content)
  176. else:
  177. with open(os.path.join(bb_conf_path, 'conf-summary.txt')) as f:
  178. self.assertIn(bitbake_config["description"], f.read())
  179. with open(os.path.join(bb_conf_path, 'bblayers.conf')) as f:
  180. bblayers = f.read()
  181. for l in bitbake_config["bb-layers"]:
  182. if l.startswith('{THISDIR}/'):
  183. thisdir_layer = os.path.join(
  184. os.path.dirname(json_config["path"]),
  185. l.removeprefix("{THISDIR}/"),
  186. )
  187. self.assertIn(thisdir_layer, bblayers)
  188. else:
  189. self.assertIn(os.path.join(buildpath, "layers", l), bblayers)
  190. if 'oe-fragment' in bitbake_config.keys():
  191. for f in bitbake_config["oe-fragments"]:
  192. self.assertTrue(os.path.exists(os.path.join(bb_conf_path, f)))
  193. if 'bb-environment-passthrough' in bitbake_config.keys():
  194. with open(os.path.join(bb_build_path, 'init-build-env'), 'r') as f:
  195. init_build_env = f.read()
  196. self.assertTrue('BB_ENV_PASSTHROUGH_ADDITIONS' in init_build_env)
  197. self.assertTrue('BUILD_ID' in init_build_env)
  198. self.assertTrue('BUILD_DATE' in init_build_env)
  199. self.assertTrue('BUILD_SERVER' in init_build_env)
  200. # 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'
  201. def test_setup(self):
  202. # unset BBPATH to ensure tests run in isolation from the existing bitbake environment
  203. import os
  204. if 'BBPATH' in os.environ:
  205. del os.environ['BBPATH']
  206. # check that no arguments works
  207. self.runbbsetup("")
  208. # check that --help works
  209. self.runbbsetup("--help")
  210. # set up global location for top-dir-prefix
  211. out = self.runbbsetup("settings set --global default top-dir-prefix {}".format(self.tempdir))
  212. settings_path = "{}/global-config".format(self.tempdir)
  213. self.assertIn(settings_path, out[0])
  214. self.assertIn("From section 'default' the setting 'top-dir-prefix' was changed to", out[0])
  215. self.assertIn("Settings written to".format(settings_path), out[0])
  216. out = self.runbbsetup("settings set --global default dl-dir {}".format(os.path.join(self.tempdir, 'downloads')))
  217. self.assertIn("From section 'default' the setting 'dl-dir' was changed to", out[0])
  218. self.assertIn("Settings written to".format(settings_path), out[0])
  219. # check that writing settings works and then adjust them to point to
  220. # test registry repo
  221. out = self.runbbsetup("settings set default registry 'git://{};protocol=file;branch=master;rev=master'".format(self.registrypath))
  222. settings_path = "{}/bitbake-builds/settings.conf".format(self.tempdir)
  223. self.assertIn(settings_path, out[0])
  224. self.assertIn("From section 'default' the setting 'registry' was changed to", out[0])
  225. self.assertIn("Settings written to".format(settings_path), out[0])
  226. # check that listing settings works
  227. out = self.runbbsetup("settings list")
  228. self.assertIn("default top-dir-prefix {}".format(self.tempdir), out[0])
  229. self.assertIn("default dl-dir {}".format(os.path.join(self.tempdir, 'downloads')), out[0])
  230. self.assertIn("default registry {}".format('git://{};protocol=file;branch=master;rev=master'.format(self.registrypath)), out[0])
  231. # check that 'list' produces correct output with no configs, one config and two configs
  232. out = self.runbbsetup("list")
  233. self.assertNotIn("test-config-1", out[0])
  234. self.assertNotIn("test-config-2", out[0])
  235. json_1 = self.add_json_config_to_registry('test-config-1.conf.json', 'master', 'master')
  236. out = self.runbbsetup("list")
  237. self.assertIn("test-config-1", out[0])
  238. self.assertNotIn("test-config-2", out[0])
  239. json_2 = self.add_json_config_to_registry('config-2/test-config-2.conf.json', 'master', 'master')
  240. out = self.runbbsetup("list --write-json={}".format(os.path.join(self.tempdir, "test-configs.json")))
  241. self.assertIn("test-config-1", out[0])
  242. self.assertIn("test-config-2", out[0])
  243. with open(os.path.join(self.tempdir, "test-configs.json")) as f:
  244. json_configs = json.load(f)
  245. self.assertIn("test-config-1", json_configs)
  246. self.assertIn("test-config-2", json_configs)
  247. # check that init/status/update work
  248. # (the latter two should do nothing and say that config hasn't changed)
  249. test_file_content = 'initial\n'
  250. self.add_file_to_testrepo('test-file', test_file_content)
  251. # test-config-1 is tested as a registry config, test-config-2 as a local file
  252. test_configurations = {'test-config-1': {'cmdline': 'test-config-1',
  253. 'buildconfigs':('gadget','gizmo',
  254. 'gizmo-env-passthrough',
  255. 'gizmo-no-fragment',
  256. 'gadget-notemplate','gizmo-notemplate')},
  257. 'test-config-2': {'cmdline': os.path.join(self.registrypath,'config-2/test-config-2.conf.json'),
  258. 'buildconfigs': ('gadget','gizmo',
  259. 'gizmo-env-passthrough',
  260. 'gizmo-no-fragment',
  261. 'gadget-notemplate','gizmo-notemplate',
  262. 'gizmo-notemplate-with-thisdir')}
  263. }
  264. for cf, v in test_configurations.items():
  265. for c in v['buildconfigs']:
  266. out = self.runbbsetup("init --non-interactive {} {}".format(v['cmdline'], c))
  267. buildpath = os.path.join(self.tempdir, 'bitbake-builds', '{}-{}'.format(cf, c))
  268. with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
  269. config_upstream = json.load(f)
  270. self.check_builddir_files(buildpath, test_file_content, config_upstream)
  271. os.environ['BBPATH'] = os.path.join(buildpath, 'build')
  272. out = self.runbbsetup("status")
  273. self.assertIn("Configuration in {} has not changed".format(buildpath), out[0])
  274. out = self.runbbsetup("update")
  275. self.assertIn("Configuration in {} has not changed".format(buildpath), out[0])
  276. # install buildtools
  277. out = self.runbbsetup("install-buildtools")
  278. self.assertIn("Buildtools installed into", out[0])
  279. self.assertTrue(os.path.exists(os.path.join(buildpath, 'buildtools')))
  280. # change a file in the test layer repo, make a new commit and
  281. # test that status/update correctly report the change and update the config
  282. prev_test_file_content = test_file_content
  283. test_file_content = 'modified\n'
  284. self.add_file_to_testrepo('test-file', test_file_content)
  285. for c in ('gadget', 'gizmo',
  286. 'gizmo-env-passthrough',
  287. 'gizmo-no-fragment',
  288. 'gadget-notemplate', 'gizmo-notemplate'):
  289. buildpath = os.path.join(self.tempdir, 'bitbake-builds', 'test-config-1-{}'.format(c))
  290. os.environ['BBPATH'] = os.path.join(buildpath, 'build')
  291. out = self.runbbsetup("status")
  292. self.assertIn("Layer repository file://{} checked out into {}/layers/test-repo updated revision master from".format(self.testrepopath, buildpath), out[0])
  293. out = self.runbbsetup("update")
  294. if c in ('gadget', 'gizmo'):
  295. self.assertIn("Existing bitbake configuration directory renamed to {}/build/conf-backup.".format(buildpath), out[0])
  296. self.assertIn('-{}+{}'.format(prev_test_file_content, test_file_content), out[0])
  297. with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
  298. config_upstream = json.load(f)
  299. self.check_builddir_files(buildpath, test_file_content, config_upstream)
  300. # make a new branch in the test layer repo, change a file on that branch,
  301. # make a new commit, update the top level json config to refer to that branch,
  302. # and test that status/update correctly report the change and update the config
  303. prev_test_file_content = test_file_content
  304. test_file_content = 'modified-in-branch\n'
  305. branch = "another-branch"
  306. self.git('checkout -b {}'.format(branch), cwd=self.testrepopath)
  307. self.add_file_to_testrepo('test-file', test_file_content)
  308. json_1 = self.add_json_config_to_registry('test-config-1.conf.json', branch, branch)
  309. for c in ('gadget', 'gizmo',
  310. 'gizmo-env-passthrough',
  311. 'gizmo-no-fragment',
  312. 'gadget-notemplate', 'gizmo-notemplate'):
  313. buildpath = os.path.join(self.tempdir, 'bitbake-builds', 'test-config-1-{}'.format(c))
  314. os.environ['BBPATH'] = os.path.join(buildpath, 'build')
  315. out = self.runbbsetup("status")
  316. self.assertIn("Configuration in {} has changed:".format(buildpath), out[0])
  317. self.assertIn('- "rev": "master"\n+ "rev": "another-branch"', out[0])
  318. out = self.runbbsetup("update")
  319. if c in ('gadget', 'gizmo'):
  320. self.assertIn("Existing bitbake configuration directory renamed to {}/build/conf-backup.".format(buildpath), out[0])
  321. self.assertIn('-{}+{}'.format(prev_test_file_content, test_file_content), out[0])
  322. with open(os.path.join(buildpath, 'config', "config-upstream.json")) as f:
  323. config_upstream = json.load(f)
  324. self.check_builddir_files(buildpath, test_file_content, config_upstream)