blob: 23d55903fb3154073b4cea4387c1b3e794e2905c [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
2# SPDX-License-Identifier: MIT
3#
4
Brad Bishopd7bf8c12018-02-25 22:55:05 -05005import os
6import re
7import shutil
8import tempfile
9import glob
10import fnmatch
11
12import oeqa.utils.ftools as ftools
13from oeqa.selftest.case import OESelftestTestCase
14from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
15from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Brad Bishopd7bf8c12018-02-25 22:55:05 -050016
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080017oldmetapath = None
18
19def setUpModule():
20 import bb.utils
21
22 global templayerdir
23 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
24 corecopydir = os.path.join(templayerdir, 'core-copy')
25 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
26 edited_layers = []
27
28 # 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
30 # however things like COREBASE mean that you can't just copy meta, you
31 # need the whole repository.
32 def bblayers_edit_cb(layerpath, canonical_layerpath):
33 global oldmetapath
34 if not canonical_layerpath.endswith('/'):
35 # This helps us match exactly when we're using this path later
36 canonical_layerpath += '/'
37 if not edited_layers and canonical_layerpath.endswith('/meta/'):
38 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
39 edited_layers.append(layerpath)
40 oldmetapath = os.path.realpath(layerpath)
41 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
42 oldreporoot = result.output.rstrip()
43 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
44 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
45 # Now we need to copy any modified files
46 # You might ask "why not just copy the entire tree instead of
47 # cloning and doing this?" - well, the problem with that is
48 # TMPDIR or an equally large subdirectory might exist
49 # under COREBASE and we don't want to copy that, so we have
50 # to be selective.
51 result = runCmd('git status --porcelain', cwd=oldreporoot)
52 for line in result.output.splitlines():
53 if line.startswith(' M ') or line.startswith('?? '):
54 relpth = line.split()[1]
55 pth = os.path.join(oldreporoot, relpth)
56 if pth.startswith(canonical_layerpath):
57 if relpth.endswith('/'):
58 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050059 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060060 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080061 else:
62 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
63 bb.utils.mkdirhier(destdir)
64 shutil.copy2(pth, destdir)
65 return newmetapath
66 else:
67 return layerpath
68 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
69
70def tearDownModule():
71 if oldmetapath:
72 edited_layers = []
73 def bblayers_edit_cb(layerpath, canonical_layerpath):
74 if not edited_layers and canonical_layerpath.endswith('/meta'):
75 edited_layers.append(layerpath)
76 return oldmetapath
77 else:
78 return layerpath
79 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
80 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
81 shutil.rmtree(templayerdir)
82
Andrew Geissler595f6302022-01-24 19:11:47 +000083class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080084
85 def setUp(self):
86 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +000087 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080088 self.workspacedir = os.path.join(self.builddir, 'workspace')
89 self.assertTrue(not os.path.exists(self.workspacedir),
90 'This test cannot be run with a workspace directory '
91 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080092
93 def _check_src_repo(self, repo_dir):
94 """Check srctree git repository"""
95 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
96 'git repository for external source tree not found')
97 result = runCmd('git status --porcelain', cwd=repo_dir)
98 self.assertEqual(result.output.strip(), "",
99 'Created git repo is not clean')
100 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
101 self.assertEqual(result.output.strip(), "refs/heads/devtool",
102 'Wrong branch in git repo')
103
104 def _check_repo_status(self, repo_dir, expected_status):
105 """Check the worktree status of a repository"""
106 result = runCmd('git status . --porcelain',
107 cwd=repo_dir)
108 for line in result.output.splitlines():
109 for ind, (f_status, fn_re) in enumerate(expected_status):
110 if re.match(fn_re, line[3:]):
111 if f_status != line[:2]:
112 self.fail('Unexpected status in line: %s' % line)
113 expected_status.pop(ind)
114 break
115 else:
116 self.fail('Unexpected modified file in line: %s' % line)
117 if expected_status:
118 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500119
120 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
121 with open(recipefile, 'r') as f:
122 invar = None
123 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500124 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500125 for line in f:
126 var = None
127 if invar:
128 value = line.strip().strip('"')
129 if value.endswith('\\'):
130 invalue += ' ' + value[:-1].strip()
131 continue
132 else:
133 invalue += ' ' + value.strip()
134 var = invar
135 value = invalue
136 invar = None
137 elif '=' in line:
138 splitline = line.split('=', 1)
139 var = splitline[0].rstrip()
140 value = splitline[1].strip().strip('"')
141 if value.endswith('\\'):
142 invalue = value[:-1].strip()
143 invar = var
144 continue
145 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500146 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500147
148 if var and var in checkvars:
149 needvalue = checkvars.pop(var)
150 if needvalue is None:
151 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
152 if isinstance(needvalue, set):
153 if var == 'LICENSE':
154 value = set(value.split(' & '))
155 else:
156 value = set(value.split())
157 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
158
159
160 missingvars = {}
161 for var, value in checkvars.items():
162 if value is not None:
163 missingvars[var] = value
164 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
165
166 for inherit in checkinherits:
167 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
168
169 def _check_bbappend(self, testrecipe, recipefile, appenddir):
170 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
171 resultlines = result.output.splitlines()
172 inrecipe = False
173 bbappends = []
174 bbappendfile = None
175 for line in resultlines:
176 if inrecipe:
177 if line.startswith(' '):
178 bbappends.append(line.strip())
179 else:
180 break
181 elif line == '%s:' % os.path.basename(recipefile):
182 inrecipe = True
183 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
184 for bbappend in bbappends:
185 if bbappend.startswith(appenddir):
186 bbappendfile = bbappend
187 break
188 else:
189 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
190 return bbappendfile
191
192 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
193 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
194 if addlayer:
195 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
196 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
197
198 def _process_ls_output(self, output):
199 """
200 Convert ls -l output to a format we can reasonably compare from one context
201 to another (e.g. from host to target)
202 """
203 filelist = []
204 for line in output.splitlines():
205 splitline = line.split()
206 if len(splitline) < 8:
207 self.fail('_process_ls_output: invalid output line: %s' % line)
208 # Remove trailing . on perms
209 splitline[0] = splitline[0].rstrip('.')
210 # Remove leading . on paths
211 splitline[-1] = splitline[-1].lstrip('.')
212 # Drop fields we don't want to compare
213 del splitline[7]
214 del splitline[6]
215 del splitline[5]
216 del splitline[4]
217 del splitline[1]
218 filelist.append(' '.join(splitline))
219 return filelist
220
221
Andrew Geissler595f6302022-01-24 19:11:47 +0000222class DevtoolBase(DevtoolTestCase):
223
224 @classmethod
225 def setUpClass(cls):
226 super(DevtoolBase, cls).setUpClass()
227 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
228 cls.original_sstate = bb_vars['SSTATE_DIR']
229 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
230 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
231 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
232 % cls.original_sstate)
233
234 @classmethod
235 def tearDownClass(cls):
236 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
237 runCmd('rm -rf %s' % cls.devtool_sstate)
238 super(DevtoolBase, cls).tearDownClass()
239
240 def setUp(self):
241 """Test case setup function"""
242 super(DevtoolBase, self).setUp()
243 self.append_config(self.sstate_conf)
244
245
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500246class DevtoolTests(DevtoolBase):
247
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500248 def test_create_workspace(self):
249 # Check preconditions
250 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400251 self.assertTrue('\nworkspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf')
Brad Bishop96ff1982019-08-19 13:50:42 -0400252 # remove conf/devtool.conf to avoid it corrupting tests
253 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
254 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500255 # Try creating a workspace layer with a specific path
256 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
257 self.track_for_cleanup(tempdir)
258 result = runCmd('devtool create-workspace %s' % tempdir)
259 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
260 result = runCmd('bitbake-layers show-layers')
261 self.assertIn(tempdir, result.output)
262 # Try creating a workspace layer with the default path
263 self.track_for_cleanup(self.workspacedir)
264 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
265 result = runCmd('devtool create-workspace')
266 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
267 result = runCmd('bitbake-layers show-layers')
268 self.assertNotIn(tempdir, result.output)
269 self.assertIn(self.workspacedir, result.output)
270
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800271class DevtoolAddTests(DevtoolBase):
272
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500273 def test_devtool_add(self):
274 # Fetch source
275 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
276 self.track_for_cleanup(tempdir)
277 pn = 'pv'
278 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600279 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500280 result = runCmd('wget %s' % url, cwd=tempdir)
281 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
282 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
283 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
284 # Test devtool add
285 self.track_for_cleanup(self.workspacedir)
286 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
287 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
288 result = runCmd('devtool add %s %s' % (pn, srcdir))
289 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
290 # Test devtool status
291 result = runCmd('devtool status')
292 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
293 self.assertIn(recipepath, result.output)
294 self.assertIn(srcdir, result.output)
295 # Test devtool find-recipe
296 result = runCmd('devtool -q find-recipe %s' % pn)
297 self.assertEqual(recipepath, result.output.strip())
298 # Test devtool edit-recipe
299 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
300 self.assertEqual('123 %s' % recipepath, result.output.strip())
301 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
302 bitbake('%s -c cleansstate' % pn)
303 # Test devtool build
304 result = runCmd('devtool build %s' % pn)
305 bb_vars = get_bb_vars(['D', 'bindir'], pn)
306 installdir = bb_vars['D']
307 self.assertTrue(installdir, 'Could not query installdir variable')
308 bindir = bb_vars['bindir']
309 self.assertTrue(bindir, 'Could not query bindir variable')
310 if bindir[0] == '/':
311 bindir = bindir[1:]
312 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
313
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800315 # We need dbus built so that DEPENDS recognition works
316 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500317 # Fetch source from a remote URL, but do it outside of devtool
318 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
319 self.track_for_cleanup(tempdir)
320 pn = 'dbus-wait'
321 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
322 # We choose an https:// git URL here to check rewriting the URL works
323 url = 'https://git.yoctoproject.org/git/dbus-wait'
324 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
325 # instead of the directory name
326 result = runCmd('git clone %s noname' % url, cwd=tempdir)
327 srcdir = os.path.join(tempdir, 'noname')
328 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
329 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
330 # Test devtool add
331 self.track_for_cleanup(self.workspacedir)
332 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
333 # Don't specify a name since we should be able to auto-detect it
334 result = runCmd('devtool add %s' % srcdir)
335 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
336 # Check the recipe name is correct
337 recipefile = get_bb_var('FILE', pn)
338 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
339 self.assertIn(recipefile, result.output)
340 # Test devtool status
341 result = runCmd('devtool status')
342 self.assertIn(pn, result.output)
343 self.assertIn(srcdir, result.output)
344 self.assertIn(recipefile, result.output)
345 checkvars = {}
346 checkvars['LICENSE'] = 'GPLv2'
347 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
348 checkvars['S'] = '${WORKDIR}/git'
349 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000350 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500351 checkvars['SRCREV'] = srcrev
352 checkvars['DEPENDS'] = set(['dbus'])
353 self._test_recipe_contents(recipefile, checkvars, [])
354
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500355 def test_devtool_add_library(self):
356 # Fetch source
357 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
358 self.track_for_cleanup(tempdir)
359 version = '1.1'
360 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
361 result = runCmd('wget %s' % url, cwd=tempdir)
362 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
363 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
364 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
365 # Test devtool add (and use -V so we test that too)
366 self.track_for_cleanup(self.workspacedir)
367 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
368 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
369 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
370 # Test devtool status
371 result = runCmd('devtool status')
372 self.assertIn('libftdi', result.output)
373 self.assertIn(srcdir, result.output)
374 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
375 bitbake('libftdi -c cleansstate')
376 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
377 # There's also the matter of it installing cmake files to a path we don't
378 # normally cover, which triggers the installed-vs-shipped QA test we have
379 # within do_package
380 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
381 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
382 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500383 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500384 # We don't have the ability to pick up this dependency automatically yet...
385 f.write('\nDEPENDS += "libusb1"\n')
386 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
387 # Test devtool build
388 result = runCmd('devtool build libftdi')
389 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
390 staging_libdir = bb_vars['TESTLIBOUTPUT']
391 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
392 self.assertTrue(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), "libftdi binary not found in STAGING_LIBDIR. Output of devtool build libftdi %s" % result.output)
393 # Test devtool reset
394 stampprefix = bb_vars['STAMP']
395 result = runCmd('devtool reset libftdi')
396 result = runCmd('devtool status')
397 self.assertNotIn('libftdi', result.output)
398 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
399 matches = glob.glob(stampprefix + '*')
400 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
401 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
402
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500403 def test_devtool_add_fetch(self):
404 # Fetch source
405 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
406 self.track_for_cleanup(tempdir)
407 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400408 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500409 testrecipe = 'python-markupsafe'
410 srcdir = os.path.join(tempdir, testrecipe)
411 # Test devtool add
412 self.track_for_cleanup(self.workspacedir)
413 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
414 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
415 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
416 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
417 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
418 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
419 # Test devtool status
420 result = runCmd('devtool status')
421 self.assertIn(testrecipe, result.output)
422 self.assertIn(srcdir, result.output)
423 # Check recipe
424 recipefile = get_bb_var('FILE', testrecipe)
425 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
426 checkvars = {}
427 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
428 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
429 self._test_recipe_contents(recipefile, checkvars, [])
430 # Try with version specified
431 result = runCmd('devtool reset -n %s' % testrecipe)
432 shutil.rmtree(srcdir)
433 fakever = '1.9'
434 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
435 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
436 # Test devtool status
437 result = runCmd('devtool status')
438 self.assertIn(testrecipe, result.output)
439 self.assertIn(srcdir, result.output)
440 # Check recipe
441 recipefile = get_bb_var('FILE', testrecipe)
442 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
443 checkvars = {}
444 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
445 checkvars['SRC_URI'] = url
446 self._test_recipe_contents(recipefile, checkvars, [])
447
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500448 def test_devtool_add_fetch_git(self):
449 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
450 self.track_for_cleanup(tempdir)
451 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000452 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500453 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
454 testrecipe = 'mraa'
455 srcdir = os.path.join(tempdir, testrecipe)
456 # Test devtool add
457 self.track_for_cleanup(self.workspacedir)
458 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
459 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
460 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
461 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
462 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
463 # Test devtool status
464 result = runCmd('devtool status')
465 self.assertIn(testrecipe, result.output)
466 self.assertIn(srcdir, result.output)
467 # Check recipe
468 recipefile = get_bb_var('FILE', testrecipe)
469 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
470 checkvars = {}
471 checkvars['S'] = '${WORKDIR}/git'
472 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000473 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474 checkvars['SRCREV'] = '${AUTOREV}'
475 self._test_recipe_contents(recipefile, checkvars, [])
476 # Try with revision and version specified
477 result = runCmd('devtool reset -n %s' % testrecipe)
478 shutil.rmtree(srcdir)
479 url_rev = '%s;rev=%s' % (url, checkrev)
480 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
481 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
482 # Test devtool status
483 result = runCmd('devtool status')
484 self.assertIn(testrecipe, result.output)
485 self.assertIn(srcdir, result.output)
486 # Check recipe
487 recipefile = get_bb_var('FILE', testrecipe)
488 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
489 checkvars = {}
490 checkvars['S'] = '${WORKDIR}/git'
491 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000492 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500493 checkvars['SRCREV'] = checkrev
494 self._test_recipe_contents(recipefile, checkvars, [])
495
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500496 def test_devtool_add_fetch_simple(self):
497 # Fetch source from a remote URL, auto-detecting name
498 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
499 self.track_for_cleanup(tempdir)
500 testver = '1.6.0'
501 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
502 testrecipe = 'pv'
503 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
504 # Test devtool add
505 self.track_for_cleanup(self.workspacedir)
506 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
507 result = runCmd('devtool add %s' % url)
508 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
509 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
510 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
511 # Test devtool status
512 result = runCmd('devtool status')
513 self.assertIn(testrecipe, result.output)
514 self.assertIn(srcdir, result.output)
515 # Check recipe
516 recipefile = get_bb_var('FILE', testrecipe)
517 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
518 checkvars = {}
519 checkvars['S'] = None
520 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
521 self._test_recipe_contents(recipefile, checkvars, [])
522
Andrew Geissler82c905d2020-04-13 13:39:40 -0500523 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600524 collections = get_bb_var('BBFILE_COLLECTIONS').split()
525 if "openembedded-layer" not in collections:
526 self.skipTest("Test needs meta-oe for nodejs")
527
Andrew Geissler82c905d2020-04-13 13:39:40 -0500528 pn = 'savoirfairelinux-node-server-example'
529 pv = '1.0.0'
530 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
531 # Test devtool add
532 self.track_for_cleanup(self.workspacedir)
533 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
534 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
535 result = runCmd('devtool add \'%s\'' % url)
536 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
537 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
538 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
539 # Test devtool status
540 result = runCmd('devtool status')
541 self.assertIn(pn, result.output)
542 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
543 bitbake('%s -c cleansstate' % pn)
544 # Test devtool build
545 result = runCmd('devtool build %s' % pn)
546
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800547class DevtoolModifyTests(DevtoolBase):
548
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500549 def test_devtool_modify(self):
550 import oe.path
551
552 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
553 self.track_for_cleanup(tempdir)
554 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500555 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400556 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500557 result = runCmd('devtool modify mdadm -x %s' % tempdir)
558 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
559 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
560 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
561 self.assertTrue(matches, 'bbappend not created %s' % result.output)
562
563 # Test devtool status
564 result = runCmd('devtool status')
565 self.assertIn('mdadm', result.output)
566 self.assertIn(tempdir, result.output)
567 self._check_src_repo(tempdir)
568
569 bitbake('mdadm -C unpack')
570
571 def check_line(checkfile, expected, message, present=True):
572 # Check for $expected, on a line on its own, in checkfile.
573 with open(checkfile, 'r') as f:
574 if present:
575 self.assertIn(expected + '\n', f, message)
576 else:
577 self.assertNotIn(expected + '\n', f, message)
578
579 modfile = os.path.join(tempdir, 'mdadm.8.in')
580 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
581 pkgd = bb_vars['PKGD']
582 self.assertTrue(pkgd, 'Could not query PKGD variable')
583 mandir = bb_vars['mandir']
584 self.assertTrue(mandir, 'Could not query mandir variable')
585 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
586
587 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
588 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
589
590 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
591 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
592
593 bitbake('mdadm -c package')
594 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
595
596 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
597 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
598
599 bitbake('mdadm -c package')
600 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
601
602 result = runCmd('devtool reset mdadm')
603 result = runCmd('devtool status')
604 self.assertNotIn('mdadm', result.output)
605
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500606 def test_devtool_buildclean(self):
607 def assertFile(path, *paths):
608 f = os.path.join(path, *paths)
609 self.assertExists(f)
610 def assertNoFile(path, *paths):
611 f = os.path.join(path, *paths)
612 self.assertNotExists(f)
613
614 # Clean up anything in the workdir/sysroot/sstate cache
615 bitbake('mdadm m4 -c cleansstate')
616 # Try modifying a recipe
617 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
618 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
619 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
620 self.track_for_cleanup(tempdir_mdadm)
621 self.track_for_cleanup(tempdir_m4)
622 self.track_for_cleanup(builddir_m4)
623 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400625 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500626 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
627 try:
628 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
629 runCmd('devtool modify m4 -x %s' % tempdir_m4)
630 assertNoFile(tempdir_mdadm, 'mdadm')
631 assertNoFile(builddir_m4, 'src/m4')
632 result = bitbake('m4 -e')
633 result = bitbake('mdadm m4 -c compile')
634 self.assertEqual(result.status, 0)
635 assertFile(tempdir_mdadm, 'mdadm')
636 assertFile(builddir_m4, 'src/m4')
637 # Check that buildclean task exists and does call make clean
638 bitbake('mdadm m4 -c buildclean')
639 assertNoFile(tempdir_mdadm, 'mdadm')
640 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400641 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500642 bitbake('mdadm m4 -c compile')
643 assertFile(tempdir_mdadm, 'mdadm')
644 assertFile(builddir_m4, 'src/m4')
645 bitbake('mdadm m4 -c clean')
646 # Check that buildclean task is run before clean for B == S
647 assertNoFile(tempdir_mdadm, 'mdadm')
648 # Check that buildclean task is not run before clean for B != S
649 assertFile(builddir_m4, 'src/m4')
650 finally:
651 self.delete_recipeinc('m4')
652
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500653 def test_devtool_modify_invalid(self):
654 # Try modifying some recipes
655 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
656 self.track_for_cleanup(tempdir)
657 self.track_for_cleanup(self.workspacedir)
658 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
659
Andrew Geissler5199d832021-09-24 16:47:35 -0500660 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500661 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
662 result = runCmd('bitbake-layers show-recipes gcc-source*')
663 for line in result.output.splitlines():
664 # just match those lines that contain a real target
665 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
666 if m:
667 testrecipes.append(m.group('recipe'))
668 for testrecipe in testrecipes:
669 # Check it's a valid recipe
670 bitbake('%s -e' % testrecipe)
671 # devtool extract should fail
672 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
673 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
674 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
675 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
676 # devtool modify should fail
677 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
678 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
679 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
680
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500681 def test_devtool_modify_native(self):
682 # Check preconditions
683 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
684 # Try modifying some recipes
685 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
686 self.track_for_cleanup(tempdir)
687 self.track_for_cleanup(self.workspacedir)
688 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
689
690 bbclassextended = False
691 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500692 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500693 for testrecipe in testrecipes:
694 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
695 if not bbclassextended:
696 bbclassextended = checkextend
697 if not inheritnative:
698 inheritnative = not checkextend
699 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
700 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
701 result = runCmd('devtool build %s' % testrecipe)
702 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
703 result = runCmd('devtool reset %s' % testrecipe)
704 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
705
706 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
707 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600708 def test_devtool_modify_localfiles_only(self):
709 # Check preconditions
710 testrecipe = 'base-files'
711 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
712 foundlocalonly = False
713 correct_symlink = False
714 for item in src_uri:
715 if item.startswith('file://'):
716 if '.patch' not in item:
717 foundlocalonly = True
718 else:
719 foundlocalonly = False
720 break
721 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
722 # Clean up anything in the workdir/sysroot/sstate cache
723 bitbake('%s -c cleansstate' % testrecipe)
724 # Try modifying a recipe
725 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
726 self.track_for_cleanup(tempdir)
727 self.track_for_cleanup(self.workspacedir)
728 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
729 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
730 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
731 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
732 srclink = os.path.join(tempdir, 'share/dot.bashrc')
733 self.assertExists(srcfile, 'Extracted source could not be found')
734 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
735 correct_symlink = True
736 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500737
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600738 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
739 self.assertTrue(matches, 'bbappend not created')
740 # Test devtool status
741 result = runCmd('devtool status')
742 self.assertIn(testrecipe, result.output)
743 self.assertIn(tempdir, result.output)
744 # Try building
745 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500746
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500747 def test_devtool_modify_git(self):
748 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400749 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500750 src_uri = get_bb_var('SRC_URI', testrecipe)
751 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
752 # Clean up anything in the workdir/sysroot/sstate cache
753 bitbake('%s -c cleansstate' % testrecipe)
754 # Try modifying a recipe
755 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
756 self.track_for_cleanup(tempdir)
757 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500758 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400759 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500760 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400761 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500762 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400763 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500764 self.assertTrue(matches, 'bbappend not created')
765 # Test devtool status
766 result = runCmd('devtool status')
767 self.assertIn(testrecipe, result.output)
768 self.assertIn(tempdir, result.output)
769 # Check git repo
770 self._check_src_repo(tempdir)
771 # Try building
772 bitbake(testrecipe)
773
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500774 def test_devtool_modify_localfiles(self):
775 # Check preconditions
776 testrecipe = 'lighttpd'
777 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
778 foundlocal = False
779 for item in src_uri:
780 if item.startswith('file://') and '.patch' not in item:
781 foundlocal = True
782 break
783 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
784 # Clean up anything in the workdir/sysroot/sstate cache
785 bitbake('%s -c cleansstate' % testrecipe)
786 # Try modifying a recipe
787 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
788 self.track_for_cleanup(tempdir)
789 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500790 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400791 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500792 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
793 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
794 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
795 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
796 self.assertTrue(matches, 'bbappend not created')
797 # Test devtool status
798 result = runCmd('devtool status')
799 self.assertIn(testrecipe, result.output)
800 self.assertIn(tempdir, result.output)
801 # Try building
802 bitbake(testrecipe)
803
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500804 def test_devtool_modify_virtual(self):
805 # Try modifying a virtual recipe
806 virtrecipe = 'virtual/make'
807 realrecipe = 'make'
808 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
809 self.track_for_cleanup(tempdir)
810 self.track_for_cleanup(self.workspacedir)
811 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
812 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
813 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
814 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
815 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
816 self.assertTrue(matches, 'bbappend not created %s' % result.output)
817 # Test devtool status
818 result = runCmd('devtool status')
819 self.assertNotIn(virtrecipe, result.output)
820 self.assertIn(realrecipe, result.output)
821 # Check git repo
822 self._check_src_repo(tempdir)
823 # This is probably sufficient
824
Andrew Geisslerf0343792020-11-18 10:42:21 -0600825 def test_devtool_modify_overrides(self):
826 # Try modifying a recipe with patches in overrides
827 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
828 self.track_for_cleanup(tempdir)
829 self.track_for_cleanup(self.workspacedir)
830 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
831 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
832
833 self._check_src_repo(tempdir)
834 source = os.path.join(tempdir, "source")
835 def check(branch, expected):
836 runCmd('git -C %s checkout %s' % (tempdir, branch))
837 with open(source, "rt") as f:
838 content = f.read()
839 self.assertEquals(content, expected)
840 check('devtool', 'This is a test for something\n')
841 check('devtool-no-overrides', 'This is a test for something\n')
842 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
843 check('devtool-override-qemux86', 'This is a test for qemux86\n')
844
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800845class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500846
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500847 def test_devtool_update_recipe(self):
848 # Check preconditions
849 testrecipe = 'minicom'
850 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
851 recipefile = bb_vars['FILE']
852 src_uri = bb_vars['SRC_URI']
853 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
854 self._check_repo_status(os.path.dirname(recipefile), [])
855 # First, modify a recipe
856 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
857 self.track_for_cleanup(tempdir)
858 self.track_for_cleanup(self.workspacedir)
859 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
860 # (don't bother with cleaning the recipe on teardown, we won't be building it)
861 # We don't use -x here so that we test the behaviour of devtool modify without it
862 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
863 # Check git repo
864 self._check_src_repo(tempdir)
865 # Add a couple of commits
866 # FIXME: this only tests adding, need to also test update and remove
867 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
868 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
869 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
870 result = runCmd('git add devtool-new-file', cwd=tempdir)
871 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
872 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
873 result = runCmd('devtool update-recipe %s' % testrecipe)
874 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
875 ('??', '.*/0001-Change-the-README.patch$'),
876 ('??', '.*/0002-Add-a-new-file.patch$')]
877 self._check_repo_status(os.path.dirname(recipefile), expected_status)
878
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500879 def test_devtool_update_recipe_git(self):
880 # Check preconditions
881 testrecipe = 'mtd-utils'
882 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
883 recipefile = bb_vars['FILE']
884 src_uri = bb_vars['SRC_URI']
885 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
886 patches = []
887 for entry in src_uri.split():
888 if entry.startswith('file://') and entry.endswith('.patch'):
889 patches.append(entry[7:].split(';')[0])
890 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
891 self._check_repo_status(os.path.dirname(recipefile), [])
892 # First, modify a recipe
893 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
894 self.track_for_cleanup(tempdir)
895 self.track_for_cleanup(self.workspacedir)
896 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
897 # (don't bother with cleaning the recipe on teardown, we won't be building it)
898 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
899 # Check git repo
900 self._check_src_repo(tempdir)
901 # Add a couple of commits
902 # FIXME: this only tests adding, need to also test update and remove
903 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
904 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
905 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
906 result = runCmd('git add devtool-new-file', cwd=tempdir)
907 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
908 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
909 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
910 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
911 [(' D', '.*/%s$' % patch) for patch in patches]
912 self._check_repo_status(os.path.dirname(recipefile), expected_status)
913
914 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000915 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500916 srcurilines = src_uri.split()
917 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
918 srcurilines.append('"')
919 removelines = ['SRCREV = ".*"'] + srcurilines
920 for line in result.output.splitlines():
921 if line.startswith('+++') or line.startswith('---'):
922 continue
923 elif line.startswith('+'):
924 matched = False
925 for item in addlines:
926 if re.match(item, line[1:].strip()):
927 matched = True
928 break
929 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
930 elif line.startswith('-'):
931 matched = False
932 for item in removelines:
933 if re.match(item, line[1:].strip()):
934 matched = True
935 break
936 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
937 # Now try with auto mode
938 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
939 result = runCmd('devtool update-recipe %s' % testrecipe)
940 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
941 topleveldir = result.output.strip()
942 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
943 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
944 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
945 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
946 self._check_repo_status(os.path.dirname(recipefile), expected_status)
947
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500948 def test_devtool_update_recipe_append(self):
949 # Check preconditions
950 testrecipe = 'mdadm'
951 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
952 recipefile = bb_vars['FILE']
953 src_uri = bb_vars['SRC_URI']
954 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
955 self._check_repo_status(os.path.dirname(recipefile), [])
956 # First, modify a recipe
957 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
958 tempsrcdir = os.path.join(tempdir, 'source')
959 templayerdir = os.path.join(tempdir, 'layer')
960 self.track_for_cleanup(tempdir)
961 self.track_for_cleanup(self.workspacedir)
962 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
963 # (don't bother with cleaning the recipe on teardown, we won't be building it)
964 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
965 # Check git repo
966 self._check_src_repo(tempsrcdir)
967 # Add a commit
968 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
969 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
970 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
971 # Create a temporary layer and add it to bblayers.conf
972 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
973 # Create the bbappend
974 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
975 self.assertNotIn('WARNING:', result.output)
976 # Check recipe is still clean
977 self._check_repo_status(os.path.dirname(recipefile), [])
978 # Check bbappend was created
979 splitpath = os.path.dirname(recipefile).split(os.sep)
980 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
981 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
982 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
983 self.assertExists(patchfile, 'Patch file not created')
984
985 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -0500986 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500987 '\n',
988 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
989 '\n']
990 with open(bbappendfile, 'r') as f:
991 self.assertEqual(expectedlines, f.readlines())
992
993 # Check we can run it again and bbappend isn't modified
994 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
995 with open(bbappendfile, 'r') as f:
996 self.assertEqual(expectedlines, f.readlines())
997 # Drop new commit and check patch gets deleted
998 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
999 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1000 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001001 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001002 '\n']
1003 with open(bbappendfile, 'r') as f:
1004 self.assertEqual(expectedlines2, f.readlines())
1005 # Put commit back and check we can run it if layer isn't in bblayers.conf
1006 os.remove(bbappendfile)
1007 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1008 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1009 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1010 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1011 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1012 with open(bbappendfile, 'r') as f:
1013 self.assertEqual(expectedlines, f.readlines())
1014 # Deleting isn't expected to work under these circumstances
1015
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001016 def test_devtool_update_recipe_append_git(self):
1017 # Check preconditions
1018 testrecipe = 'mtd-utils'
1019 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1020 recipefile = bb_vars['FILE']
1021 src_uri = bb_vars['SRC_URI']
1022 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1023 for entry in src_uri.split():
1024 if entry.startswith('git://'):
1025 git_uri = entry
1026 break
1027 self._check_repo_status(os.path.dirname(recipefile), [])
1028 # First, modify a recipe
1029 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1030 tempsrcdir = os.path.join(tempdir, 'source')
1031 templayerdir = os.path.join(tempdir, 'layer')
1032 self.track_for_cleanup(tempdir)
1033 self.track_for_cleanup(self.workspacedir)
1034 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1035 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1036 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1037 # Check git repo
1038 self._check_src_repo(tempsrcdir)
1039 # Add a commit
1040 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1041 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1042 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1043 # Create a temporary layer
1044 os.makedirs(os.path.join(templayerdir, 'conf'))
1045 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1046 f.write('BBPATH .= ":${LAYERDIR}"\n')
1047 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1048 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1049 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1050 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1051 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -04001052 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001053 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1054 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1055 # Create the bbappend
1056 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1057 self.assertNotIn('WARNING:', result.output)
1058 # Check recipe is still clean
1059 self._check_repo_status(os.path.dirname(recipefile), [])
1060 # Check bbappend was created
1061 splitpath = os.path.dirname(recipefile).split(os.sep)
1062 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1063 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1064 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1065
1066 # Check bbappend contents
1067 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1068 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1069 '\n',
1070 'SRC_URI = "%s"\n' % git_uri,
1071 '\n'])
1072 with open(bbappendfile, 'r') as f:
1073 self.assertEqual(expectedlines, set(f.readlines()))
1074
1075 # Check we can run it again and bbappend isn't modified
1076 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1077 with open(bbappendfile, 'r') as f:
1078 self.assertEqual(expectedlines, set(f.readlines()))
1079 # Drop new commit and check SRCREV changes
1080 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1081 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1082 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1083 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1084 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1085 '\n',
1086 'SRC_URI = "%s"\n' % git_uri,
1087 '\n'])
1088 with open(bbappendfile, 'r') as f:
1089 self.assertEqual(expectedlines, set(f.readlines()))
1090 # Put commit back and check we can run it if layer isn't in bblayers.conf
1091 os.remove(bbappendfile)
1092 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1093 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1094 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1095 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1096 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1097 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1098 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1099 '\n',
1100 'SRC_URI = "%s"\n' % git_uri,
1101 '\n'])
1102 with open(bbappendfile, 'r') as f:
1103 self.assertEqual(expectedlines, set(f.readlines()))
1104 # Deleting isn't expected to work under these circumstances
1105
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001106 def test_devtool_update_recipe_local_files(self):
1107 """Check that local source files are copied over instead of patched"""
1108 testrecipe = 'makedevs'
1109 recipefile = get_bb_var('FILE', testrecipe)
1110 # Setup srctree for modifying the recipe
1111 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1112 self.track_for_cleanup(tempdir)
1113 self.track_for_cleanup(self.workspacedir)
1114 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1115 # (don't bother with cleaning the recipe on teardown, we won't be
1116 # building it)
1117 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1118 # Check git repo
1119 self._check_src_repo(tempdir)
1120 # Try building just to ensure we haven't broken that
1121 bitbake("%s" % testrecipe)
1122 # Edit / commit local source
1123 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1124 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1125 runCmd('echo "Bar" > new-file', cwd=tempdir)
1126 runCmd('git add new-file', cwd=tempdir)
1127 runCmd('git commit -m "Add new file"', cwd=tempdir)
1128 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1129 os.path.dirname(recipefile))
1130 runCmd('devtool update-recipe %s' % testrecipe)
1131 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1132 (' M', '.*/makedevs/makedevs.c$'),
1133 ('??', '.*/makedevs/new-local$'),
1134 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1135 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1136
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001137 def test_devtool_update_recipe_local_files_2(self):
1138 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001139 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001140 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001141 recipedir = os.path.dirname(recipefile)
1142 result = runCmd('git status --porcelain .', cwd=recipedir)
1143 if result.output.strip():
1144 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001145 # Setup srctree for modifying the 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-layers remove-layer */workspace')
1150 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1151 # Check git repo
1152 self._check_src_repo(tempdir)
1153 # Add oe-local-files to Git
1154 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1155 runCmd('git add oe-local-files', cwd=tempdir)
1156 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1157 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001158 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001159 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001160 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001161 runCmd('git commit -m"Remove file"', cwd=tempdir)
1162 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1163 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1164 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1165 runCmd('echo "Gar" > new-file', cwd=tempdir)
1166 runCmd('git add new-file', cwd=tempdir)
1167 runCmd('git commit -m "Add new file"', cwd=tempdir)
1168 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1169 os.path.dirname(recipefile))
1170 # Checkout unmodified file to working copy -> devtool should still pick
1171 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001172 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001173 runCmd('devtool update-recipe %s' % testrecipe)
1174 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001175 (' M', '.*/file1$'),
1176 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001177 ('??', '.*/new-local$'),
1178 ('??', '.*/0001-Add-new-file.patch$')]
1179 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1180
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001181 def test_devtool_update_recipe_with_gitignore(self):
1182 # First, modify the recipe
1183 testrecipe = 'devtool-test-ignored'
1184 bb_vars = get_bb_vars(['FILE'], testrecipe)
1185 recipefile = bb_vars['FILE']
1186 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1187 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1188 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1189 self.track_for_cleanup(tempdir)
1190 self.track_for_cleanup(self.workspacedir)
1191 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1192 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1193 result = runCmd('devtool modify %s' % testrecipe)
1194 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1195 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1196 # Check recipe got changed as expected
1197 with open(newpatchfile, 'r') as f:
1198 desiredlines = f.readlines()
1199 with open(patchfile, 'r') as f:
1200 newlines = f.readlines()
1201 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1202 # which changes the metadata subject which is added into the patch, but keep
1203 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1204 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1205 self.assertEqual(desiredlines[5:], newlines[5:])
1206
1207 def test_devtool_update_recipe_long_filename(self):
1208 # First, modify the recipe
1209 testrecipe = 'devtool-test-long-filename'
1210 bb_vars = get_bb_vars(['FILE'], testrecipe)
1211 recipefile = bb_vars['FILE']
1212 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1213 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1214 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1215 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1216 self.track_for_cleanup(tempdir)
1217 self.track_for_cleanup(self.workspacedir)
1218 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1219 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1220 result = runCmd('devtool modify %s' % testrecipe)
1221 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1222 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1223 # Check recipe got changed as expected
1224 with open(newpatchfile, 'r') as f:
1225 desiredlines = f.readlines()
1226 with open(patchfile, 'r') as f:
1227 newlines = f.readlines()
1228 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1229 # which changes the metadata subject which is added into the patch, but keep
1230 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1231 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1232 self.assertEqual(desiredlines[5:], newlines[5:])
1233
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001234 def test_devtool_update_recipe_local_files_3(self):
1235 # First, modify the recipe
1236 testrecipe = 'devtool-test-localonly'
1237 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1238 recipefile = bb_vars['FILE']
1239 src_uri = bb_vars['SRC_URI']
1240 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1241 self.track_for_cleanup(tempdir)
1242 self.track_for_cleanup(self.workspacedir)
1243 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1244 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1245 result = runCmd('devtool modify %s' % testrecipe)
1246 # Modify one file
1247 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1248 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1249 result = runCmd('devtool update-recipe %s' % testrecipe)
1250 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1251 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1252
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001253 def test_devtool_update_recipe_local_patch_gz(self):
1254 # First, modify the recipe
1255 testrecipe = 'devtool-test-patch-gz'
1256 if get_bb_var('DISTRO') == 'poky-tiny':
1257 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1258 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1259 recipefile = bb_vars['FILE']
1260 src_uri = bb_vars['SRC_URI']
1261 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1262 self.track_for_cleanup(tempdir)
1263 self.track_for_cleanup(self.workspacedir)
1264 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1265 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1266 result = runCmd('devtool modify %s' % testrecipe)
1267 # Modify one file
1268 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1269 runCmd('echo "Another line" >> README', cwd=srctree)
1270 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1271 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1272 result = runCmd('devtool update-recipe %s' % testrecipe)
1273 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1274 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1275 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1276 result = runCmd('file %s' % patch_gz)
1277 if 'gzip compressed data' not in result.output:
1278 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1279
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001280 def test_devtool_update_recipe_local_files_subdir(self):
1281 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1282 # SRC_URI such that it overwrites a file that was in an archive that
1283 # was also in SRC_URI
1284 # First, modify the recipe
1285 testrecipe = 'devtool-test-subdir'
1286 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1287 recipefile = bb_vars['FILE']
1288 src_uri = bb_vars['SRC_URI']
1289 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1290 self.track_for_cleanup(tempdir)
1291 self.track_for_cleanup(self.workspacedir)
1292 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1293 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1294 result = runCmd('devtool modify %s' % testrecipe)
1295 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1296 self.assertExists(testfile, 'Extracted source could not be found')
1297 with open(testfile, 'r') as f:
1298 contents = f.read().rstrip()
1299 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1300 # Test devtool update-recipe without modifying any files
1301 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1302 result = runCmd('devtool update-recipe %s' % testrecipe)
1303 expected_status = []
1304 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1305
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001306class DevtoolExtractTests(DevtoolBase):
1307
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001308 def test_devtool_extract(self):
1309 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1310 # Try devtool extract
1311 self.track_for_cleanup(tempdir)
1312 self.track_for_cleanup(self.workspacedir)
1313 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1314 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1315 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1316 self._check_src_repo(tempdir)
1317
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001318 def test_devtool_extract_virtual(self):
1319 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1320 # Try devtool extract
1321 self.track_for_cleanup(tempdir)
1322 self.track_for_cleanup(self.workspacedir)
1323 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1324 result = runCmd('devtool extract virtual/make %s' % tempdir)
1325 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1326 self._check_src_repo(tempdir)
1327
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001328 def test_devtool_reset_all(self):
1329 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1330 self.track_for_cleanup(tempdir)
1331 self.track_for_cleanup(self.workspacedir)
1332 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1333 testrecipe1 = 'mdadm'
1334 testrecipe2 = 'cronie'
1335 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1336 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1337 result = runCmd('devtool build %s' % testrecipe1)
1338 result = runCmd('devtool build %s' % testrecipe2)
1339 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1340 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1341 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1342 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1343 result = runCmd('devtool reset -a')
1344 self.assertIn(testrecipe1, result.output)
1345 self.assertIn(testrecipe2, result.output)
1346 result = runCmd('devtool status')
1347 self.assertNotIn(testrecipe1, result.output)
1348 self.assertNotIn(testrecipe2, result.output)
1349 matches1 = glob.glob(stampprefix1 + '*')
1350 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1351 matches2 = glob.glob(stampprefix2 + '*')
1352 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1353
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001354 def test_devtool_deploy_target(self):
1355 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1356 # unfortunately the runtime tests run under bitbake and you can't run
1357 # devtool within bitbake (since devtool needs to run bitbake itself).
1358 # Additionally we are testing build-time functionality as well, so
1359 # really this has to be done as an oe-selftest test.
1360 #
1361 # Check preconditions
1362 machine = get_bb_var('MACHINE')
1363 if not machine.startswith('qemu'):
1364 self.skipTest('This test only works with qemu machines')
1365 if not os.path.exists('/etc/runqemu-nosudo'):
1366 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1367 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1368 if result.status != 0:
1369 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1370 if result.status != 0:
1371 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1372 for line in result.output.splitlines():
1373 if line.startswith('tap'):
1374 break
1375 else:
1376 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1377 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1378 # Definitions
1379 testrecipe = 'mdadm'
1380 testfile = '/sbin/mdadm'
1381 testimage = 'oe-selftest-image'
1382 testcommand = '/sbin/mdadm --help'
1383 # Build an image to run
1384 bitbake("%s qemu-native qemu-helper-native" % testimage)
1385 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1386 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1387 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1388 # Clean recipe so the first deploy will fail
1389 bitbake("%s -c clean" % testrecipe)
1390 # Try devtool modify
1391 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1392 self.track_for_cleanup(tempdir)
1393 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001394 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001395 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001396 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1397 # Test that deploy-target at this point fails (properly)
1398 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1399 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1400 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1401 result = runCmd('devtool build %s' % testrecipe)
1402 # First try a dry-run of deploy-target
1403 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1404 self.assertIn(' %s' % testfile, result.output)
1405 # Boot the image
1406 with runqemu(testimage) as qemu:
1407 # Now really test deploy-target
1408 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1409 # Run a test command to see if it was installed properly
1410 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1411 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1412 # Check if it deployed all of the files with the right ownership/perms
1413 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1414 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1415 installdir = bb_vars['D']
1416 fakerootenv = bb_vars['FAKEROOTENV']
1417 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001418 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001419 filelist1 = self._process_ls_output(result.output)
1420
1421 # Now look on the target
1422 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1423 self.track_for_cleanup(tempdir2)
1424 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1425 with open(tmpfilelist, 'w') as f:
1426 for line in filelist1:
1427 splitline = line.split()
1428 f.write(splitline[-1] + '\n')
1429 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1430 filelist2 = self._process_ls_output(result.output)
1431 filelist1.sort(key=lambda item: item.split()[-1])
1432 filelist2.sort(key=lambda item: item.split()[-1])
1433 self.assertEqual(filelist1, filelist2)
1434 # Test undeploy-target
1435 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1436 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1437 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1438
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001439 def test_devtool_build_image(self):
1440 """Test devtool build-image plugin"""
1441 # Check preconditions
1442 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1443 image = 'core-image-minimal'
1444 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001445 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001446 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001447 bitbake('%s -c clean' % image)
1448 # Add target and native recipes to workspace
1449 recipes = ['mdadm', 'parted-native']
1450 for recipe in recipes:
1451 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1452 self.track_for_cleanup(tempdir)
1453 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1454 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1455 # Try to build image
1456 result = runCmd('devtool build-image %s' % image)
1457 self.assertNotEqual(result, 0, 'devtool build-image failed')
1458 # Check if image contains expected packages
1459 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1460 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1461 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1462 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1463 for line in f:
1464 splitval = line.split()
1465 if splitval:
1466 pkg = splitval[0]
1467 if pkg in reqpkgs:
1468 reqpkgs.remove(pkg)
1469 if reqpkgs:
1470 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1471
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001472class DevtoolUpgradeTests(DevtoolBase):
1473
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001474 def test_devtool_upgrade(self):
1475 # Check preconditions
1476 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1477 self.track_for_cleanup(self.workspacedir)
1478 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1479 # Check parameters
1480 result = runCmd('devtool upgrade -h')
1481 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1482 self.assertIn(param, result.output)
1483 # For the moment, we are using a real recipe.
1484 recipe = 'devtool-upgrade-test1'
1485 version = '1.6.0'
1486 oldrecipefile = get_bb_var('FILE', recipe)
1487 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1488 self.track_for_cleanup(tempdir)
1489 # Check that recipe is not already under devtool control
1490 result = runCmd('devtool status')
1491 self.assertNotIn(recipe, result.output)
1492 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1493 # we are downgrading instead of upgrading.
1494 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1495 # Check if srctree at least is populated
1496 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1497 # Check new recipe subdirectory is present
1498 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1499 # Check new recipe file is present
1500 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1501 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1502 # Check devtool status and make sure recipe is present
1503 result = runCmd('devtool status')
1504 self.assertIn(recipe, result.output)
1505 self.assertIn(tempdir, result.output)
1506 # Check recipe got changed as expected
1507 with open(oldrecipefile + '.upgraded', 'r') as f:
1508 desiredlines = f.readlines()
1509 with open(newrecipefile, 'r') as f:
1510 newlines = f.readlines()
1511 self.assertEqual(desiredlines, newlines)
1512 # Check devtool reset recipe
1513 result = runCmd('devtool reset %s -n' % recipe)
1514 result = runCmd('devtool status')
1515 self.assertNotIn(recipe, result.output)
1516 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1517
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001518 def test_devtool_upgrade_git(self):
1519 # Check preconditions
1520 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1521 self.track_for_cleanup(self.workspacedir)
1522 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1523 recipe = 'devtool-upgrade-test2'
1524 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1525 oldrecipefile = get_bb_var('FILE', recipe)
1526 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1527 self.track_for_cleanup(tempdir)
1528 # Check that recipe is not already under devtool control
1529 result = runCmd('devtool status')
1530 self.assertNotIn(recipe, result.output)
1531 # Check upgrade
1532 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1533 # Check if srctree at least is populated
1534 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1535 # Check new recipe file is present
1536 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1537 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1538 # Check devtool status and make sure recipe is present
1539 result = runCmd('devtool status')
1540 self.assertIn(recipe, result.output)
1541 self.assertIn(tempdir, result.output)
1542 # Check recipe got changed as expected
1543 with open(oldrecipefile + '.upgraded', 'r') as f:
1544 desiredlines = f.readlines()
1545 with open(newrecipefile, 'r') as f:
1546 newlines = f.readlines()
1547 self.assertEqual(desiredlines, newlines)
1548 # Check devtool reset recipe
1549 result = runCmd('devtool reset %s -n' % recipe)
1550 result = runCmd('devtool status')
1551 self.assertNotIn(recipe, result.output)
1552 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1553
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001554 def test_devtool_layer_plugins(self):
1555 """Test that devtool can use plugins from other layers.
1556
1557 This test executes the selftest-reverse command from meta-selftest."""
1558
1559 self.track_for_cleanup(self.workspacedir)
1560 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1561
1562 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1563 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1564 self.assertEqual(result.output, s[::-1])
1565
1566 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1567 dstdir = basedstdir
1568 self.assertExists(dstdir)
1569 for p in paths:
1570 dstdir = os.path.join(dstdir, p)
1571 if not os.path.exists(dstdir):
1572 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001573 if p == "lib":
1574 # Can race with other tests
1575 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1576 else:
1577 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001578 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1579 if srcfile != dstfile:
1580 shutil.copy(srcfile, dstfile)
1581 self.track_for_cleanup(dstfile)
1582
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001583 def test_devtool_load_plugin(self):
1584 """Test that devtool loads only the first found plugin in BBPATH."""
1585
1586 self.track_for_cleanup(self.workspacedir)
1587 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1588
1589 devtool = runCmd("which devtool")
1590 fromname = runCmd("devtool --quiet pluginfile")
1591 srcfile = fromname.output
1592 bbpath = get_bb_var('BBPATH')
1593 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1594 plugincontent = []
1595 with open(srcfile) as fh:
1596 plugincontent = fh.readlines()
1597 try:
1598 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1599 for path in searchpath:
1600 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1601 result = runCmd("devtool --quiet count")
1602 self.assertEqual(result.output, '1')
1603 result = runCmd("devtool --quiet multiloaded")
1604 self.assertEqual(result.output, "no")
1605 for path in searchpath:
1606 result = runCmd("devtool --quiet bbdir")
1607 self.assertEqual(result.output, path)
1608 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1609 finally:
1610 with open(srcfile, 'w') as fh:
1611 fh.writelines(plugincontent)
1612
1613 def _setup_test_devtool_finish_upgrade(self):
1614 # Check preconditions
1615 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1616 self.track_for_cleanup(self.workspacedir)
1617 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1618 # Use a "real" recipe from meta-selftest
1619 recipe = 'devtool-upgrade-test1'
1620 oldversion = '1.5.3'
1621 newversion = '1.6.0'
1622 oldrecipefile = get_bb_var('FILE', recipe)
1623 recipedir = os.path.dirname(oldrecipefile)
1624 result = runCmd('git status --porcelain .', cwd=recipedir)
1625 if result.output.strip():
1626 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1627 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1628 self.track_for_cleanup(tempdir)
1629 # Check that recipe is not already under devtool control
1630 result = runCmd('devtool status')
1631 self.assertNotIn(recipe, result.output)
1632 # Do the upgrade
1633 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1634 # Check devtool status and make sure recipe is present
1635 result = runCmd('devtool status')
1636 self.assertIn(recipe, result.output)
1637 self.assertIn(tempdir, result.output)
1638 # Make a change to the source
1639 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1640 result = runCmd('git status --porcelain', cwd=tempdir)
1641 self.assertIn('M src/pv/number.c', result.output)
1642 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1643 # Check if patch is there
1644 recipedir = os.path.dirname(oldrecipefile)
1645 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1646 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001647 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001648 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001649 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1650 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001651
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001652 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001653 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001654 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1655 self.assertIn('/meta-selftest/', recipedir)
1656 # Try finish to the original layer
1657 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1658 result = runCmd('devtool finish %s meta-selftest' % recipe)
1659 result = runCmd('devtool status')
1660 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1661 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1662 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1663 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001664 self.assertNotExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should have been deleted but wasn\'t')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001665 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1666 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1667 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1668 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001669 self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001670 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001671 with open(newrecipefile, 'r') as f:
1672 newcontent = f.read()
1673 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1674 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1675 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1676 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1677
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001678
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001679 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001680 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001681 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1682 self.assertIn('/meta-selftest/', recipedir)
1683 # Try finish to a different layer - should create a bbappend
1684 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1685 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1686 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1687 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1688 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1689 self.track_for_cleanup(newrecipedir)
1690 result = runCmd('devtool finish %s oe-core' % recipe)
1691 result = runCmd('devtool status')
1692 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1693 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1694 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1695 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001696 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001697 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1698 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1699 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001700 self.assertNotExists(os.path.join(newdir, backportedpatchfn), 'Backported patch file should not have been copied into new directory but was')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001701 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001702 with open(newrecipefile, 'r') as f:
1703 newcontent = f.read()
1704 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1705 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1706 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1707 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001708
1709 def _setup_test_devtool_finish_modify(self):
1710 # Check preconditions
1711 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1712 # Try modifying a recipe
1713 self.track_for_cleanup(self.workspacedir)
1714 recipe = 'mdadm'
1715 oldrecipefile = get_bb_var('FILE', recipe)
1716 recipedir = os.path.dirname(oldrecipefile)
1717 result = runCmd('git status --porcelain .', cwd=recipedir)
1718 if result.output.strip():
1719 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1720 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1721 self.track_for_cleanup(tempdir)
1722 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1723 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1724 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1725 # Test devtool status
1726 result = runCmd('devtool status')
1727 self.assertIn(recipe, result.output)
1728 self.assertIn(tempdir, result.output)
1729 # Make a change to the source
1730 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1731 result = runCmd('git status --porcelain', cwd=tempdir)
1732 self.assertIn('M maps.c', result.output)
1733 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1734 for entry in os.listdir(recipedir):
1735 filesdir = os.path.join(recipedir, entry)
1736 if os.path.isdir(filesdir):
1737 break
1738 else:
1739 self.fail('Unable to find recipe files directory for %s' % recipe)
1740 return recipe, oldrecipefile, recipedir, filesdir
1741
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001742 def test_devtool_finish_modify_origlayer(self):
1743 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1744 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1745 self.assertIn('/meta/', recipedir)
1746 # Try finish to the original layer
1747 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1748 result = runCmd('devtool finish %s meta' % recipe)
1749 result = runCmd('devtool status')
1750 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1751 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1752 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1753 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1754 self._check_repo_status(recipedir, expected_status)
1755
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001756 def test_devtool_finish_modify_otherlayer(self):
1757 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1758 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1759 self.assertIn('/meta/', recipedir)
1760 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1761 appenddir = os.path.join(get_test_layer(), relpth)
1762 self.track_for_cleanup(appenddir)
1763 # Try finish to the original layer
1764 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1765 result = runCmd('devtool finish %s meta-selftest' % recipe)
1766 result = runCmd('devtool status')
1767 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1768 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1769 result = runCmd('git status --porcelain .', cwd=recipedir)
1770 if result.output.strip():
1771 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1772 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1773 recipefn = recipefn.split('_')[0] + '_%'
1774 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1775 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1776 newdir = os.path.join(appenddir, recipe)
1777 files = os.listdir(newdir)
1778 foundpatch = None
1779 for fn in files:
1780 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1781 foundpatch = fn
1782 if not foundpatch:
1783 self.fail('No patch file created next to bbappend')
1784 files.remove(foundpatch)
1785 if files:
1786 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1787
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001788 def test_devtool_rename(self):
1789 # Check preconditions
1790 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1791 self.track_for_cleanup(self.workspacedir)
1792 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1793
1794 # First run devtool add
1795 # We already have this recipe in OE-Core, but that doesn't matter
1796 recipename = 'i2c-tools'
1797 recipever = '3.1.2'
1798 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1799 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1800 def add_recipe():
1801 result = runCmd('devtool add %s' % url)
1802 self.assertExists(recipefile, 'Expected recipe file not created')
1803 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1804 checkvars = {}
1805 checkvars['S'] = None
1806 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1807 self._test_recipe_contents(recipefile, checkvars, [])
1808 add_recipe()
1809 # Now rename it - change both name and version
1810 newrecipename = 'mynewrecipe'
1811 newrecipever = '456'
1812 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1813 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1814 self.assertExists(newrecipefile, 'Recipe file not renamed')
1815 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1816 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1817 self.assertExists(newsrctree, 'Source directory not renamed')
1818 checkvars = {}
1819 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1820 checkvars['SRC_URI'] = url
1821 self._test_recipe_contents(newrecipefile, checkvars, [])
1822 # Try again - change just name this time
1823 result = runCmd('devtool reset -n %s' % newrecipename)
1824 shutil.rmtree(newsrctree)
1825 add_recipe()
1826 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1827 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1828 self.assertExists(newrecipefile, 'Recipe file not renamed')
1829 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1830 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1831 checkvars = {}
1832 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1833 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1834 self._test_recipe_contents(newrecipefile, checkvars, [])
1835 # Try again - change just version this time
1836 result = runCmd('devtool reset -n %s' % newrecipename)
1837 shutil.rmtree(newsrctree)
1838 add_recipe()
1839 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1840 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1841 self.assertExists(newrecipefile, 'Recipe file not renamed')
1842 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1843 checkvars = {}
1844 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1845 checkvars['SRC_URI'] = url
1846 self._test_recipe_contents(newrecipefile, checkvars, [])
1847
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001848 def test_devtool_virtual_kernel_modify(self):
1849 """
1850 Summary: The purpose of this test case is to verify that
1851 devtool modify works correctly when building
1852 the kernel.
1853 Dependencies: NA
1854 Steps: 1. Build kernel with bitbake.
1855 2. Save the config file generated.
1856 3. Clean the environment.
1857 4. Use `devtool modify virtual/kernel` to validate following:
1858 4.1 The source is checked out correctly.
1859 4.2 The resulting configuration is the same as
1860 what was get on step 2.
1861 4.3 The Kernel can be build correctly.
1862 4.4 Changes made on the source are reflected on the
1863 subsequent builds.
1864 4.5 Changes on the configuration are reflected on the
1865 subsequent builds
1866 Expected: devtool modify is able to checkout the source of the kernel
1867 and modification to the source and configurations are reflected
1868 when building the kernel.
1869 """
1870 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001871 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001872 bitbake('%s -c clean' % kernel_provider)
1873 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1874 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1875 self.track_for_cleanup(tempdir)
1876 self.track_for_cleanup(tempdir_cfg)
1877 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001878 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001879 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001880 #Step 1
1881 #Here is just generated the config file instead of all the kernel to optimize the
1882 #time of executing this test case.
1883 bitbake('%s -c configure' % kernel_provider)
1884 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1885 #Step 2
1886 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1887 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1888
1889 tmpconfig = os.path.join(tempdir_cfg, '.config')
1890 #Step 3
1891 bitbake('%s -c clean' % kernel_provider)
1892 #Step 4.1
1893 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1894 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1895 #Step 4.2
1896 configfile = os.path.join(tempdir,'.config')
1897 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1898 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1899 #Step 4.3
1900 #NOTE: virtual/kernel is mapped to kernel_provider
1901 result = runCmd('devtool build %s' % kernel_provider)
1902 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1903 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1904 self.assertExists(kernelfile, 'Kernel was not build correctly')
1905
1906 #Modify the kernel source
1907 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1908 modstring = "Use a boot loader. Devtool testing."
1909 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1910 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1911 #Modify the configuration
1912 codeconfigfile = os.path.join(tempdir,'.config.new')
1913 modconfopt = "CONFIG_SG_POOL=n"
1914 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1915 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1916 #Build again kernel with devtool
1917 rebuild = runCmd('devtool build %s' % kernel_provider)
1918 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1919 #Step 4.4
1920 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1921 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1922 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1923 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1924 #Step 4.5
1925 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1926 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')