diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases/devtool.py')
-rw-r--r-- | meta/lib/oeqa/selftest/cases/devtool.py | 1412 |
1 files changed, 1262 insertions, 150 deletions
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py index 3385546e8e..05f228f03e 100644 --- a/meta/lib/oeqa/selftest/cases/devtool.py +++ b/meta/lib/oeqa/selftest/cases/devtool.py | |||
@@ -1,18 +1,23 @@ | |||
1 | # | 1 | # |
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
2 | # SPDX-License-Identifier: MIT | 4 | # SPDX-License-Identifier: MIT |
3 | # | 5 | # |
4 | 6 | ||
7 | import errno | ||
5 | import os | 8 | import os |
6 | import re | 9 | import re |
7 | import shutil | 10 | import shutil |
8 | import tempfile | 11 | import tempfile |
9 | import glob | 12 | import glob |
10 | import fnmatch | 13 | import fnmatch |
14 | import unittest | ||
15 | import json | ||
11 | 16 | ||
12 | import oeqa.utils.ftools as ftools | ||
13 | from oeqa.selftest.case import OESelftestTestCase | 17 | from oeqa.selftest.case import OESelftestTestCase |
14 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer | 18 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer |
15 | from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer | 19 | from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer |
20 | from oeqa.core.decorator import OETestTag | ||
16 | 21 | ||
17 | oldmetapath = None | 22 | oldmetapath = None |
18 | 23 | ||
@@ -24,6 +29,9 @@ def setUpModule(): | |||
24 | corecopydir = os.path.join(templayerdir, 'core-copy') | 29 | corecopydir = os.path.join(templayerdir, 'core-copy') |
25 | bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf') | 30 | bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf') |
26 | edited_layers = [] | 31 | edited_layers = [] |
32 | # make sure user doesn't have a local workspace | ||
33 | result = runCmd('bitbake-layers show-layers') | ||
34 | assert "workspacelayer" not in result.output, "Devtool test suite cannot be run with a local workspace directory" | ||
27 | 35 | ||
28 | # We need to take a copy of the meta layer so we can modify it and not | 36 | # We need to take a copy of the meta layer so we can modify it and not |
29 | # have any races against other tests that might be running in parallel | 37 | # have any races against other tests that might be running in parallel |
@@ -38,10 +46,17 @@ def setUpModule(): | |||
38 | canonical_layerpath = os.path.realpath(canonical_layerpath) + '/' | 46 | canonical_layerpath = os.path.realpath(canonical_layerpath) + '/' |
39 | edited_layers.append(layerpath) | 47 | edited_layers.append(layerpath) |
40 | oldmetapath = os.path.realpath(layerpath) | 48 | oldmetapath = os.path.realpath(layerpath) |
49 | |||
50 | # when downloading poky from tar.gz some tests will be skipped (BUG 12389) | ||
51 | try: | ||
52 | runCmd('git rev-parse --is-inside-work-tree', cwd=canonical_layerpath) | ||
53 | except: | ||
54 | raise unittest.SkipTest("devtool tests require folder to be a git repo") | ||
55 | |||
41 | result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath) | 56 | result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath) |
42 | oldreporoot = result.output.rstrip() | 57 | oldreporoot = result.output.rstrip() |
43 | newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot)) | 58 | newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot)) |
44 | runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir) | 59 | runCmd('git clone file://%s %s' % (oldreporoot, corecopydir), cwd=templayerdir) |
45 | # Now we need to copy any modified files | 60 | # Now we need to copy any modified files |
46 | # You might ask "why not just copy the entire tree instead of | 61 | # You might ask "why not just copy the entire tree instead of |
47 | # cloning and doing this?" - well, the problem with that is | 62 | # cloning and doing this?" - well, the problem with that is |
@@ -49,11 +64,15 @@ def setUpModule(): | |||
49 | # under COREBASE and we don't want to copy that, so we have | 64 | # under COREBASE and we don't want to copy that, so we have |
50 | # to be selective. | 65 | # to be selective. |
51 | result = runCmd('git status --porcelain', cwd=oldreporoot) | 66 | result = runCmd('git status --porcelain', cwd=oldreporoot) |
67 | |||
68 | # Also copy modifications to the 'scripts/' directory | ||
69 | canonical_layerpath_scripts = os.path.normpath(canonical_layerpath + "../scripts") | ||
70 | |||
52 | for line in result.output.splitlines(): | 71 | for line in result.output.splitlines(): |
53 | if line.startswith(' M ') or line.startswith('?? '): | 72 | if line.startswith(' M ') or line.startswith('?? '): |
54 | relpth = line.split()[1] | 73 | relpth = line.split()[1] |
55 | pth = os.path.join(oldreporoot, relpth) | 74 | pth = os.path.join(oldreporoot, relpth) |
56 | if pth.startswith(canonical_layerpath): | 75 | if pth.startswith(canonical_layerpath) or pth.startswith(canonical_layerpath_scripts): |
57 | if relpth.endswith('/'): | 76 | if relpth.endswith('/'): |
58 | destdir = os.path.join(corecopydir, relpth) | 77 | destdir = os.path.join(corecopydir, relpth) |
59 | # avoid race condition by not copying .pyc files YPBZ#13421,13803 | 78 | # avoid race condition by not copying .pyc files YPBZ#13421,13803 |
@@ -80,32 +99,15 @@ def tearDownModule(): | |||
80 | bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb) | 99 | bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb) |
81 | shutil.rmtree(templayerdir) | 100 | shutil.rmtree(templayerdir) |
82 | 101 | ||
83 | class DevtoolBase(OESelftestTestCase): | 102 | class DevtoolTestCase(OESelftestTestCase): |
84 | |||
85 | @classmethod | ||
86 | def setUpClass(cls): | ||
87 | super(DevtoolBase, cls).setUpClass() | ||
88 | bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR']) | ||
89 | cls.original_sstate = bb_vars['SSTATE_DIR'] | ||
90 | cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool') | ||
91 | cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate | ||
92 | cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n' | ||
93 | % cls.original_sstate) | ||
94 | |||
95 | @classmethod | ||
96 | def tearDownClass(cls): | ||
97 | cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate) | ||
98 | runCmd('rm -rf %s' % cls.devtool_sstate) | ||
99 | super(DevtoolBase, cls).tearDownClass() | ||
100 | 103 | ||
101 | def setUp(self): | 104 | def setUp(self): |
102 | """Test case setup function""" | 105 | """Test case setup function""" |
103 | super(DevtoolBase, self).setUp() | 106 | super(DevtoolTestCase, self).setUp() |
104 | self.workspacedir = os.path.join(self.builddir, 'workspace') | 107 | self.workspacedir = os.path.join(self.builddir, 'workspace') |
105 | self.assertTrue(not os.path.exists(self.workspacedir), | 108 | self.assertTrue(not os.path.exists(self.workspacedir), |
106 | 'This test cannot be run with a workspace directory ' | 109 | 'This test cannot be run with a workspace directory ' |
107 | 'under the build directory') | 110 | 'under the build directory') |
108 | self.append_config(self.sstate_conf) | ||
109 | 111 | ||
110 | def _check_src_repo(self, repo_dir): | 112 | def _check_src_repo(self, repo_dir): |
111 | """Check srctree git repository""" | 113 | """Check srctree git repository""" |
@@ -152,7 +154,7 @@ class DevtoolBase(OESelftestTestCase): | |||
152 | value = invalue | 154 | value = invalue |
153 | invar = None | 155 | invar = None |
154 | elif '=' in line: | 156 | elif '=' in line: |
155 | splitline = line.split('=', 1) | 157 | splitline = re.split(r"[?+:]*=[+]?", line, 1) |
156 | var = splitline[0].rstrip() | 158 | var = splitline[0].rstrip() |
157 | value = splitline[1].strip().strip('"') | 159 | value = splitline[1].strip().strip('"') |
158 | if value.endswith('\\'): | 160 | if value.endswith('\\'): |
@@ -235,6 +237,103 @@ class DevtoolBase(OESelftestTestCase): | |||
235 | filelist.append(' '.join(splitline)) | 237 | filelist.append(' '.join(splitline)) |
236 | return filelist | 238 | return filelist |
237 | 239 | ||
240 | def _check_diff(self, diffoutput, addlines, removelines): | ||
241 | """Check output from 'git diff' matches expectation""" | ||
242 | remaining_addlines = addlines[:] | ||
243 | remaining_removelines = removelines[:] | ||
244 | for line in diffoutput.splitlines(): | ||
245 | if line.startswith('+++') or line.startswith('---'): | ||
246 | continue | ||
247 | elif line.startswith('+'): | ||
248 | matched = False | ||
249 | for item in addlines: | ||
250 | if re.match(item, line[1:].strip()): | ||
251 | matched = True | ||
252 | remaining_addlines.remove(item) | ||
253 | break | ||
254 | self.assertTrue(matched, 'Unexpected diff add line: %s' % line) | ||
255 | elif line.startswith('-'): | ||
256 | matched = False | ||
257 | for item in removelines: | ||
258 | if re.match(item, line[1:].strip()): | ||
259 | matched = True | ||
260 | remaining_removelines.remove(item) | ||
261 | break | ||
262 | self.assertTrue(matched, 'Unexpected diff remove line: %s' % line) | ||
263 | if remaining_addlines: | ||
264 | self.fail('Expected added lines not found: %s' % remaining_addlines) | ||
265 | if remaining_removelines: | ||
266 | self.fail('Expected removed lines not found: %s' % remaining_removelines) | ||
267 | |||
268 | def _check_runqemu_prerequisites(self): | ||
269 | """Check runqemu is available | ||
270 | |||
271 | Whilst some tests would seemingly be better placed as a runtime test, | ||
272 | unfortunately the runtime tests run under bitbake and you can't run | ||
273 | devtool within bitbake (since devtool needs to run bitbake itself). | ||
274 | Additionally we are testing build-time functionality as well, so | ||
275 | really this has to be done as an oe-selftest test. | ||
276 | """ | ||
277 | machine = get_bb_var('MACHINE') | ||
278 | if not machine.startswith('qemu'): | ||
279 | self.skipTest('This test only works with qemu machines') | ||
280 | if not os.path.exists('/etc/runqemu-nosudo'): | ||
281 | self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
282 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True) | ||
283 | if result.status != 0: | ||
284 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True) | ||
285 | if result.status != 0: | ||
286 | self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output) | ||
287 | for line in result.output.splitlines(): | ||
288 | if line.startswith('tap'): | ||
289 | break | ||
290 | else: | ||
291 | self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
292 | |||
293 | def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri, srcrev=None): | ||
294 | self.track_for_cleanup(self.workspacedir) | ||
295 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
296 | command = 'devtool add --version %s %s %s' % (version, pn, git_url) | ||
297 | if srcrev : | ||
298 | command += ' --srcrev %s' %srcrev | ||
299 | result = runCmd(command) | ||
300 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created') | ||
301 | # Check the recipe name is correct | ||
302 | recipefile = get_bb_var('FILE', pn) | ||
303 | self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named') | ||
304 | self.assertIn(recipefile, result.output) | ||
305 | # Test devtool status | ||
306 | result = runCmd('devtool status') | ||
307 | self.assertIn(pn, result.output) | ||
308 | self.assertIn(recipefile, result.output) | ||
309 | checkvars = {} | ||
310 | checkvars['SRC_URI'] = resulting_src_uri | ||
311 | self._test_recipe_contents(recipefile, checkvars, []) | ||
312 | |||
313 | class DevtoolBase(DevtoolTestCase): | ||
314 | |||
315 | @classmethod | ||
316 | def setUpClass(cls): | ||
317 | super(DevtoolBase, cls).setUpClass() | ||
318 | bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR']) | ||
319 | cls.original_sstate = bb_vars['SSTATE_DIR'] | ||
320 | cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool') | ||
321 | cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate | ||
322 | cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n' | ||
323 | % cls.original_sstate) | ||
324 | cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yoctoproject.org:8686"\n') | ||
325 | |||
326 | @classmethod | ||
327 | def tearDownClass(cls): | ||
328 | cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate) | ||
329 | runCmd('rm -rf %s' % cls.devtool_sstate) | ||
330 | super(DevtoolBase, cls).tearDownClass() | ||
331 | |||
332 | def setUp(self): | ||
333 | """Test case setup function""" | ||
334 | super(DevtoolBase, self).setUp() | ||
335 | self.append_config(self.sstate_conf) | ||
336 | |||
238 | 337 | ||
239 | class DevtoolTests(DevtoolBase): | 338 | class DevtoolTests(DevtoolBase): |
240 | 339 | ||
@@ -304,6 +403,38 @@ class DevtoolAddTests(DevtoolBase): | |||
304 | bindir = bindir[1:] | 403 | bindir = bindir[1:] |
305 | self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D') | 404 | self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D') |
306 | 405 | ||
406 | def test_devtool_add_binary(self): | ||
407 | # Create a binary package containing a known test file | ||
408 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
409 | self.track_for_cleanup(tempdir) | ||
410 | pn = 'tst-bin' | ||
411 | pv = '1.0' | ||
412 | test_file_dir = "var/lib/%s/" % pn | ||
413 | test_file_name = "test_file" | ||
414 | test_file_content = "TEST CONTENT" | ||
415 | test_file_package_root = os.path.join(tempdir, pn) | ||
416 | test_file_dir_full = os.path.join(test_file_package_root, test_file_dir) | ||
417 | bb.utils.mkdirhier(test_file_dir_full) | ||
418 | with open(os.path.join(test_file_dir_full, test_file_name), "w") as f: | ||
419 | f.write(test_file_content) | ||
420 | bin_package_path = os.path.join(tempdir, "%s.tar.gz" % pn) | ||
421 | runCmd("tar czf %s -C %s ." % (bin_package_path, test_file_package_root)) | ||
422 | |||
423 | # Test devtool add -b on the binary package | ||
424 | self.track_for_cleanup(self.workspacedir) | ||
425 | self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn) | ||
426 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
427 | result = runCmd('devtool add -b %s %s' % (pn, bin_package_path)) | ||
428 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created') | ||
429 | |||
430 | # Build the resulting recipe | ||
431 | result = runCmd('devtool build %s' % pn) | ||
432 | installdir = get_bb_var('D', pn) | ||
433 | self.assertTrue(installdir, 'Could not query installdir variable') | ||
434 | |||
435 | # Check that a known file from the binary package has indeed been installed | ||
436 | self.assertTrue(os.path.isfile(os.path.join(installdir, test_file_dir, test_file_name)), '%s not found in D' % test_file_name) | ||
437 | |||
307 | def test_devtool_add_git_local(self): | 438 | def test_devtool_add_git_local(self): |
308 | # We need dbus built so that DEPENDS recognition works | 439 | # We need dbus built so that DEPENDS recognition works |
309 | bitbake('dbus') | 440 | bitbake('dbus') |
@@ -336,15 +467,32 @@ class DevtoolAddTests(DevtoolBase): | |||
336 | self.assertIn(srcdir, result.output) | 467 | self.assertIn(srcdir, result.output) |
337 | self.assertIn(recipefile, result.output) | 468 | self.assertIn(recipefile, result.output) |
338 | checkvars = {} | 469 | checkvars = {} |
339 | checkvars['LICENSE'] = 'GPLv2' | 470 | checkvars['LICENSE'] = 'GPL-2.0-only' |
340 | checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' | 471 | checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' |
341 | checkvars['S'] = '${WORKDIR}/git' | 472 | checkvars['S'] = None |
342 | checkvars['PV'] = '0.1+git${SRCPV}' | 473 | checkvars['PV'] = '0.1+git' |
343 | checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https' | 474 | checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master' |
344 | checkvars['SRCREV'] = srcrev | 475 | checkvars['SRCREV'] = srcrev |
345 | checkvars['DEPENDS'] = set(['dbus']) | 476 | checkvars['DEPENDS'] = set(['dbus']) |
346 | self._test_recipe_contents(recipefile, checkvars, []) | 477 | self._test_recipe_contents(recipefile, checkvars, []) |
347 | 478 | ||
479 | def test_devtool_add_git_style1(self): | ||
480 | version = 'v3.1.0' | ||
481 | pn = 'mbedtls' | ||
482 | # this will trigger reformat_git_uri with branch parameter in url | ||
483 | git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'" | ||
484 | resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https" | ||
485 | self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri) | ||
486 | |||
487 | def test_devtool_add_git_style2(self): | ||
488 | version = 'v3.1.0' | ||
489 | srcrev = 'v3.1.0' | ||
490 | pn = 'mbedtls' | ||
491 | # this will trigger reformat_git_uri with branch parameter in url | ||
492 | git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'" | ||
493 | resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master" | ||
494 | self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri, srcrev) | ||
495 | |||
348 | def test_devtool_add_library(self): | 496 | def test_devtool_add_library(self): |
349 | # Fetch source | 497 | # Fetch source |
350 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | 498 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') |
@@ -373,7 +521,7 @@ class DevtoolAddTests(DevtoolBase): | |||
373 | recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version) | 521 | recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version) |
374 | result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile) | 522 | result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile) |
375 | with open(recipefile, 'a') as f: | 523 | with open(recipefile, 'a') as f: |
376 | f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n') | 524 | f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n') |
377 | # We don't have the ability to pick up this dependency automatically yet... | 525 | # We don't have the ability to pick up this dependency automatically yet... |
378 | f.write('\nDEPENDS += "libusb1"\n') | 526 | f.write('\nDEPENDS += "libusb1"\n') |
379 | f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n') | 527 | f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n') |
@@ -405,7 +553,7 @@ class DevtoolAddTests(DevtoolBase): | |||
405 | self.track_for_cleanup(self.workspacedir) | 553 | self.track_for_cleanup(self.workspacedir) |
406 | self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) | 554 | self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) |
407 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | 555 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') |
408 | result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) | 556 | result = runCmd('devtool add --no-pypi %s %s -f %s' % (testrecipe, srcdir, url)) |
409 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output) | 557 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output) |
410 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') | 558 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') |
411 | self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created') | 559 | self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created') |
@@ -417,14 +565,14 @@ class DevtoolAddTests(DevtoolBase): | |||
417 | recipefile = get_bb_var('FILE', testrecipe) | 565 | recipefile = get_bb_var('FILE', testrecipe) |
418 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') | 566 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') |
419 | checkvars = {} | 567 | checkvars = {} |
420 | checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}' | 568 | checkvars['S'] = '${UNPACKDIR}/MarkupSafe-${PV}' |
421 | checkvars['SRC_URI'] = url.replace(testver, '${PV}') | 569 | checkvars['SRC_URI'] = url.replace(testver, '${PV}') |
422 | self._test_recipe_contents(recipefile, checkvars, []) | 570 | self._test_recipe_contents(recipefile, checkvars, []) |
423 | # Try with version specified | 571 | # Try with version specified |
424 | result = runCmd('devtool reset -n %s' % testrecipe) | 572 | result = runCmd('devtool reset -n %s' % testrecipe) |
425 | shutil.rmtree(srcdir) | 573 | shutil.rmtree(srcdir) |
426 | fakever = '1.9' | 574 | fakever = '1.9' |
427 | result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever)) | 575 | result = runCmd('devtool add --no-pypi %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever)) |
428 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') | 576 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') |
429 | # Test devtool status | 577 | # Test devtool status |
430 | result = runCmd('devtool status') | 578 | result = runCmd('devtool status') |
@@ -434,7 +582,7 @@ class DevtoolAddTests(DevtoolBase): | |||
434 | recipefile = get_bb_var('FILE', testrecipe) | 582 | recipefile = get_bb_var('FILE', testrecipe) |
435 | self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named') | 583 | self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named') |
436 | checkvars = {} | 584 | checkvars = {} |
437 | checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver | 585 | checkvars['S'] = '${UNPACKDIR}/MarkupSafe-%s' % testver |
438 | checkvars['SRC_URI'] = url | 586 | checkvars['SRC_URI'] = url |
439 | self._test_recipe_contents(recipefile, checkvars, []) | 587 | self._test_recipe_contents(recipefile, checkvars, []) |
440 | 588 | ||
@@ -442,6 +590,7 @@ class DevtoolAddTests(DevtoolBase): | |||
442 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | 590 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') |
443 | self.track_for_cleanup(tempdir) | 591 | self.track_for_cleanup(tempdir) |
444 | url = 'gitsm://git.yoctoproject.org/mraa' | 592 | url = 'gitsm://git.yoctoproject.org/mraa' |
593 | url_branch = '%s;branch=master' % url | ||
445 | checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d' | 594 | checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d' |
446 | testrecipe = 'mraa' | 595 | testrecipe = 'mraa' |
447 | srcdir = os.path.join(tempdir, testrecipe) | 596 | srcdir = os.path.join(tempdir, testrecipe) |
@@ -460,9 +609,9 @@ class DevtoolAddTests(DevtoolBase): | |||
460 | recipefile = get_bb_var('FILE', testrecipe) | 609 | recipefile = get_bb_var('FILE', testrecipe) |
461 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') | 610 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') |
462 | checkvars = {} | 611 | checkvars = {} |
463 | checkvars['S'] = '${WORKDIR}/git' | 612 | checkvars['S'] = None |
464 | checkvars['PV'] = '1.0+git${SRCPV}' | 613 | checkvars['PV'] = '1.0+git' |
465 | checkvars['SRC_URI'] = url | 614 | checkvars['SRC_URI'] = url_branch |
466 | checkvars['SRCREV'] = '${AUTOREV}' | 615 | checkvars['SRCREV'] = '${AUTOREV}' |
467 | self._test_recipe_contents(recipefile, checkvars, []) | 616 | self._test_recipe_contents(recipefile, checkvars, []) |
468 | # Try with revision and version specified | 617 | # Try with revision and version specified |
@@ -479,9 +628,9 @@ class DevtoolAddTests(DevtoolBase): | |||
479 | recipefile = get_bb_var('FILE', testrecipe) | 628 | recipefile = get_bb_var('FILE', testrecipe) |
480 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') | 629 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') |
481 | checkvars = {} | 630 | checkvars = {} |
482 | checkvars['S'] = '${WORKDIR}/git' | 631 | checkvars['S'] = None |
483 | checkvars['PV'] = '1.5+git${SRCPV}' | 632 | checkvars['PV'] = '1.5+git' |
484 | checkvars['SRC_URI'] = url | 633 | checkvars['SRC_URI'] = url_branch |
485 | checkvars['SRCREV'] = checkrev | 634 | checkvars['SRCREV'] = checkrev |
486 | self._test_recipe_contents(recipefile, checkvars, []) | 635 | self._test_recipe_contents(recipefile, checkvars, []) |
487 | 636 | ||
@@ -504,7 +653,7 @@ class DevtoolAddTests(DevtoolBase): | |||
504 | result = runCmd('devtool status') | 653 | result = runCmd('devtool status') |
505 | self.assertIn(testrecipe, result.output) | 654 | self.assertIn(testrecipe, result.output) |
506 | self.assertIn(srcdir, result.output) | 655 | self.assertIn(srcdir, result.output) |
507 | # Check recipe | 656 | # Check recipedevtool add |
508 | recipefile = get_bb_var('FILE', testrecipe) | 657 | recipefile = get_bb_var('FILE', testrecipe) |
509 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') | 658 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') |
510 | checkvars = {} | 659 | checkvars = {} |
@@ -536,6 +685,19 @@ class DevtoolAddTests(DevtoolBase): | |||
536 | # Test devtool build | 685 | # Test devtool build |
537 | result = runCmd('devtool build %s' % pn) | 686 | result = runCmd('devtool build %s' % pn) |
538 | 687 | ||
688 | def test_devtool_add_python_egg_requires(self): | ||
689 | # Fetch source | ||
690 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
691 | self.track_for_cleanup(tempdir) | ||
692 | testver = '0.14.0' | ||
693 | url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver | ||
694 | testrecipe = 'python3-uvicorn' | ||
695 | srcdir = os.path.join(tempdir, testrecipe) | ||
696 | # Test devtool add | ||
697 | self.track_for_cleanup(self.workspacedir) | ||
698 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
699 | result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) | ||
700 | |||
539 | class DevtoolModifyTests(DevtoolBase): | 701 | class DevtoolModifyTests(DevtoolBase): |
540 | 702 | ||
541 | def test_devtool_modify(self): | 703 | def test_devtool_modify(self): |
@@ -595,6 +757,25 @@ class DevtoolModifyTests(DevtoolBase): | |||
595 | result = runCmd('devtool status') | 757 | result = runCmd('devtool status') |
596 | self.assertNotIn('mdadm', result.output) | 758 | self.assertNotIn('mdadm', result.output) |
597 | 759 | ||
760 | def test_devtool_modify_go(self): | ||
761 | import oe.path | ||
762 | from tempfile import TemporaryDirectory | ||
763 | with TemporaryDirectory(prefix='devtoolqa') as tempdir: | ||
764 | self.track_for_cleanup(self.workspacedir) | ||
765 | self.add_command_to_tearDown('bitbake -c clean go-helloworld') | ||
766 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
767 | result = runCmd('devtool modify go-helloworld -x %s' % tempdir) | ||
768 | self.assertExists( | ||
769 | oe.path.join(tempdir, 'src', 'golang.org', 'x', 'example', 'go.mod'), | ||
770 | 'Extracted source could not be found' | ||
771 | ) | ||
772 | self.assertExists( | ||
773 | oe.path.join(self.workspacedir, 'conf', 'layer.conf'), | ||
774 | 'Workspace directory not created' | ||
775 | ) | ||
776 | matches = glob.glob(oe.path.join(self.workspacedir, 'appends', 'go-helloworld_*.bbappend')) | ||
777 | self.assertTrue(matches, 'bbappend not created %s' % result.output) | ||
778 | |||
598 | def test_devtool_buildclean(self): | 779 | def test_devtool_buildclean(self): |
599 | def assertFile(path, *paths): | 780 | def assertFile(path, *paths): |
600 | f = os.path.join(path, *paths) | 781 | f = os.path.join(path, *paths) |
@@ -649,7 +830,7 @@ class DevtoolModifyTests(DevtoolBase): | |||
649 | self.track_for_cleanup(self.workspacedir) | 830 | self.track_for_cleanup(self.workspacedir) |
650 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | 831 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') |
651 | 832 | ||
652 | testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split() | 833 | testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split() |
653 | # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose | 834 | # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose |
654 | result = runCmd('bitbake-layers show-recipes gcc-source*') | 835 | result = runCmd('bitbake-layers show-recipes gcc-source*') |
655 | for line in result.output.splitlines(): | 836 | for line in result.output.splitlines(): |
@@ -697,6 +878,7 @@ class DevtoolModifyTests(DevtoolBase): | |||
697 | 878 | ||
698 | self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) | 879 | self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) |
699 | self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) | 880 | self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) |
881 | |||
700 | def test_devtool_modify_localfiles_only(self): | 882 | def test_devtool_modify_localfiles_only(self): |
701 | # Check preconditions | 883 | # Check preconditions |
702 | testrecipe = 'base-files' | 884 | testrecipe = 'base-files' |
@@ -720,13 +902,8 @@ class DevtoolModifyTests(DevtoolBase): | |||
720 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | 902 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) |
721 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | 903 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') |
722 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | 904 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) |
723 | srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc') | 905 | srcfile = os.path.join(tempdir, 'share/dot.bashrc') |
724 | srclink = os.path.join(tempdir, 'share/dot.bashrc') | ||
725 | self.assertExists(srcfile, 'Extracted source could not be found') | 906 | self.assertExists(srcfile, 'Extracted source could not be found') |
726 | if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink): | ||
727 | correct_symlink = True | ||
728 | self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken') | ||
729 | |||
730 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) | 907 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) |
731 | self.assertTrue(matches, 'bbappend not created') | 908 | self.assertTrue(matches, 'bbappend not created') |
732 | # Test devtool status | 909 | # Test devtool status |
@@ -763,6 +940,122 @@ class DevtoolModifyTests(DevtoolBase): | |||
763 | # Try building | 940 | # Try building |
764 | bitbake(testrecipe) | 941 | bitbake(testrecipe) |
765 | 942 | ||
943 | def test_devtool_modify_git_no_extract(self): | ||
944 | # Check preconditions | ||
945 | testrecipe = 'psplash' | ||
946 | src_uri = get_bb_var('SRC_URI', testrecipe) | ||
947 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) | ||
948 | # Clean up anything in the workdir/sysroot/sstate cache | ||
949 | bitbake('%s -c cleansstate' % testrecipe) | ||
950 | # Try modifying a recipe | ||
951 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
952 | self.track_for_cleanup(tempdir) | ||
953 | self.track_for_cleanup(self.workspacedir) | ||
954 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
955 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
956 | result = runCmd('git clone https://git.yoctoproject.org/psplash %s && devtool modify -n %s %s' % (tempdir, testrecipe, tempdir)) | ||
957 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output) | ||
958 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend')) | ||
959 | self.assertTrue(matches, 'bbappend not created') | ||
960 | # Test devtool status | ||
961 | result = runCmd('devtool status') | ||
962 | self.assertIn(testrecipe, result.output) | ||
963 | self.assertIn(tempdir, result.output) | ||
964 | |||
965 | def test_devtool_modify_git_crates_subpath(self): | ||
966 | # This tests two things in devtool context: | ||
967 | # - that we support local git dependencies for cargo based recipe | ||
968 | # - that we support patches in SRC_URI when git url contains subpath parameter | ||
969 | |||
970 | # Check preconditions: | ||
971 | # recipe inherits cargo | ||
972 | # git:// uri with a subpath as the main package | ||
973 | # some crate:// in SRC_URI | ||
974 | # others git:// in SRC_URI | ||
975 | # cointains a patch | ||
976 | testrecipe = 'hello-rs' | ||
977 | bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'UNPACKDIR', 'CARGO_HOME'], testrecipe) | ||
978 | recipefile = bb_vars['FILE'] | ||
979 | unpackdir = bb_vars['UNPACKDIR'] | ||
980 | cargo_home = bb_vars['CARGO_HOME'] | ||
981 | src_uri = bb_vars['SRC_URI'].split() | ||
982 | self.assertTrue(src_uri[0].startswith('git://'), | ||
983 | 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe) | ||
984 | self.assertIn(';subpath=', src_uri[0], | ||
985 | 'This test expects the %s recipe to have a git uri with subpath' % testrecipe) | ||
986 | self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]), | ||
987 | 'This test expects the %s recipe to have some crates in its src uris' % testrecipe) | ||
988 | self.assertGreaterEqual(sum(map(lambda x:x.startswith('git://'), src_uri)), 2, | ||
989 | 'This test expects the %s recipe to have several git:// uris' % testrecipe) | ||
990 | self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]), | ||
991 | 'This test expects the %s recipe to have a patch in its src uris' % testrecipe) | ||
992 | |||
993 | self._test_recipe_contents(recipefile, {}, ['ptest-cargo']) | ||
994 | |||
995 | # Clean up anything in the workdir/sysroot/sstate cache | ||
996 | bitbake('%s -c cleansstate' % testrecipe) | ||
997 | # Try modifying a recipe | ||
998 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
999 | self.track_for_cleanup(tempdir) | ||
1000 | self.track_for_cleanup(self.workspacedir) | ||
1001 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
1002 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1003 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
1004 | self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found') | ||
1005 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output) | ||
1006 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) | ||
1007 | self.assertTrue(matches, 'bbappend not created') | ||
1008 | # Test devtool status | ||
1009 | result = runCmd('devtool status') | ||
1010 | self.assertIn(testrecipe, result.output) | ||
1011 | self.assertIn(tempdir, result.output) | ||
1012 | # Check git repo | ||
1013 | self._check_src_repo(tempdir) | ||
1014 | # Check that the patch is correctly applied. | ||
1015 | # The last commit message in the tree must contain the following note: | ||
1016 | # Notes (devtool): | ||
1017 | # original patch: <patchname> | ||
1018 | # .. | ||
1019 | patchname = None | ||
1020 | for uri in src_uri: | ||
1021 | if uri.startswith('file://') and '.patch' in uri: | ||
1022 | patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch' | ||
1023 | self.assertIsNotNone(patchname) | ||
1024 | result = runCmd('git -C %s log -1' % tempdir) | ||
1025 | self.assertIn("Notes (devtool):\n original patch: %s" % patchname, result.output) | ||
1026 | |||
1027 | # Configure the recipe to check that the git dependencies are correctly patched in cargo config | ||
1028 | bitbake('-c configure %s' % testrecipe) | ||
1029 | |||
1030 | cargo_config_path = os.path.join(cargo_home, 'config.toml') | ||
1031 | with open(cargo_config_path, "r") as f: | ||
1032 | cargo_config_contents = [line.strip('\n') for line in f.readlines()] | ||
1033 | |||
1034 | # Get back git dependencies of the recipe (ignoring the main one) | ||
1035 | # and check that they are all correctly patched to be fetched locally | ||
1036 | git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:] | ||
1037 | for git_dep in git_deps: | ||
1038 | raw_url, _, raw_parms = git_dep.partition(";") | ||
1039 | parms = {} | ||
1040 | for parm in raw_parms.split(";"): | ||
1041 | name_parm, _, value_parm = parm.partition('=') | ||
1042 | parms[name_parm]=value_parm | ||
1043 | self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter') | ||
1044 | self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter') | ||
1045 | self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter') | ||
1046 | self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter') | ||
1047 | self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"') | ||
1048 | raw_url = raw_url.replace("git://", '%s://' % parms['protocol']) | ||
1049 | patch_line = '[patch."%s"]' % raw_url | ||
1050 | path_patched = os.path.join(unpackdir, parms['destsuffix']) | ||
1051 | path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched) | ||
1052 | # Would have been better to use tomllib to read this file :/ | ||
1053 | self.assertIn(patch_line, cargo_config_contents) | ||
1054 | self.assertIn(path_override_line, cargo_config_contents) | ||
1055 | |||
1056 | # Try to package the recipe | ||
1057 | bitbake('-c package_qa %s' % testrecipe) | ||
1058 | |||
766 | def test_devtool_modify_localfiles(self): | 1059 | def test_devtool_modify_localfiles(self): |
767 | # Check preconditions | 1060 | # Check preconditions |
768 | testrecipe = 'lighttpd' | 1061 | testrecipe = 'lighttpd' |
@@ -828,12 +1121,43 @@ class DevtoolModifyTests(DevtoolBase): | |||
828 | runCmd('git -C %s checkout %s' % (tempdir, branch)) | 1121 | runCmd('git -C %s checkout %s' % (tempdir, branch)) |
829 | with open(source, "rt") as f: | 1122 | with open(source, "rt") as f: |
830 | content = f.read() | 1123 | content = f.read() |
831 | self.assertEquals(content, expected) | 1124 | self.assertEqual(content, expected) |
832 | check('devtool', 'This is a test for something\n') | 1125 | if self.td["MACHINE"] == "qemux86": |
1126 | check('devtool', 'This is a test for qemux86\n') | ||
1127 | elif self.td["MACHINE"] == "qemuarm": | ||
1128 | check('devtool', 'This is a test for qemuarm\n') | ||
1129 | else: | ||
1130 | check('devtool', 'This is a test for something\n') | ||
833 | check('devtool-no-overrides', 'This is a test for something\n') | 1131 | check('devtool-no-overrides', 'This is a test for something\n') |
834 | check('devtool-override-qemuarm', 'This is a test for qemuarm\n') | 1132 | check('devtool-override-qemuarm', 'This is a test for qemuarm\n') |
835 | check('devtool-override-qemux86', 'This is a test for qemux86\n') | 1133 | check('devtool-override-qemux86', 'This is a test for qemux86\n') |
836 | 1134 | ||
1135 | def test_devtool_modify_multiple_sources(self): | ||
1136 | # This test check that recipes fetching several sources can be used with devtool modify/build | ||
1137 | # Check preconditions | ||
1138 | testrecipe = 'bzip2' | ||
1139 | src_uri = get_bb_var('SRC_URI', testrecipe) | ||
1140 | src1 = 'https://' in src_uri | ||
1141 | src2 = 'git://' in src_uri | ||
1142 | self.assertTrue(src1 and src2, 'This test expects the %s recipe to fetch both a git source and a tarball and it seems that it no longer does' % testrecipe) | ||
1143 | # Clean up anything in the workdir/sysroot/sstate cache | ||
1144 | bitbake('%s -c cleansstate' % testrecipe) | ||
1145 | # Try modifying a recipe | ||
1146 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1147 | self.track_for_cleanup(tempdir) | ||
1148 | self.track_for_cleanup(self.workspacedir) | ||
1149 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
1150 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1151 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
1152 | self.assertEqual(result.status, 0, "Could not modify recipe %s. Output: %s" % (testrecipe, result.output)) | ||
1153 | # Test devtool status | ||
1154 | result = runCmd('devtool status') | ||
1155 | self.assertIn(testrecipe, result.output) | ||
1156 | self.assertIn(tempdir, result.output) | ||
1157 | # Try building | ||
1158 | result = bitbake(testrecipe) | ||
1159 | self.assertEqual(result.status, 0, "Bitbake failed, exit code %s, output %s" % (result.status, result.output)) | ||
1160 | |||
837 | class DevtoolUpdateTests(DevtoolBase): | 1161 | class DevtoolUpdateTests(DevtoolBase): |
838 | 1162 | ||
839 | def test_devtool_update_recipe(self): | 1163 | def test_devtool_update_recipe(self): |
@@ -861,16 +1185,20 @@ class DevtoolUpdateTests(DevtoolBase): | |||
861 | result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir) | 1185 | result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir) |
862 | result = runCmd('git add devtool-new-file', cwd=tempdir) | 1186 | result = runCmd('git add devtool-new-file', cwd=tempdir) |
863 | result = runCmd('git commit -m "Add a new file"', cwd=tempdir) | 1187 | result = runCmd('git commit -m "Add a new file"', cwd=tempdir) |
864 | self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | 1188 | cleanup_cmd = 'cd %s; rm %s/*.patch; git add %s; git checkout %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)) |
1189 | self.add_command_to_tearDown(cleanup_cmd) | ||
865 | result = runCmd('devtool update-recipe %s' % testrecipe) | 1190 | result = runCmd('devtool update-recipe %s' % testrecipe) |
1191 | result = runCmd('git add minicom', cwd=os.path.dirname(recipefile)) | ||
866 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | 1192 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), |
867 | ('??', '.*/0001-Change-the-README.patch$'), | 1193 | ('A ', '.*/0001-Change-the-README.patch$'), |
868 | ('??', '.*/0002-Add-a-new-file.patch$')] | 1194 | ('A ', '.*/0002-Add-a-new-file.patch$')] |
869 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | 1195 | self._check_repo_status(os.path.dirname(recipefile), expected_status) |
1196 | result = runCmd(cleanup_cmd) | ||
1197 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
870 | 1198 | ||
871 | def test_devtool_update_recipe_git(self): | 1199 | def test_devtool_update_recipe_git(self): |
872 | # Check preconditions | 1200 | # Check preconditions |
873 | testrecipe = 'mtd-utils' | 1201 | testrecipe = 'mtd-utils-selftest' |
874 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | 1202 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) |
875 | recipefile = bb_vars['FILE'] | 1203 | recipefile = bb_vars['FILE'] |
876 | src_uri = bb_vars['SRC_URI'] | 1204 | src_uri = bb_vars['SRC_URI'] |
@@ -904,28 +1232,12 @@ class DevtoolUpdateTests(DevtoolBase): | |||
904 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | 1232 | self._check_repo_status(os.path.dirname(recipefile), expected_status) |
905 | 1233 | ||
906 | result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) | 1234 | result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) |
907 | addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"'] | 1235 | addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"'] |
908 | srcurilines = src_uri.split() | 1236 | srcurilines = src_uri.split() |
909 | srcurilines[0] = 'SRC_URI = "' + srcurilines[0] | 1237 | srcurilines[0] = 'SRC_URI = "' + srcurilines[0] |
910 | srcurilines.append('"') | 1238 | srcurilines.append('"') |
911 | removelines = ['SRCREV = ".*"'] + srcurilines | 1239 | removelines = ['SRCREV = ".*"'] + srcurilines |
912 | for line in result.output.splitlines(): | 1240 | self._check_diff(result.output, addlines, removelines) |
913 | if line.startswith('+++') or line.startswith('---'): | ||
914 | continue | ||
915 | elif line.startswith('+'): | ||
916 | matched = False | ||
917 | for item in addlines: | ||
918 | if re.match(item, line[1:].strip()): | ||
919 | matched = True | ||
920 | break | ||
921 | self.assertTrue(matched, 'Unexpected diff add line: %s' % line) | ||
922 | elif line.startswith('-'): | ||
923 | matched = False | ||
924 | for item in removelines: | ||
925 | if re.match(item, line[1:].strip()): | ||
926 | matched = True | ||
927 | break | ||
928 | self.assertTrue(matched, 'Unexpected diff remove line: %s' % line) | ||
929 | # Now try with auto mode | 1241 | # Now try with auto mode |
930 | runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile))) | 1242 | runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile))) |
931 | result = runCmd('devtool update-recipe %s' % testrecipe) | 1243 | result = runCmd('devtool update-recipe %s' % testrecipe) |
@@ -939,7 +1251,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
939 | 1251 | ||
940 | def test_devtool_update_recipe_append(self): | 1252 | def test_devtool_update_recipe_append(self): |
941 | # Check preconditions | 1253 | # Check preconditions |
942 | testrecipe = 'mdadm' | 1254 | testrecipe = 'minicom' |
943 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | 1255 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) |
944 | recipefile = bb_vars['FILE'] | 1256 | recipefile = bb_vars['FILE'] |
945 | src_uri = bb_vars['SRC_URI'] | 1257 | src_uri = bb_vars['SRC_URI'] |
@@ -957,7 +1269,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
957 | # Check git repo | 1269 | # Check git repo |
958 | self._check_src_repo(tempsrcdir) | 1270 | self._check_src_repo(tempsrcdir) |
959 | # Add a commit | 1271 | # Add a commit |
960 | result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir) | 1272 | result = runCmd('echo "Additional line" >> README', cwd=tempsrcdir) |
961 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) | 1273 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) |
962 | self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe)) | 1274 | self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe)) |
963 | # Create a temporary layer and add it to bblayers.conf | 1275 | # Create a temporary layer and add it to bblayers.conf |
@@ -975,7 +1287,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
975 | self.assertExists(patchfile, 'Patch file not created') | 1287 | self.assertExists(patchfile, 'Patch file not created') |
976 | 1288 | ||
977 | # Check bbappend contents | 1289 | # Check bbappend contents |
978 | expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', | 1290 | expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', |
979 | '\n', | 1291 | '\n', |
980 | 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n', | 1292 | 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n', |
981 | '\n'] | 1293 | '\n'] |
@@ -987,15 +1299,16 @@ class DevtoolUpdateTests(DevtoolBase): | |||
987 | with open(bbappendfile, 'r') as f: | 1299 | with open(bbappendfile, 'r') as f: |
988 | self.assertEqual(expectedlines, f.readlines()) | 1300 | self.assertEqual(expectedlines, f.readlines()) |
989 | # Drop new commit and check patch gets deleted | 1301 | # Drop new commit and check patch gets deleted |
990 | result = runCmd('git reset HEAD^', cwd=tempsrcdir) | 1302 | result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir) |
991 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | 1303 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) |
992 | self.assertNotExists(patchfile, 'Patch file not deleted') | 1304 | self.assertNotExists(patchfile, 'Patch file not deleted') |
993 | expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', | 1305 | expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', |
994 | '\n'] | 1306 | '\n'] |
995 | with open(bbappendfile, 'r') as f: | 1307 | with open(bbappendfile, 'r') as f: |
996 | self.assertEqual(expectedlines2, f.readlines()) | 1308 | self.assertEqual(expectedlines2, f.readlines()) |
997 | # Put commit back and check we can run it if layer isn't in bblayers.conf | 1309 | # Put commit back and check we can run it if layer isn't in bblayers.conf |
998 | os.remove(bbappendfile) | 1310 | os.remove(bbappendfile) |
1311 | result = runCmd('echo "Additional line" >> README', cwd=tempsrcdir) | ||
999 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) | 1312 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) |
1000 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) | 1313 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) |
1001 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | 1314 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) |
@@ -1007,10 +1320,11 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1007 | 1320 | ||
1008 | def test_devtool_update_recipe_append_git(self): | 1321 | def test_devtool_update_recipe_append_git(self): |
1009 | # Check preconditions | 1322 | # Check preconditions |
1010 | testrecipe = 'mtd-utils' | 1323 | testrecipe = 'mtd-utils-selftest' |
1011 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | 1324 | bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe) |
1012 | recipefile = bb_vars['FILE'] | 1325 | recipefile = bb_vars['FILE'] |
1013 | src_uri = bb_vars['SRC_URI'] | 1326 | src_uri = bb_vars['SRC_URI'] |
1327 | corenames = bb_vars['LAYERSERIES_CORENAMES'] | ||
1014 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) | 1328 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) |
1015 | for entry in src_uri.split(): | 1329 | for entry in src_uri.split(): |
1016 | if entry.startswith('git://'): | 1330 | if entry.startswith('git://'): |
@@ -1041,7 +1355,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1041 | f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n') | 1355 | f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n') |
1042 | f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n') | 1356 | f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n') |
1043 | f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n') | 1357 | f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n') |
1044 | f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n') | 1358 | f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames) |
1045 | self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir) | 1359 | self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir) |
1046 | result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir) | 1360 | result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir) |
1047 | # Create the bbappend | 1361 | # Create the bbappend |
@@ -1069,7 +1383,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1069 | with open(bbappendfile, 'r') as f: | 1383 | with open(bbappendfile, 'r') as f: |
1070 | self.assertEqual(expectedlines, set(f.readlines())) | 1384 | self.assertEqual(expectedlines, set(f.readlines())) |
1071 | # Drop new commit and check SRCREV changes | 1385 | # Drop new commit and check SRCREV changes |
1072 | result = runCmd('git reset HEAD^', cwd=tempsrcdir) | 1386 | result = runCmd('git reset HEAD^ --hard', cwd=tempsrcdir) |
1073 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | 1387 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) |
1074 | self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created') | 1388 | self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created') |
1075 | result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) | 1389 | result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) |
@@ -1081,6 +1395,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1081 | self.assertEqual(expectedlines, set(f.readlines())) | 1395 | self.assertEqual(expectedlines, set(f.readlines())) |
1082 | # Put commit back and check we can run it if layer isn't in bblayers.conf | 1396 | # Put commit back and check we can run it if layer isn't in bblayers.conf |
1083 | os.remove(bbappendfile) | 1397 | os.remove(bbappendfile) |
1398 | result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir) | ||
1084 | result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) | 1399 | result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) |
1085 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) | 1400 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) |
1086 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | 1401 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) |
@@ -1112,22 +1427,39 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1112 | # Try building just to ensure we haven't broken that | 1427 | # Try building just to ensure we haven't broken that |
1113 | bitbake("%s" % testrecipe) | 1428 | bitbake("%s" % testrecipe) |
1114 | # Edit / commit local source | 1429 | # Edit / commit local source |
1115 | runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir) | 1430 | runCmd('echo "/* Foobar */" >> makedevs.c', cwd=tempdir) |
1116 | runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) | 1431 | runCmd('echo "Foo" > new-local', cwd=tempdir) |
1117 | runCmd('echo "Bar" > new-file', cwd=tempdir) | 1432 | runCmd('echo "Bar" > new-file', cwd=tempdir) |
1118 | runCmd('git add new-file', cwd=tempdir) | 1433 | runCmd('git add new-file', cwd=tempdir) |
1119 | runCmd('git commit -m "Add new file"', cwd=tempdir) | 1434 | runCmd('git commit -m "Add new file"', cwd=tempdir) |
1120 | self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' % | 1435 | runCmd('git add new-local', cwd=tempdir) |
1121 | os.path.dirname(recipefile)) | ||
1122 | runCmd('devtool update-recipe %s' % testrecipe) | 1436 | runCmd('devtool update-recipe %s' % testrecipe) |
1123 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | 1437 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), |
1124 | (' M', '.*/makedevs/makedevs.c$'), | 1438 | (' M', '.*/makedevs/makedevs.c$'), |
1125 | ('??', '.*/makedevs/new-local$'), | 1439 | ('??', '.*/makedevs/new-local$'), |
1126 | ('??', '.*/makedevs/0001-Add-new-file.patch$')] | 1440 | ('??', '.*/makedevs/0001-Add-new-file.patch$')] |
1127 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | 1441 | self._check_repo_status(os.path.dirname(recipefile), expected_status) |
1128 | 1442 | # Now try to update recipe in another layer, so first, clean it | |
1129 | def test_devtool_update_recipe_local_files_2(self): | 1443 | runCmd('cd %s; git clean -fd .; git checkout .' % os.path.dirname(recipefile)) |
1130 | """Check local source files support when oe-local-files is in Git""" | 1444 | # Create a temporary layer and add it to bblayers.conf |
1445 | self._create_temp_layer(templayerdir, True, 'templayer') | ||
1446 | # Update recipe in templayer | ||
1447 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | ||
1448 | self.assertNotIn('WARNING:', result.output) | ||
1449 | # Check recipe is still clean | ||
1450 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
1451 | splitpath = os.path.dirname(recipefile).split(os.sep) | ||
1452 | appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1]) | ||
1453 | bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir) | ||
1454 | patchfile = os.path.join(appenddir, testrecipe, '0001-Add-new-file.patch') | ||
1455 | new_local_file = os.path.join(appenddir, testrecipe, 'new_local') | ||
1456 | local_file = os.path.join(appenddir, testrecipe, 'makedevs.c') | ||
1457 | self.assertExists(patchfile, 'Patch file 0001-Add-new-file.patch not created') | ||
1458 | self.assertExists(local_file, 'File makedevs.c not created') | ||
1459 | self.assertExists(patchfile, 'File new_local not created') | ||
1460 | |||
1461 | def _test_devtool_update_recipe_local_files_2(self): | ||
1462 | """Check local source files support when editing local files in Git""" | ||
1131 | testrecipe = 'devtool-test-local' | 1463 | testrecipe = 'devtool-test-local' |
1132 | recipefile = get_bb_var('FILE', testrecipe) | 1464 | recipefile = get_bb_var('FILE', testrecipe) |
1133 | recipedir = os.path.dirname(recipefile) | 1465 | recipedir = os.path.dirname(recipefile) |
@@ -1142,17 +1474,13 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1142 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | 1474 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) |
1143 | # Check git repo | 1475 | # Check git repo |
1144 | self._check_src_repo(tempdir) | 1476 | self._check_src_repo(tempdir) |
1145 | # Add oe-local-files to Git | ||
1146 | runCmd('rm oe-local-files/.gitignore', cwd=tempdir) | ||
1147 | runCmd('git add oe-local-files', cwd=tempdir) | ||
1148 | runCmd('git commit -m "Add local sources"', cwd=tempdir) | ||
1149 | # Edit / commit local sources | 1477 | # Edit / commit local sources |
1150 | runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir) | 1478 | runCmd('echo "# Foobar" >> file1', cwd=tempdir) |
1151 | runCmd('git commit -am "Edit existing file"', cwd=tempdir) | 1479 | runCmd('git commit -am "Edit existing file"', cwd=tempdir) |
1152 | runCmd('git rm oe-local-files/file2', cwd=tempdir) | 1480 | runCmd('git rm file2', cwd=tempdir) |
1153 | runCmd('git commit -m"Remove file"', cwd=tempdir) | 1481 | runCmd('git commit -m"Remove file"', cwd=tempdir) |
1154 | runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) | 1482 | runCmd('echo "Foo" > new-local', cwd=tempdir) |
1155 | runCmd('git add oe-local-files/new-local', cwd=tempdir) | 1483 | runCmd('git add new-local', cwd=tempdir) |
1156 | runCmd('git commit -m "Add new local file"', cwd=tempdir) | 1484 | runCmd('git commit -m "Add new local file"', cwd=tempdir) |
1157 | runCmd('echo "Gar" > new-file', cwd=tempdir) | 1485 | runCmd('echo "Gar" > new-file', cwd=tempdir) |
1158 | runCmd('git add new-file', cwd=tempdir) | 1486 | runCmd('git add new-file', cwd=tempdir) |
@@ -1161,7 +1489,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1161 | os.path.dirname(recipefile)) | 1489 | os.path.dirname(recipefile)) |
1162 | # Checkout unmodified file to working copy -> devtool should still pick | 1490 | # Checkout unmodified file to working copy -> devtool should still pick |
1163 | # the modified version from HEAD | 1491 | # the modified version from HEAD |
1164 | runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir) | 1492 | runCmd('git checkout HEAD^ -- file1', cwd=tempdir) |
1165 | runCmd('devtool update-recipe %s' % testrecipe) | 1493 | runCmd('devtool update-recipe %s' % testrecipe) |
1166 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | 1494 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), |
1167 | (' M', '.*/file1$'), | 1495 | (' M', '.*/file1$'), |
@@ -1236,7 +1564,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1236 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | 1564 | # (don't bother with cleaning the recipe on teardown, we won't be building it) |
1237 | result = runCmd('devtool modify %s' % testrecipe) | 1565 | result = runCmd('devtool modify %s' % testrecipe) |
1238 | # Modify one file | 1566 | # Modify one file |
1239 | runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files')) | 1567 | runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe)) |
1240 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | 1568 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) |
1241 | result = runCmd('devtool update-recipe %s' % testrecipe) | 1569 | result = runCmd('devtool update-recipe %s' % testrecipe) |
1242 | expected_status = [(' M', '.*/%s/file2$' % testrecipe)] | 1570 | expected_status = [(' M', '.*/%s/file2$' % testrecipe)] |
@@ -1259,7 +1587,7 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1259 | # Modify one file | 1587 | # Modify one file |
1260 | srctree = os.path.join(self.workspacedir, 'sources', testrecipe) | 1588 | srctree = os.path.join(self.workspacedir, 'sources', testrecipe) |
1261 | runCmd('echo "Another line" >> README', cwd=srctree) | 1589 | runCmd('echo "Another line" >> README', cwd=srctree) |
1262 | runCmd('git commit -a --amend --no-edit', cwd=srctree) | 1590 | runCmd('git commit -a --amend --no-edit --no-verify', cwd=srctree) |
1263 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | 1591 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) |
1264 | result = runCmd('devtool update-recipe %s' % testrecipe) | 1592 | result = runCmd('devtool update-recipe %s' % testrecipe) |
1265 | expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)] | 1593 | expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)] |
@@ -1295,6 +1623,121 @@ class DevtoolUpdateTests(DevtoolBase): | |||
1295 | expected_status = [] | 1623 | expected_status = [] |
1296 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | 1624 | self._check_repo_status(os.path.dirname(recipefile), expected_status) |
1297 | 1625 | ||
1626 | def test_devtool_finish_modify_git_subdir(self): | ||
1627 | # Check preconditions | ||
1628 | testrecipe = 'dos2unix' | ||
1629 | self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n') | ||
1630 | bb_vars = get_bb_vars(['SRC_URI', 'S', 'UNPACKDIR', 'FILE', 'BB_GIT_DEFAULT_DESTSUFFIX'], testrecipe) | ||
1631 | self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe) | ||
1632 | unpackdir_git = '%s/%s/' % (bb_vars['UNPACKDIR'], bb_vars['BB_GIT_DEFAULT_DESTSUFFIX']) | ||
1633 | if not bb_vars['S'].startswith(unpackdir_git): | ||
1634 | self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe) | ||
1635 | subdir = bb_vars['S'].split(unpackdir_git, 1)[1] | ||
1636 | # Clean up anything in the workdir/sysroot/sstate cache | ||
1637 | bitbake('%s -c cleansstate' % testrecipe) | ||
1638 | # Try modifying a recipe | ||
1639 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1640 | self.track_for_cleanup(tempdir) | ||
1641 | self.track_for_cleanup(self.workspacedir) | ||
1642 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
1643 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1644 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
1645 | testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c') | ||
1646 | self.assertExists(testsrcfile, 'Extracted source could not be found') | ||
1647 | self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output) | ||
1648 | self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo') | ||
1649 | # Check git repo | ||
1650 | self._check_src_repo(tempdir) | ||
1651 | # Modify file | ||
1652 | runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile) | ||
1653 | result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir) | ||
1654 | # Now try updating original recipe | ||
1655 | recipefile = bb_vars['FILE'] | ||
1656 | recipedir = os.path.dirname(recipefile) | ||
1657 | self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe)) | ||
1658 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
1659 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | ||
1660 | ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))] | ||
1661 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
1662 | result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) | ||
1663 | removelines = ['SRC_URI = "git://.*"'] | ||
1664 | addlines = [ | ||
1665 | 'SRC_URI = "git://.* \\\\', | ||
1666 | 'file://0001-Add-a-comment.patch;patchdir=.. \\\\', | ||
1667 | '"' | ||
1668 | ] | ||
1669 | self._check_diff(result.output, addlines, removelines) | ||
1670 | # Put things back so we can run devtool finish on a different layer | ||
1671 | runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe)) | ||
1672 | # Run devtool finish | ||
1673 | res = re.search('recipes-.*', recipedir) | ||
1674 | self.assertTrue(res, 'Unable to find recipe subdirectory') | ||
1675 | recipesubdir = res[0] | ||
1676 | self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir)) | ||
1677 | result = runCmd('devtool finish %s meta-selftest' % testrecipe) | ||
1678 | # Check bbappend file contents | ||
1679 | appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe) | ||
1680 | with open(appendfn, 'r') as f: | ||
1681 | appendlines = f.readlines() | ||
1682 | expected_appendlines = [ | ||
1683 | 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', | ||
1684 | '\n', | ||
1685 | 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n', | ||
1686 | '\n' | ||
1687 | ] | ||
1688 | self.assertEqual(appendlines, expected_appendlines) | ||
1689 | self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch')) | ||
1690 | # Try building | ||
1691 | bitbake('%s -c patch' % testrecipe) | ||
1692 | |||
1693 | def test_devtool_git_submodules(self): | ||
1694 | # This tests if we can add a patch in a git submodule and extract it properly using devtool finish | ||
1695 | # Check preconditions | ||
1696 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1697 | self.track_for_cleanup(self.workspacedir) | ||
1698 | recipe = 'vulkan-samples' | ||
1699 | src_uri = get_bb_var('SRC_URI', recipe) | ||
1700 | self.assertIn('gitsm://', src_uri, 'This test expects the %s recipe to be a git recipe with submodules' % recipe) | ||
1701 | oldrecipefile = get_bb_var('FILE', recipe) | ||
1702 | recipedir = os.path.dirname(oldrecipefile) | ||
1703 | result = runCmd('git status --porcelain .', cwd=recipedir) | ||
1704 | if result.output.strip(): | ||
1705 | self.fail('Recipe directory for %s contains uncommitted changes' % recipe) | ||
1706 | self.assertIn('/meta/', recipedir) | ||
1707 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1708 | self.track_for_cleanup(tempdir) | ||
1709 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1710 | result = runCmd('devtool modify %s %s' % (recipe, tempdir)) | ||
1711 | self.assertExists(os.path.join(tempdir, 'CMakeLists.txt'), 'Extracted source could not be found') | ||
1712 | # Test devtool status | ||
1713 | result = runCmd('devtool status') | ||
1714 | self.assertIn(recipe, result.output) | ||
1715 | self.assertIn(tempdir, result.output) | ||
1716 | # Modify a source file in a submodule, (grab the first one) | ||
1717 | result = runCmd('git submodule --quiet foreach \'echo $sm_path\'', cwd=tempdir) | ||
1718 | submodule = result.output.splitlines()[0] | ||
1719 | submodule_path = os.path.join(tempdir, submodule) | ||
1720 | runCmd('echo "#This is a first comment" >> testfile', cwd=submodule_path) | ||
1721 | result = runCmd('git status --porcelain . ', cwd=submodule_path) | ||
1722 | self.assertIn("testfile", result.output) | ||
1723 | runCmd('git add testfile; git commit -m "Adding a new file"', cwd=submodule_path) | ||
1724 | |||
1725 | # Try finish to the original layer | ||
1726 | self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir)) | ||
1727 | runCmd('devtool finish -f %s meta' % recipe) | ||
1728 | result = runCmd('devtool status') | ||
1729 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
1730 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish') | ||
1731 | expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)), | ||
1732 | ('??', '.*/.*-Adding-a-new-file.patch$')] | ||
1733 | self._check_repo_status(recipedir, expected_status) | ||
1734 | # Make sure the patch is added to the recipe with the correct "patchdir" option | ||
1735 | result = runCmd('git diff .', cwd=recipedir) | ||
1736 | addlines = [ | ||
1737 | 'file://0001-Adding-a-new-file.patch;patchdir=%s \\\\' % submodule | ||
1738 | ] | ||
1739 | self._check_diff(result.output, addlines, []) | ||
1740 | |||
1298 | class DevtoolExtractTests(DevtoolBase): | 1741 | class DevtoolExtractTests(DevtoolBase): |
1299 | 1742 | ||
1300 | def test_devtool_extract(self): | 1743 | def test_devtool_extract(self): |
@@ -1317,6 +1760,8 @@ class DevtoolExtractTests(DevtoolBase): | |||
1317 | self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found') | 1760 | self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found') |
1318 | self._check_src_repo(tempdir) | 1761 | self._check_src_repo(tempdir) |
1319 | 1762 | ||
1763 | class DevtoolResetTests(DevtoolBase): | ||
1764 | |||
1320 | def test_devtool_reset_all(self): | 1765 | def test_devtool_reset_all(self): |
1321 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | 1766 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') |
1322 | self.track_for_cleanup(tempdir) | 1767 | self.track_for_cleanup(tempdir) |
@@ -1343,33 +1788,30 @@ class DevtoolExtractTests(DevtoolBase): | |||
1343 | matches2 = glob.glob(stampprefix2 + '*') | 1788 | matches2 = glob.glob(stampprefix2 + '*') |
1344 | self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2) | 1789 | self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2) |
1345 | 1790 | ||
1791 | def test_devtool_reset_re_plus_plus(self): | ||
1792 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1793 | self.track_for_cleanup(tempdir) | ||
1794 | self.track_for_cleanup(self.workspacedir) | ||
1795 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1796 | testrecipe = 'devtool-test-reset-re++' | ||
1797 | result = runCmd('devtool modify %s' % testrecipe) | ||
1798 | result = runCmd('devtool reset -n %s' % testrecipe) | ||
1799 | self.assertIn(testrecipe, result.output) | ||
1800 | result = runCmd('devtool status') | ||
1801 | self.assertNotIn(testrecipe, result.output) | ||
1802 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', testrecipe), 'Recipe directory should not exist after resetting') | ||
1803 | |||
1804 | class DevtoolDeployTargetTests(DevtoolBase): | ||
1805 | |||
1806 | @OETestTag("runqemu") | ||
1346 | def test_devtool_deploy_target(self): | 1807 | def test_devtool_deploy_target(self): |
1347 | # NOTE: Whilst this test would seemingly be better placed as a runtime test, | 1808 | self._check_runqemu_prerequisites() |
1348 | # unfortunately the runtime tests run under bitbake and you can't run | ||
1349 | # devtool within bitbake (since devtool needs to run bitbake itself). | ||
1350 | # Additionally we are testing build-time functionality as well, so | ||
1351 | # really this has to be done as an oe-selftest test. | ||
1352 | # | ||
1353 | # Check preconditions | ||
1354 | machine = get_bb_var('MACHINE') | ||
1355 | if not machine.startswith('qemu'): | ||
1356 | self.skipTest('This test only works with qemu machines') | ||
1357 | if not os.path.exists('/etc/runqemu-nosudo'): | ||
1358 | self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
1359 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True) | ||
1360 | if result.status != 0: | ||
1361 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True) | ||
1362 | if result.status != 0: | ||
1363 | self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output) | ||
1364 | for line in result.output.splitlines(): | ||
1365 | if line.startswith('tap'): | ||
1366 | break | ||
1367 | else: | ||
1368 | self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
1369 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | 1809 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') |
1370 | # Definitions | 1810 | # Definitions |
1371 | testrecipe = 'mdadm' | 1811 | testrecipe = 'mdadm' |
1372 | testfile = '/sbin/mdadm' | 1812 | testfile = '/sbin/mdadm' |
1813 | if "usrmerge" in get_bb_var('DISTRO_FEATURES'): | ||
1814 | testfile = '/usr/sbin/mdadm' | ||
1373 | testimage = 'oe-selftest-image' | 1815 | testimage = 'oe-selftest-image' |
1374 | testcommand = '/sbin/mdadm --help' | 1816 | testcommand = '/sbin/mdadm --help' |
1375 | # Build an image to run | 1817 | # Build an image to run |
@@ -1428,6 +1870,8 @@ class DevtoolExtractTests(DevtoolBase): | |||
1428 | result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True) | 1870 | result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True) |
1429 | self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') | 1871 | self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') |
1430 | 1872 | ||
1873 | class DevtoolBuildImageTests(DevtoolBase): | ||
1874 | |||
1431 | def test_devtool_build_image(self): | 1875 | def test_devtool_build_image(self): |
1432 | """Test devtool build-image plugin""" | 1876 | """Test devtool build-image plugin""" |
1433 | # Check preconditions | 1877 | # Check preconditions |
@@ -1463,6 +1907,14 @@ class DevtoolExtractTests(DevtoolBase): | |||
1463 | 1907 | ||
1464 | class DevtoolUpgradeTests(DevtoolBase): | 1908 | class DevtoolUpgradeTests(DevtoolBase): |
1465 | 1909 | ||
1910 | def setUp(self): | ||
1911 | super().setUp() | ||
1912 | try: | ||
1913 | runCmd("git config --global user.name") | ||
1914 | runCmd("git config --global user.email") | ||
1915 | except: | ||
1916 | self.skip("Git user.name and user.email must be set") | ||
1917 | |||
1466 | def test_devtool_upgrade(self): | 1918 | def test_devtool_upgrade(self): |
1467 | # Check preconditions | 1919 | # Check preconditions |
1468 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | 1920 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') |
@@ -1543,6 +1995,100 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1543 | self.assertNotIn(recipe, result.output) | 1995 | self.assertNotIn(recipe, result.output) |
1544 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting') | 1996 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting') |
1545 | 1997 | ||
1998 | def test_devtool_upgrade_drop_md5sum(self): | ||
1999 | # Check preconditions | ||
2000 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
2001 | self.track_for_cleanup(self.workspacedir) | ||
2002 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
2003 | # For the moment, we are using a real recipe. | ||
2004 | recipe = 'devtool-upgrade-test3' | ||
2005 | version = '1.6.0' | ||
2006 | oldrecipefile = get_bb_var('FILE', recipe) | ||
2007 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
2008 | self.track_for_cleanup(tempdir) | ||
2009 | # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that | ||
2010 | # we are downgrading instead of upgrading. | ||
2011 | result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version)) | ||
2012 | # Check new recipe file is present | ||
2013 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version)) | ||
2014 | self.assertExists(newrecipefile, 'Recipe file should exist after upgrade') | ||
2015 | # Check recipe got changed as expected | ||
2016 | with open(oldrecipefile + '.upgraded', 'r') as f: | ||
2017 | desiredlines = f.readlines() | ||
2018 | with open(newrecipefile, 'r') as f: | ||
2019 | newlines = f.readlines() | ||
2020 | self.assertEqual(desiredlines, newlines) | ||
2021 | |||
2022 | def test_devtool_upgrade_all_checksums(self): | ||
2023 | # Check preconditions | ||
2024 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
2025 | self.track_for_cleanup(self.workspacedir) | ||
2026 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
2027 | # For the moment, we are using a real recipe. | ||
2028 | recipe = 'devtool-upgrade-test4' | ||
2029 | version = '1.6.0' | ||
2030 | oldrecipefile = get_bb_var('FILE', recipe) | ||
2031 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
2032 | self.track_for_cleanup(tempdir) | ||
2033 | # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that | ||
2034 | # we are downgrading instead of upgrading. | ||
2035 | result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version)) | ||
2036 | # Check new recipe file is present | ||
2037 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version)) | ||
2038 | self.assertExists(newrecipefile, 'Recipe file should exist after upgrade') | ||
2039 | # Check recipe got changed as expected | ||
2040 | with open(oldrecipefile + '.upgraded', 'r') as f: | ||
2041 | desiredlines = f.readlines() | ||
2042 | with open(newrecipefile, 'r') as f: | ||
2043 | newlines = f.readlines() | ||
2044 | self.assertEqual(desiredlines, newlines) | ||
2045 | |||
2046 | def test_devtool_upgrade_recipe_upgrade_extra_tasks(self): | ||
2047 | # Check preconditions | ||
2048 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
2049 | self.track_for_cleanup(self.workspacedir) | ||
2050 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
2051 | recipe = 'python3-guessing-game' | ||
2052 | version = '0.2.0' | ||
2053 | commit = '40cf004c2772ffa20ea803fa3be1528a75be3e98' | ||
2054 | oldrecipefile = get_bb_var('FILE', recipe) | ||
2055 | oldcratesincfile = os.path.join(os.path.dirname(oldrecipefile), os.path.basename(oldrecipefile).strip('_git.bb') + '-crates.inc') | ||
2056 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
2057 | self.track_for_cleanup(tempdir) | ||
2058 | # Check that recipe is not already under devtool control | ||
2059 | result = runCmd('devtool status') | ||
2060 | self.assertNotIn(recipe, result.output) | ||
2061 | # Check upgrade | ||
2062 | result = runCmd('devtool upgrade %s %s --version %s --srcrev %s' % (recipe, tempdir, version, commit)) | ||
2063 | # Check if srctree at least is populated | ||
2064 | self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit)) | ||
2065 | # Check new recipe file and new -crates.inc files are present | ||
2066 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile)) | ||
2067 | newcratesincfile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldcratesincfile)) | ||
2068 | self.assertExists(newrecipefile, 'Recipe file should exist after upgrade') | ||
2069 | self.assertExists(newcratesincfile, 'Recipe crates.inc file should exist after upgrade') | ||
2070 | # Check devtool status and make sure recipe is present | ||
2071 | result = runCmd('devtool status') | ||
2072 | self.assertIn(recipe, result.output) | ||
2073 | self.assertIn(tempdir, result.output) | ||
2074 | # Check recipe got changed as expected | ||
2075 | with open(oldrecipefile + '.upgraded', 'r') as f: | ||
2076 | desiredlines = f.readlines() | ||
2077 | with open(newrecipefile, 'r') as f: | ||
2078 | newlines = f.readlines() | ||
2079 | self.assertEqual(desiredlines, newlines) | ||
2080 | # Check crates.inc got changed as expected | ||
2081 | with open(oldcratesincfile + '.upgraded', 'r') as f: | ||
2082 | desiredlines = f.readlines() | ||
2083 | with open(newcratesincfile, 'r') as f: | ||
2084 | newlines = f.readlines() | ||
2085 | self.assertEqual(desiredlines, newlines) | ||
2086 | # Check devtool reset recipe | ||
2087 | result = runCmd('devtool reset %s -n' % recipe) | ||
2088 | result = runCmd('devtool status') | ||
2089 | self.assertNotIn(recipe, result.output) | ||
2090 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting') | ||
2091 | |||
1546 | def test_devtool_layer_plugins(self): | 2092 | def test_devtool_layer_plugins(self): |
1547 | """Test that devtool can use plugins from other layers. | 2093 | """Test that devtool can use plugins from other layers. |
1548 | 2094 | ||
@@ -1561,7 +2107,15 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1561 | for p in paths: | 2107 | for p in paths: |
1562 | dstdir = os.path.join(dstdir, p) | 2108 | dstdir = os.path.join(dstdir, p) |
1563 | if not os.path.exists(dstdir): | 2109 | if not os.path.exists(dstdir): |
1564 | os.makedirs(dstdir) | 2110 | try: |
2111 | os.makedirs(dstdir) | ||
2112 | except PermissionError: | ||
2113 | return False | ||
2114 | except OSError as e: | ||
2115 | if e.errno == errno.EROFS: | ||
2116 | return False | ||
2117 | else: | ||
2118 | raise e | ||
1565 | if p == "lib": | 2119 | if p == "lib": |
1566 | # Can race with other tests | 2120 | # Can race with other tests |
1567 | self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir) | 2121 | self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir) |
@@ -1569,8 +2123,12 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1569 | self.track_for_cleanup(dstdir) | 2123 | self.track_for_cleanup(dstdir) |
1570 | dstfile = os.path.join(dstdir, os.path.basename(srcfile)) | 2124 | dstfile = os.path.join(dstdir, os.path.basename(srcfile)) |
1571 | if srcfile != dstfile: | 2125 | if srcfile != dstfile: |
1572 | shutil.copy(srcfile, dstfile) | 2126 | try: |
2127 | shutil.copy(srcfile, dstfile) | ||
2128 | except PermissionError: | ||
2129 | return False | ||
1573 | self.track_for_cleanup(dstfile) | 2130 | self.track_for_cleanup(dstfile) |
2131 | return True | ||
1574 | 2132 | ||
1575 | def test_devtool_load_plugin(self): | 2133 | def test_devtool_load_plugin(self): |
1576 | """Test that devtool loads only the first found plugin in BBPATH.""" | 2134 | """Test that devtool loads only the first found plugin in BBPATH.""" |
@@ -1588,15 +2146,17 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1588 | plugincontent = fh.readlines() | 2146 | plugincontent = fh.readlines() |
1589 | try: | 2147 | try: |
1590 | self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found') | 2148 | self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found') |
1591 | for path in searchpath: | 2149 | searchpath = [ |
1592 | self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool') | 2150 | path for path in searchpath |
2151 | if self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool') | ||
2152 | ] | ||
1593 | result = runCmd("devtool --quiet count") | 2153 | result = runCmd("devtool --quiet count") |
1594 | self.assertEqual(result.output, '1') | 2154 | self.assertEqual(result.output, '1') |
1595 | result = runCmd("devtool --quiet multiloaded") | 2155 | result = runCmd("devtool --quiet multiloaded") |
1596 | self.assertEqual(result.output, "no") | 2156 | self.assertEqual(result.output, "no") |
1597 | for path in searchpath: | 2157 | for path in searchpath: |
1598 | result = runCmd("devtool --quiet bbdir") | 2158 | result = runCmd("devtool --quiet bbdir") |
1599 | self.assertEqual(result.output, path) | 2159 | self.assertEqual(os.path.realpath(result.output), os.path.realpath(path)) |
1600 | os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py')) | 2160 | os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py')) |
1601 | finally: | 2161 | finally: |
1602 | with open(srcfile, 'w') as fh: | 2162 | with open(srcfile, 'w') as fh: |
@@ -1777,6 +2337,52 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1777 | if files: | 2337 | if files: |
1778 | self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files)) | 2338 | self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files)) |
1779 | 2339 | ||
2340 | def test_devtool_finish_update_patch(self): | ||
2341 | # This test uses a modified version of the sysdig recipe from meta-oe. | ||
2342 | # - The patches have been renamed. | ||
2343 | # - The dependencies are commented out since the recipe is not being | ||
2344 | # built. | ||
2345 | # | ||
2346 | # The sysdig recipe is interesting in that it fetches two different Git | ||
2347 | # repositories, and there are patches for both. This leads to that | ||
2348 | # devtool will create ignore commits as it uses Git submodules to keep | ||
2349 | # track of the second repository. | ||
2350 | # | ||
2351 | # This test will verify that the ignored commits actually are ignored | ||
2352 | # when a commit in between is modified. It will also verify that the | ||
2353 | # updated patch keeps its original name. | ||
2354 | |||
2355 | # Check preconditions | ||
2356 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
2357 | # Try modifying a recipe | ||
2358 | self.track_for_cleanup(self.workspacedir) | ||
2359 | recipe = 'sysdig-selftest' | ||
2360 | recipefile = get_bb_var('FILE', recipe) | ||
2361 | recipedir = os.path.dirname(recipefile) | ||
2362 | result = runCmd('git status --porcelain .', cwd=recipedir) | ||
2363 | if result.output.strip(): | ||
2364 | self.fail('Recipe directory for %s contains uncommitted changes' % recipe) | ||
2365 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
2366 | self.track_for_cleanup(tempdir) | ||
2367 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
2368 | result = runCmd('devtool modify %s %s' % (recipe, tempdir)) | ||
2369 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (recipedir, recipe, recipe, os.path.basename(recipefile))) | ||
2370 | self.assertExists(os.path.join(tempdir, 'CMakeLists.txt'), 'Extracted source could not be found') | ||
2371 | # Make a change to one of the existing commits | ||
2372 | result = runCmd('echo "# A comment " >> CMakeLists.txt', cwd=tempdir) | ||
2373 | result = runCmd('git status --porcelain', cwd=tempdir) | ||
2374 | self.assertIn('M CMakeLists.txt', result.output) | ||
2375 | result = runCmd('git commit --fixup HEAD^ CMakeLists.txt', cwd=tempdir) | ||
2376 | result = runCmd('git show -s --format=%s', cwd=tempdir) | ||
2377 | self.assertIn('fixup! cmake: Pass PROBE_NAME via CFLAGS', result.output) | ||
2378 | result = runCmd('GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash devtool-base', cwd=tempdir) | ||
2379 | result = runCmd('devtool finish %s meta-selftest' % recipe) | ||
2380 | result = runCmd('devtool status') | ||
2381 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
2382 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish') | ||
2383 | expected_status = [(' M', '.*/0099-cmake-Pass-PROBE_NAME-via-CFLAGS.patch$')] | ||
2384 | self._check_repo_status(recipedir, expected_status) | ||
2385 | |||
1780 | def test_devtool_rename(self): | 2386 | def test_devtool_rename(self): |
1781 | # Check preconditions | 2387 | # Check preconditions |
1782 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | 2388 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') |
@@ -1808,12 +2414,11 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1808 | newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename) | 2414 | newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename) |
1809 | self.assertExists(newsrctree, 'Source directory not renamed') | 2415 | self.assertExists(newsrctree, 'Source directory not renamed') |
1810 | checkvars = {} | 2416 | checkvars = {} |
1811 | checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever) | 2417 | checkvars['S'] = '${UNPACKDIR}/%s-%s' % (recipename, recipever) |
1812 | checkvars['SRC_URI'] = url | 2418 | checkvars['SRC_URI'] = url |
1813 | self._test_recipe_contents(newrecipefile, checkvars, []) | 2419 | self._test_recipe_contents(newrecipefile, checkvars, []) |
1814 | # Try again - change just name this time | 2420 | # Try again - change just name this time |
1815 | result = runCmd('devtool reset -n %s' % newrecipename) | 2421 | result = runCmd('devtool reset -n %s' % newrecipename) |
1816 | shutil.rmtree(newsrctree) | ||
1817 | add_recipe() | 2422 | add_recipe() |
1818 | newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever)) | 2423 | newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever)) |
1819 | result = runCmd('devtool rename %s %s' % (recipename, newrecipename)) | 2424 | result = runCmd('devtool rename %s %s' % (recipename, newrecipename)) |
@@ -1821,19 +2426,18 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1821 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists') | 2426 | self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists') |
1822 | self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed') | 2427 | self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed') |
1823 | checkvars = {} | 2428 | checkvars = {} |
1824 | checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename | 2429 | checkvars['S'] = '${UNPACKDIR}/%s-${PV}' % recipename |
1825 | checkvars['SRC_URI'] = url.replace(recipever, '${PV}') | 2430 | checkvars['SRC_URI'] = url.replace(recipever, '${PV}') |
1826 | self._test_recipe_contents(newrecipefile, checkvars, []) | 2431 | self._test_recipe_contents(newrecipefile, checkvars, []) |
1827 | # Try again - change just version this time | 2432 | # Try again - change just version this time |
1828 | result = runCmd('devtool reset -n %s' % newrecipename) | 2433 | result = runCmd('devtool reset -n %s' % newrecipename) |
1829 | shutil.rmtree(newsrctree) | ||
1830 | add_recipe() | 2434 | add_recipe() |
1831 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever)) | 2435 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever)) |
1832 | result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever)) | 2436 | result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever)) |
1833 | self.assertExists(newrecipefile, 'Recipe file not renamed') | 2437 | self.assertExists(newrecipefile, 'Recipe file not renamed') |
1834 | self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists') | 2438 | self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists') |
1835 | checkvars = {} | 2439 | checkvars = {} |
1836 | checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever | 2440 | checkvars['S'] = '${UNPACKDIR}/${BPN}-%s' % recipever |
1837 | checkvars['SRC_URI'] = url | 2441 | checkvars['SRC_URI'] = url |
1838 | self._test_recipe_contents(newrecipefile, checkvars, []) | 2442 | self._test_recipe_contents(newrecipefile, checkvars, []) |
1839 | 2443 | ||
@@ -1858,8 +2462,9 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1858 | Expected: devtool modify is able to checkout the source of the kernel | 2462 | Expected: devtool modify is able to checkout the source of the kernel |
1859 | and modification to the source and configurations are reflected | 2463 | and modification to the source and configurations are reflected |
1860 | when building the kernel. | 2464 | when building the kernel. |
1861 | """ | 2465 | """ |
1862 | kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel') | 2466 | kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel'] |
2467 | |||
1863 | # Clean up the environment | 2468 | # Clean up the environment |
1864 | bitbake('%s -c clean' % kernel_provider) | 2469 | bitbake('%s -c clean' % kernel_provider) |
1865 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | 2470 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') |
@@ -1886,33 +2491,540 @@ class DevtoolUpgradeTests(DevtoolBase): | |||
1886 | self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found') | 2491 | self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found') |
1887 | #Step 4.2 | 2492 | #Step 4.2 |
1888 | configfile = os.path.join(tempdir,'.config') | 2493 | configfile = os.path.join(tempdir,'.config') |
1889 | diff = runCmd('diff %s %s' % (tmpconfig, configfile)) | 2494 | runCmd('diff %s %s' % (tmpconfig, configfile)) |
1890 | self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool') | 2495 | |
1891 | #Step 4.3 | 2496 | #Step 4.3 |
1892 | #NOTE: virtual/kernel is mapped to kernel_provider | 2497 | #NOTE: virtual/kernel is mapped to kernel_provider |
1893 | result = runCmd('devtool build %s' % kernel_provider) | 2498 | runCmd('devtool build %s' % kernel_provider) |
1894 | self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`') | ||
1895 | kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux') | 2499 | kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux') |
1896 | self.assertExists(kernelfile, 'Kernel was not build correctly') | 2500 | self.assertExists(kernelfile, 'Kernel was not build correctly') |
1897 | 2501 | ||
1898 | #Modify the kernel source | 2502 | #Modify the kernel source |
1899 | modfile = os.path.join(tempdir,'arch/x86/boot/header.S') | 2503 | modfile = os.path.join(tempdir, 'init/version.c') |
1900 | modstring = "Use a boot loader. Devtool testing." | 2504 | # Moved to uts.h in 6.1 onwards |
1901 | modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile)) | 2505 | modfile2 = os.path.join(tempdir, 'include/linux/uts.h') |
1902 | self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile) | 2506 | runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2)) |
2507 | |||
1903 | #Modify the configuration | 2508 | #Modify the configuration |
1904 | codeconfigfile = os.path.join(tempdir,'.config.new') | 2509 | codeconfigfile = os.path.join(tempdir, '.config.new') |
1905 | modconfopt = "CONFIG_SG_POOL=n" | 2510 | modconfopt = "CONFIG_SG_POOL=n" |
1906 | modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile)) | 2511 | runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile)) |
1907 | self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile) | 2512 | |
1908 | #Build again kernel with devtool | 2513 | #Build again kernel with devtool |
1909 | rebuild = runCmd('devtool build %s' % kernel_provider) | 2514 | runCmd('devtool build %s' % kernel_provider) |
1910 | self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config') | 2515 | |
1911 | #Step 4.4 | 2516 | #Step 4.4 |
1912 | bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider) | 2517 | runCmd("grep '%s' %s" % ('LiNuX', kernelfile)) |
1913 | bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename) | 2518 | |
1914 | checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile)) | ||
1915 | self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed') | ||
1916 | #Step 4.5 | 2519 | #Step 4.5 |
1917 | checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile)) | 2520 | runCmd("grep %s %s" % (modconfopt, codeconfigfile)) |
1918 | self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed') | 2521 | |
2522 | |||
2523 | class DevtoolIdeSdkTests(DevtoolBase): | ||
2524 | def _write_bb_config(self, recipe_names): | ||
2525 | """Helper to write the bitbake local.conf file""" | ||
2526 | conf_lines = [ | ||
2527 | 'IMAGE_CLASSES += "image-combined-dbg"', | ||
2528 | 'IMAGE_GEN_DEBUGFS = "1"', | ||
2529 | 'IMAGE_INSTALL:append = " gdbserver %s"' % ' '.join( | ||
2530 | [r + '-ptest' for r in recipe_names]) | ||
2531 | ] | ||
2532 | self.write_config("\n".join(conf_lines)) | ||
2533 | |||
2534 | def _check_workspace(self): | ||
2535 | """Check if a workspace directory is available and setup the cleanup""" | ||
2536 | self.assertTrue(not os.path.exists(self.workspacedir), | ||
2537 | 'This test cannot be run with a workspace directory under the build directory') | ||
2538 | self.track_for_cleanup(self.workspacedir) | ||
2539 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
2540 | |||
2541 | def _workspace_scripts_dir(self, recipe_name): | ||
2542 | return os.path.realpath(os.path.join(self.builddir, 'workspace', 'ide-sdk', recipe_name, 'scripts')) | ||
2543 | |||
2544 | def _sources_scripts_dir(self, src_dir): | ||
2545 | return os.path.realpath(os.path.join(src_dir, 'oe-scripts')) | ||
2546 | |||
2547 | def _workspace_gdbinit_dir(self, recipe_name): | ||
2548 | return os.path.realpath(os.path.join(self.builddir, 'workspace', 'ide-sdk', recipe_name, 'scripts', 'gdbinit')) | ||
2549 | |||
2550 | def _sources_gdbinit_dir(self, src_dir): | ||
2551 | return os.path.realpath(os.path.join(src_dir, 'oe-gdbinit')) | ||
2552 | |||
2553 | def _devtool_ide_sdk_recipe(self, recipe_name, build_file, testimage): | ||
2554 | """Setup a recipe for working with devtool ide-sdk | ||
2555 | |||
2556 | Basically devtool modify -x followed by some tests | ||
2557 | """ | ||
2558 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
2559 | self.track_for_cleanup(tempdir) | ||
2560 | self.add_command_to_tearDown('bitbake -c clean %s' % recipe_name) | ||
2561 | |||
2562 | result = runCmd('devtool modify %s -x %s --debug-build' % (recipe_name, tempdir)) | ||
2563 | self.assertExists(os.path.join(tempdir, build_file), | ||
2564 | 'Extracted source could not be found') | ||
2565 | self.assertExists(os.path.join(self.workspacedir, 'conf', | ||
2566 | 'layer.conf'), 'Workspace directory not created') | ||
2567 | matches = glob.glob(os.path.join(self.workspacedir, | ||
2568 | 'appends', recipe_name + '.bbappend')) | ||
2569 | self.assertTrue(matches, 'bbappend not created %s' % result.output) | ||
2570 | |||
2571 | # Test devtool status | ||
2572 | result = runCmd('devtool status') | ||
2573 | self.assertIn(recipe_name, result.output) | ||
2574 | self.assertIn(tempdir, result.output) | ||
2575 | self._check_src_repo(tempdir) | ||
2576 | |||
2577 | # Usually devtool ide-sdk would initiate the build of the SDK. | ||
2578 | # But there is a circular dependency with starting Qemu and passing the IP of runqemu to devtool ide-sdk. | ||
2579 | if testimage: | ||
2580 | bitbake("%s qemu-native qemu-helper-native" % testimage) | ||
2581 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
2582 | self.add_command_to_tearDown('bitbake -c clean %s' % testimage) | ||
2583 | self.add_command_to_tearDown( | ||
2584 | 'rm -f %s/%s*' % (deploy_dir_image, testimage)) | ||
2585 | |||
2586 | return tempdir | ||
2587 | |||
2588 | def _get_recipe_ids(self, recipe_name): | ||
2589 | """IDs needed to write recipe specific config entries into IDE config files""" | ||
2590 | package_arch = get_bb_var('PACKAGE_ARCH', recipe_name) | ||
2591 | recipe_id = recipe_name + "-" + package_arch | ||
2592 | recipe_id_pretty = recipe_name + ": " + package_arch | ||
2593 | return (recipe_id, recipe_id_pretty) | ||
2594 | |||
2595 | def _verify_install_script_code(self, tempdir, recipe_name): | ||
2596 | """Verify the scripts referred by the tasks.json file are fine. | ||
2597 | |||
2598 | This function does not depend on Qemu. Therefore it verifies the scripts | ||
2599 | exists and the delete step works as expected. But it does not try to | ||
2600 | deploy to Qemu. | ||
2601 | """ | ||
2602 | recipe_id, recipe_id_pretty = self._get_recipe_ids(recipe_name) | ||
2603 | with open(os.path.join(tempdir, '.vscode', 'tasks.json')) as tasks_j: | ||
2604 | tasks_d = json.load(tasks_j) | ||
2605 | tasks = tasks_d["tasks"] | ||
2606 | task_install = next( | ||
2607 | (task for task in tasks if task["label"] == "install && deploy-target %s" % recipe_id_pretty), None) | ||
2608 | self.assertIsNot(task_install, None) | ||
2609 | # execute only the bb_run_do_install script since the deploy would require e.g. Qemu running. | ||
2610 | i_and_d_script = "install_and_deploy_" + recipe_id | ||
2611 | i_and_d_script_path = os.path.join( | ||
2612 | self._workspace_scripts_dir(recipe_name), i_and_d_script) | ||
2613 | self.assertExists(i_and_d_script_path) | ||
2614 | |||
2615 | def _devtool_ide_sdk_qemu(self, tempdir, qemu, recipe_name, example_exe): | ||
2616 | """Verify deployment and execution in Qemu system work for one recipe. | ||
2617 | |||
2618 | This function checks the entire SDK workflow: changing the code, recompiling | ||
2619 | it and deploying it back to Qemu, and checking that the changes have been | ||
2620 | incorporated into the provided binaries. It also runs the tests of the recipe. | ||
2621 | """ | ||
2622 | recipe_id, _ = self._get_recipe_ids(recipe_name) | ||
2623 | i_and_d_script = "install_and_deploy_" + recipe_id | ||
2624 | install_deploy_cmd = os.path.join( | ||
2625 | self._workspace_scripts_dir(recipe_name), i_and_d_script) | ||
2626 | self.assertExists(install_deploy_cmd, | ||
2627 | '%s script not found' % install_deploy_cmd) | ||
2628 | runCmd(install_deploy_cmd) | ||
2629 | |||
2630 | MAGIC_STRING_ORIG = "Magic: 123456789" | ||
2631 | MAGIC_STRING_NEW = "Magic: 987654321" | ||
2632 | ptest_cmd = "ptest-runner " + recipe_name | ||
2633 | |||
2634 | # validate that SSH is working | ||
2635 | status, _ = qemu.run("uname") | ||
2636 | self.assertEqual( | ||
2637 | status, 0, msg="Failed to connect to the SSH server on Qemu") | ||
2638 | |||
2639 | # Verify the unmodified example prints the magic string | ||
2640 | status, output = qemu.run(example_exe) | ||
2641 | self.assertEqual(status, 0, msg="%s failed: %s" % | ||
2642 | (example_exe, output)) | ||
2643 | self.assertIn(MAGIC_STRING_ORIG, output) | ||
2644 | |||
2645 | # Verify the unmodified ptests work | ||
2646 | status, output = qemu.run(ptest_cmd) | ||
2647 | self.assertEqual(status, 0, msg="%s failed: %s" % (ptest_cmd, output)) | ||
2648 | self.assertIn("PASS: cpp-example-lib", output) | ||
2649 | |||
2650 | # Verify remote debugging works | ||
2651 | self._gdb_cross_debugging( | ||
2652 | qemu, recipe_name, example_exe, MAGIC_STRING_ORIG) | ||
2653 | |||
2654 | # Replace the Magic String in the code, compile and deploy to Qemu | ||
2655 | cpp_example_lib_hpp = os.path.join(tempdir, 'cpp-example-lib.hpp') | ||
2656 | with open(cpp_example_lib_hpp, 'r') as file: | ||
2657 | cpp_code = file.read() | ||
2658 | cpp_code = cpp_code.replace(MAGIC_STRING_ORIG, MAGIC_STRING_NEW) | ||
2659 | with open(cpp_example_lib_hpp, 'w') as file: | ||
2660 | file.write(cpp_code) | ||
2661 | runCmd(install_deploy_cmd, cwd=tempdir) | ||
2662 | |||
2663 | # Verify the modified example prints the modified magic string | ||
2664 | status, output = qemu.run(example_exe) | ||
2665 | self.assertEqual(status, 0, msg="%s failed: %s" % | ||
2666 | (example_exe, output)) | ||
2667 | self.assertNotIn(MAGIC_STRING_ORIG, output) | ||
2668 | self.assertIn(MAGIC_STRING_NEW, output) | ||
2669 | |||
2670 | # Verify the modified example ptests work | ||
2671 | status, output = qemu.run(ptest_cmd) | ||
2672 | self.assertEqual(status, 0, msg="%s failed: %s" % (ptest_cmd, output)) | ||
2673 | self.assertIn("PASS: cpp-example-lib", output) | ||
2674 | |||
2675 | # Verify remote debugging works wit the modified magic string | ||
2676 | self._gdb_cross_debugging( | ||
2677 | qemu, recipe_name, example_exe, MAGIC_STRING_NEW) | ||
2678 | |||
2679 | def _gdb_cross(self): | ||
2680 | """Verify gdb-cross is provided by devtool ide-sdk""" | ||
2681 | target_arch = self.td["TARGET_ARCH"] | ||
2682 | target_sys = self.td["TARGET_SYS"] | ||
2683 | gdb_recipe = "gdb-cross-" + target_arch | ||
2684 | gdb_binary = target_sys + "-gdb" | ||
2685 | |||
2686 | native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", gdb_recipe) | ||
2687 | r = runCmd("%s --version" % gdb_binary, | ||
2688 | native_sysroot=native_sysroot, target_sys=target_sys) | ||
2689 | self.assertEqual(r.status, 0) | ||
2690 | self.assertIn("GNU gdb", r.output) | ||
2691 | |||
2692 | def _gdb_cross_debugging(self, qemu, recipe_name, example_exe, magic_string): | ||
2693 | """Verify gdb-cross is working | ||
2694 | |||
2695 | Test remote debugging: | ||
2696 | break main | ||
2697 | run | ||
2698 | continue | ||
2699 | break CppExample::print_json() | ||
2700 | continue | ||
2701 | print CppExample::test_string.compare("cpp-example-lib Magic: 123456789") | ||
2702 | $1 = 0 | ||
2703 | print CppExample::test_string.compare("cpp-example-lib Magic: 123456789aaa") | ||
2704 | $2 = -3 | ||
2705 | list cpp-example-lib.hpp:13,13 | ||
2706 | 13 inline static const std::string test_string = "cpp-example-lib Magic: 123456789"; | ||
2707 | continue | ||
2708 | """ | ||
2709 | sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | ||
2710 | gdbserver_script = os.path.join(self._workspace_scripts_dir( | ||
2711 | recipe_name), 'gdbserver_1234_usr-bin-' + example_exe + '_m') | ||
2712 | gdb_script = os.path.join(self._workspace_scripts_dir( | ||
2713 | recipe_name), 'gdb_1234_usr-bin-' + example_exe) | ||
2714 | |||
2715 | # Start a gdbserver | ||
2716 | r = runCmd(gdbserver_script) | ||
2717 | self.assertEqual(r.status, 0) | ||
2718 | |||
2719 | # Check there is a gdbserver running | ||
2720 | r = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, 'ps')) | ||
2721 | self.assertEqual(r.status, 0) | ||
2722 | self.assertIn("gdbserver ", r.output) | ||
2723 | |||
2724 | # Check the pid file is correct | ||
2725 | test_cmd = "cat /proc/$(cat /tmp/gdbserver_1234_usr-bin-" + \ | ||
2726 | example_exe + "/pid)/cmdline" | ||
2727 | r = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, test_cmd)) | ||
2728 | self.assertEqual(r.status, 0) | ||
2729 | self.assertIn("gdbserver", r.output) | ||
2730 | |||
2731 | # Test remote debugging works | ||
2732 | gdb_batch_cmd = " --batch -ex 'break main' -ex 'run'" | ||
2733 | gdb_batch_cmd += " -ex 'break CppExample::print_json()' -ex 'continue'" | ||
2734 | gdb_batch_cmd += " -ex 'print CppExample::test_string.compare(\"cpp-example-lib %s\")'" % magic_string | ||
2735 | gdb_batch_cmd += " -ex 'print CppExample::test_string.compare(\"cpp-example-lib %saaa\")'" % magic_string | ||
2736 | gdb_batch_cmd += " -ex 'list cpp-example-lib.hpp:13,13'" | ||
2737 | gdb_batch_cmd += " -ex 'continue'" | ||
2738 | r = runCmd(gdb_script + gdb_batch_cmd) | ||
2739 | self.logger.debug("%s %s returned: %s", gdb_script, | ||
2740 | gdb_batch_cmd, r.output) | ||
2741 | self.assertEqual(r.status, 0) | ||
2742 | self.assertIn("Breakpoint 1, main", r.output) | ||
2743 | self.assertIn("$1 = 0", r.output) # test.string.compare equal | ||
2744 | self.assertIn("$2 = -3", r.output) # test.string.compare longer | ||
2745 | self.assertIn( | ||
2746 | 'inline static const std::string test_string = "cpp-example-lib %s";' % magic_string, r.output) | ||
2747 | self.assertIn("exited normally", r.output) | ||
2748 | |||
2749 | # Stop the gdbserver | ||
2750 | r = runCmd(gdbserver_script + ' stop') | ||
2751 | self.assertEqual(r.status, 0) | ||
2752 | |||
2753 | # Check there is no gdbserver running | ||
2754 | r = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, 'ps')) | ||
2755 | self.assertEqual(r.status, 0) | ||
2756 | self.assertNotIn("gdbserver ", r.output) | ||
2757 | |||
2758 | def _verify_cmake_preset(self, tempdir): | ||
2759 | """Verify the generated cmake preset works as expected | ||
2760 | |||
2761 | Check if compiling works | ||
2762 | Check if unit tests can be executed in qemu (not qemu-system) | ||
2763 | """ | ||
2764 | with open(os.path.join(tempdir, 'CMakeUserPresets.json')) as cmake_preset_j: | ||
2765 | cmake_preset_d = json.load(cmake_preset_j) | ||
2766 | config_presets = cmake_preset_d["configurePresets"] | ||
2767 | self.assertEqual(len(config_presets), 1) | ||
2768 | cmake_exe = config_presets[0]["cmakeExecutable"] | ||
2769 | preset_name = config_presets[0]["name"] | ||
2770 | |||
2771 | # Verify the wrapper for cmake native is available | ||
2772 | self.assertExists(cmake_exe) | ||
2773 | |||
2774 | # Verify the cmake preset generated by devtool ide-sdk is available | ||
2775 | result = runCmd('%s --list-presets' % cmake_exe, cwd=tempdir) | ||
2776 | self.assertIn(preset_name, result.output) | ||
2777 | |||
2778 | # Verify cmake re-uses the o files compiled by bitbake | ||
2779 | result = runCmd('%s --build --preset %s' % | ||
2780 | (cmake_exe, preset_name), cwd=tempdir) | ||
2781 | self.assertIn("ninja: no work to do.", result.output) | ||
2782 | |||
2783 | # Verify the unit tests work (in Qemu user mode) | ||
2784 | result = runCmd('%s --build --preset %s --target test' % | ||
2785 | (cmake_exe, preset_name), cwd=tempdir) | ||
2786 | self.assertIn("100% tests passed", result.output) | ||
2787 | |||
2788 | # Verify re-building and testing works again | ||
2789 | result = runCmd('%s --build --preset %s --target clean' % | ||
2790 | (cmake_exe, preset_name), cwd=tempdir) | ||
2791 | self.assertIn("Cleaning", result.output) | ||
2792 | result = runCmd('%s --build --preset %s' % | ||
2793 | (cmake_exe, preset_name), cwd=tempdir) | ||
2794 | self.assertIn("Building", result.output) | ||
2795 | self.assertIn("Linking", result.output) | ||
2796 | result = runCmd('%s --build --preset %s --target test' % | ||
2797 | (cmake_exe, preset_name), cwd=tempdir) | ||
2798 | self.assertIn("Running tests...", result.output) | ||
2799 | self.assertIn("100% tests passed", result.output) | ||
2800 | |||
2801 | @OETestTag("runqemu") | ||
2802 | def test_devtool_ide_sdk_none_qemu(self): | ||
2803 | """Start qemu-system and run tests for multiple recipes. ide=none is used.""" | ||
2804 | recipe_names = ["cmake-example", "meson-example"] | ||
2805 | testimage = "oe-selftest-image" | ||
2806 | |||
2807 | self._check_workspace() | ||
2808 | self._write_bb_config(recipe_names) | ||
2809 | self._check_runqemu_prerequisites() | ||
2810 | |||
2811 | # Verify deployment to Qemu (system mode) works | ||
2812 | bitbake(testimage) | ||
2813 | with runqemu(testimage, runqemuparams="nographic") as qemu: | ||
2814 | # cmake-example recipe | ||
2815 | recipe_name = "cmake-example" | ||
2816 | example_exe = "cmake-example" | ||
2817 | build_file = "CMakeLists.txt" | ||
2818 | tempdir = self._devtool_ide_sdk_recipe( | ||
2819 | recipe_name, build_file, testimage) | ||
2820 | bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --ide=none' % ( | ||
2821 | recipe_name, testimage, qemu.ip) | ||
2822 | runCmd(bitbake_sdk_cmd) | ||
2823 | self._gdb_cross() | ||
2824 | self._verify_cmake_preset(tempdir) | ||
2825 | self._devtool_ide_sdk_qemu(tempdir, qemu, recipe_name, example_exe) | ||
2826 | # Verify the oe-scripts sym-link is valid | ||
2827 | self.assertEqual(self._workspace_scripts_dir( | ||
2828 | recipe_name), self._sources_scripts_dir(tempdir)) | ||
2829 | |||
2830 | # meson-example recipe | ||
2831 | recipe_name = "meson-example" | ||
2832 | example_exe = "mesonex" | ||
2833 | build_file = "meson.build" | ||
2834 | tempdir = self._devtool_ide_sdk_recipe( | ||
2835 | recipe_name, build_file, testimage) | ||
2836 | bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --ide=none' % ( | ||
2837 | recipe_name, testimage, qemu.ip) | ||
2838 | runCmd(bitbake_sdk_cmd) | ||
2839 | self._gdb_cross() | ||
2840 | self._devtool_ide_sdk_qemu(tempdir, qemu, recipe_name, example_exe) | ||
2841 | # Verify the oe-scripts sym-link is valid | ||
2842 | self.assertEqual(self._workspace_scripts_dir( | ||
2843 | recipe_name), self._sources_scripts_dir(tempdir)) | ||
2844 | |||
2845 | def test_devtool_ide_sdk_code_cmake(self): | ||
2846 | """Verify a cmake recipe works with ide=code mode""" | ||
2847 | recipe_name = "cmake-example" | ||
2848 | build_file = "CMakeLists.txt" | ||
2849 | testimage = "oe-selftest-image" | ||
2850 | |||
2851 | self._check_workspace() | ||
2852 | self._write_bb_config([recipe_name]) | ||
2853 | tempdir = self._devtool_ide_sdk_recipe( | ||
2854 | recipe_name, build_file, testimage) | ||
2855 | bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@192.168.17.17 -c --ide=code' % ( | ||
2856 | recipe_name, testimage) | ||
2857 | runCmd(bitbake_sdk_cmd) | ||
2858 | self._verify_cmake_preset(tempdir) | ||
2859 | self._verify_install_script_code(tempdir, recipe_name) | ||
2860 | self._gdb_cross() | ||
2861 | |||
2862 | def test_devtool_ide_sdk_code_meson(self): | ||
2863 | """Verify a meson recipe works with ide=code mode""" | ||
2864 | recipe_name = "meson-example" | ||
2865 | build_file = "meson.build" | ||
2866 | testimage = "oe-selftest-image" | ||
2867 | |||
2868 | self._check_workspace() | ||
2869 | self._write_bb_config([recipe_name]) | ||
2870 | tempdir = self._devtool_ide_sdk_recipe( | ||
2871 | recipe_name, build_file, testimage) | ||
2872 | bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@192.168.17.17 -c --ide=code' % ( | ||
2873 | recipe_name, testimage) | ||
2874 | runCmd(bitbake_sdk_cmd) | ||
2875 | |||
2876 | with open(os.path.join(tempdir, '.vscode', 'settings.json')) as settings_j: | ||
2877 | settings_d = json.load(settings_j) | ||
2878 | meson_exe = settings_d["mesonbuild.mesonPath"] | ||
2879 | meson_build_folder = settings_d["mesonbuild.buildFolder"] | ||
2880 | |||
2881 | # Verify the wrapper for meson native is available | ||
2882 | self.assertExists(meson_exe) | ||
2883 | |||
2884 | # Verify meson re-uses the o files compiled by bitbake | ||
2885 | result = runCmd('%s compile -C %s' % | ||
2886 | (meson_exe, meson_build_folder), cwd=tempdir) | ||
2887 | self.assertIn("ninja: no work to do.", result.output) | ||
2888 | |||
2889 | # Verify the unit tests work (in Qemu) | ||
2890 | runCmd('%s test -C %s' % (meson_exe, meson_build_folder), cwd=tempdir) | ||
2891 | |||
2892 | # Verify re-building and testing works again | ||
2893 | result = runCmd('%s compile -C %s --clean' % | ||
2894 | (meson_exe, meson_build_folder), cwd=tempdir) | ||
2895 | self.assertIn("Cleaning...", result.output) | ||
2896 | result = runCmd('%s compile -C %s' % | ||
2897 | (meson_exe, meson_build_folder), cwd=tempdir) | ||
2898 | self.assertIn("Linking target", result.output) | ||
2899 | runCmd('%s test -C %s' % (meson_exe, meson_build_folder), cwd=tempdir) | ||
2900 | |||
2901 | self._verify_install_script_code(tempdir, recipe_name) | ||
2902 | self._gdb_cross() | ||
2903 | |||
2904 | def test_devtool_ide_sdk_shared_sysroots(self): | ||
2905 | """Verify the shared sysroot SDK""" | ||
2906 | |||
2907 | # Handle the workspace (which is not needed by this test case) | ||
2908 | self._check_workspace() | ||
2909 | |||
2910 | result_init = runCmd( | ||
2911 | 'devtool ide-sdk -m shared oe-selftest-image cmake-example meson-example --ide=code') | ||
2912 | bb_vars = get_bb_vars( | ||
2913 | ['REAL_MULTIMACH_TARGET_SYS', 'DEPLOY_DIR_IMAGE', 'COREBASE'], "meta-ide-support") | ||
2914 | environment_script = 'environment-setup-%s' % bb_vars['REAL_MULTIMACH_TARGET_SYS'] | ||
2915 | deploydir = bb_vars['DEPLOY_DIR_IMAGE'] | ||
2916 | environment_script_path = os.path.join(deploydir, environment_script) | ||
2917 | cpp_example_src = os.path.join( | ||
2918 | bb_vars['COREBASE'], 'meta-selftest', 'recipes-test', 'cpp', 'files') | ||
2919 | |||
2920 | # Verify the cross environment script is available | ||
2921 | self.assertExists(environment_script_path) | ||
2922 | |||
2923 | def runCmdEnv(cmd, cwd): | ||
2924 | cmd = '/bin/sh -c ". %s > /dev/null && %s"' % ( | ||
2925 | environment_script_path, cmd) | ||
2926 | return runCmd(cmd, cwd) | ||
2927 | |||
2928 | # Verify building the C++ example works with CMake | ||
2929 | tempdir_cmake = tempfile.mkdtemp(prefix='devtoolqa') | ||
2930 | self.track_for_cleanup(tempdir_cmake) | ||
2931 | |||
2932 | result_cmake = runCmdEnv("which cmake", cwd=tempdir_cmake) | ||
2933 | cmake_native = os.path.normpath(result_cmake.output.strip()) | ||
2934 | self.assertExists(cmake_native) | ||
2935 | |||
2936 | runCmdEnv('cmake %s' % cpp_example_src, cwd=tempdir_cmake) | ||
2937 | runCmdEnv('cmake --build %s' % tempdir_cmake, cwd=tempdir_cmake) | ||
2938 | |||
2939 | # Verify the printed note really referres to a cmake executable | ||
2940 | cmake_native_code = "" | ||
2941 | for line in result_init.output.splitlines(): | ||
2942 | m = re.search(r'"cmake.cmakePath": "(.*)"', line) | ||
2943 | if m: | ||
2944 | cmake_native_code = m.group(1) | ||
2945 | break | ||
2946 | self.assertExists(cmake_native_code) | ||
2947 | self.assertEqual(cmake_native, cmake_native_code) | ||
2948 | |||
2949 | # Verify building the C++ example works with Meson | ||
2950 | tempdir_meson = tempfile.mkdtemp(prefix='devtoolqa') | ||
2951 | self.track_for_cleanup(tempdir_meson) | ||
2952 | |||
2953 | result_cmake = runCmdEnv("which meson", cwd=tempdir_meson) | ||
2954 | meson_native = os.path.normpath(result_cmake.output.strip()) | ||
2955 | self.assertExists(meson_native) | ||
2956 | |||
2957 | runCmdEnv('meson setup %s' % tempdir_meson, cwd=cpp_example_src) | ||
2958 | runCmdEnv('meson compile', cwd=tempdir_meson) | ||
2959 | |||
2960 | def test_devtool_ide_sdk_plugins(self): | ||
2961 | """Test that devtool ide-sdk can use plugins from other layers.""" | ||
2962 | |||
2963 | # We need a workspace layer and a modified recipe (but no image) | ||
2964 | modified_recipe_name = "meson-example" | ||
2965 | modified_build_file = "meson.build" | ||
2966 | testimage = "oe-selftest-image" | ||
2967 | shared_recipe_name = "cmake-example" | ||
2968 | |||
2969 | self._check_workspace() | ||
2970 | self._write_bb_config([modified_recipe_name]) | ||
2971 | tempdir = self._devtool_ide_sdk_recipe( | ||
2972 | modified_recipe_name, modified_build_file, None) | ||
2973 | |||
2974 | IDE_RE = re.compile(r'.*--ide \{(.*)\}.*') | ||
2975 | |||
2976 | def get_ides_from_help(help_str): | ||
2977 | m = IDE_RE.search(help_str) | ||
2978 | return m.group(1).split(',') | ||
2979 | |||
2980 | # verify the default plugins are available but the foo plugin is not | ||
2981 | result = runCmd('devtool ide-sdk -h') | ||
2982 | found_ides = get_ides_from_help(result.output) | ||
2983 | self.assertIn('code', found_ides) | ||
2984 | self.assertIn('none', found_ides) | ||
2985 | self.assertNotIn('foo', found_ides) | ||
2986 | |||
2987 | shared_config_file = os.path.join(tempdir, 'shared-config.txt') | ||
2988 | shared_config_str = 'Dummy shared IDE config' | ||
2989 | modified_config_file = os.path.join(tempdir, 'modified-config.txt') | ||
2990 | modified_config_str = 'Dummy modified IDE config' | ||
2991 | |||
2992 | # Generate a foo plugin in the workspace layer | ||
2993 | plugin_dir = os.path.join( | ||
2994 | self.workspacedir, 'lib', 'devtool', 'ide_plugins') | ||
2995 | os.makedirs(plugin_dir) | ||
2996 | plugin_code = 'from devtool.ide_plugins import IdeBase\n\n' | ||
2997 | plugin_code += 'class IdeFoo(IdeBase):\n' | ||
2998 | plugin_code += ' def setup_shared_sysroots(self, shared_env):\n' | ||
2999 | plugin_code += ' with open("%s", "w") as config_file:\n' % shared_config_file | ||
3000 | plugin_code += ' config_file.write("%s")\n\n' % shared_config_str | ||
3001 | plugin_code += ' def setup_modified_recipe(self, args, image_recipe, modified_recipe):\n' | ||
3002 | plugin_code += ' with open("%s", "w") as config_file:\n' % modified_config_file | ||
3003 | plugin_code += ' config_file.write("%s")\n\n' % modified_config_str | ||
3004 | plugin_code += 'def register_ide_plugin(ide_plugins):\n' | ||
3005 | plugin_code += ' ide_plugins["foo"] = IdeFoo\n' | ||
3006 | |||
3007 | plugin_py = os.path.join(plugin_dir, 'ide_foo.py') | ||
3008 | with open(plugin_py, 'w') as plugin_file: | ||
3009 | plugin_file.write(plugin_code) | ||
3010 | |||
3011 | # Verify the foo plugin is available as well | ||
3012 | result = runCmd('devtool ide-sdk -h') | ||
3013 | found_ides = get_ides_from_help(result.output) | ||
3014 | self.assertIn('code', found_ides) | ||
3015 | self.assertIn('none', found_ides) | ||
3016 | self.assertIn('foo', found_ides) | ||
3017 | |||
3018 | # Verify the foo plugin generates a shared config | ||
3019 | result = runCmd( | ||
3020 | 'devtool ide-sdk -m shared --skip-bitbake --ide foo %s' % shared_recipe_name) | ||
3021 | with open(shared_config_file) as shared_config: | ||
3022 | shared_config_new = shared_config.read() | ||
3023 | self.assertEqual(shared_config_str, shared_config_new) | ||
3024 | |||
3025 | # Verify the foo plugin generates a modified config | ||
3026 | result = runCmd('devtool ide-sdk --skip-bitbake --ide foo %s %s' % | ||
3027 | (modified_recipe_name, testimage)) | ||
3028 | with open(modified_config_file) as modified_config: | ||
3029 | modified_config_new = modified_config.read() | ||
3030 | self.assertEqual(modified_config_str, modified_config_new) | ||