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