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