blob: 3a25da2033bae3cebb7e99c440a6b20c8d0e1e51 [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)
59 shutil.copytree(pth, destdir)
60 else:
61 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
62 bb.utils.mkdirhier(destdir)
63 shutil.copy2(pth, destdir)
64 return newmetapath
65 else:
66 return layerpath
67 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
68
69def tearDownModule():
70 if oldmetapath:
71 edited_layers = []
72 def bblayers_edit_cb(layerpath, canonical_layerpath):
73 if not edited_layers and canonical_layerpath.endswith('/meta'):
74 edited_layers.append(layerpath)
75 return oldmetapath
76 else:
77 return layerpath
78 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
79 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
80 shutil.rmtree(templayerdir)
81
Brad Bishopd7bf8c12018-02-25 22:55:05 -050082class DevtoolBase(OESelftestTestCase):
83
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080084 @classmethod
85 def setUpClass(cls):
86 super(DevtoolBase, cls).setUpClass()
87 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
88 cls.original_sstate = bb_vars['SSTATE_DIR']
89 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
90 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
91 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
92 % cls.original_sstate)
93
94 @classmethod
95 def tearDownClass(cls):
96 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
97 runCmd('rm -rf %s' % cls.devtool_sstate)
98 super(DevtoolBase, cls).tearDownClass()
99
100 def setUp(self):
101 """Test case setup function"""
102 super(DevtoolBase, self).setUp()
103 self.workspacedir = os.path.join(self.builddir, 'workspace')
104 self.assertTrue(not os.path.exists(self.workspacedir),
105 'This test cannot be run with a workspace directory '
106 'under the build directory')
107 self.append_config(self.sstate_conf)
108
109 def _check_src_repo(self, repo_dir):
110 """Check srctree git repository"""
111 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
112 'git repository for external source tree not found')
113 result = runCmd('git status --porcelain', cwd=repo_dir)
114 self.assertEqual(result.output.strip(), "",
115 'Created git repo is not clean')
116 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
117 self.assertEqual(result.output.strip(), "refs/heads/devtool",
118 'Wrong branch in git repo')
119
120 def _check_repo_status(self, repo_dir, expected_status):
121 """Check the worktree status of a repository"""
122 result = runCmd('git status . --porcelain',
123 cwd=repo_dir)
124 for line in result.output.splitlines():
125 for ind, (f_status, fn_re) in enumerate(expected_status):
126 if re.match(fn_re, line[3:]):
127 if f_status != line[:2]:
128 self.fail('Unexpected status in line: %s' % line)
129 expected_status.pop(ind)
130 break
131 else:
132 self.fail('Unexpected modified file in line: %s' % line)
133 if expected_status:
134 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500135
136 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
137 with open(recipefile, 'r') as f:
138 invar = None
139 invalue = None
140 for line in f:
141 var = None
142 if invar:
143 value = line.strip().strip('"')
144 if value.endswith('\\'):
145 invalue += ' ' + value[:-1].strip()
146 continue
147 else:
148 invalue += ' ' + value.strip()
149 var = invar
150 value = invalue
151 invar = None
152 elif '=' in line:
153 splitline = line.split('=', 1)
154 var = splitline[0].rstrip()
155 value = splitline[1].strip().strip('"')
156 if value.endswith('\\'):
157 invalue = value[:-1].strip()
158 invar = var
159 continue
160 elif line.startswith('inherit '):
161 inherits = line.split()[1:]
162
163 if var and var in checkvars:
164 needvalue = checkvars.pop(var)
165 if needvalue is None:
166 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
167 if isinstance(needvalue, set):
168 if var == 'LICENSE':
169 value = set(value.split(' & '))
170 else:
171 value = set(value.split())
172 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
173
174
175 missingvars = {}
176 for var, value in checkvars.items():
177 if value is not None:
178 missingvars[var] = value
179 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
180
181 for inherit in checkinherits:
182 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
183
184 def _check_bbappend(self, testrecipe, recipefile, appenddir):
185 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
186 resultlines = result.output.splitlines()
187 inrecipe = False
188 bbappends = []
189 bbappendfile = None
190 for line in resultlines:
191 if inrecipe:
192 if line.startswith(' '):
193 bbappends.append(line.strip())
194 else:
195 break
196 elif line == '%s:' % os.path.basename(recipefile):
197 inrecipe = True
198 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
199 for bbappend in bbappends:
200 if bbappend.startswith(appenddir):
201 bbappendfile = bbappend
202 break
203 else:
204 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
205 return bbappendfile
206
207 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
208 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
209 if addlayer:
210 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
211 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
212
213 def _process_ls_output(self, output):
214 """
215 Convert ls -l output to a format we can reasonably compare from one context
216 to another (e.g. from host to target)
217 """
218 filelist = []
219 for line in output.splitlines():
220 splitline = line.split()
221 if len(splitline) < 8:
222 self.fail('_process_ls_output: invalid output line: %s' % line)
223 # Remove trailing . on perms
224 splitline[0] = splitline[0].rstrip('.')
225 # Remove leading . on paths
226 splitline[-1] = splitline[-1].lstrip('.')
227 # Drop fields we don't want to compare
228 del splitline[7]
229 del splitline[6]
230 del splitline[5]
231 del splitline[4]
232 del splitline[1]
233 filelist.append(' '.join(splitline))
234 return filelist
235
236
237class DevtoolTests(DevtoolBase):
238
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500239 def test_create_workspace(self):
240 # Check preconditions
241 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400242 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 -0400243 # remove conf/devtool.conf to avoid it corrupting tests
244 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
245 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500246 # Try creating a workspace layer with a specific path
247 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
248 self.track_for_cleanup(tempdir)
249 result = runCmd('devtool create-workspace %s' % tempdir)
250 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
251 result = runCmd('bitbake-layers show-layers')
252 self.assertIn(tempdir, result.output)
253 # Try creating a workspace layer with the default path
254 self.track_for_cleanup(self.workspacedir)
255 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
256 result = runCmd('devtool create-workspace')
257 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
258 result = runCmd('bitbake-layers show-layers')
259 self.assertNotIn(tempdir, result.output)
260 self.assertIn(self.workspacedir, result.output)
261
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800262class DevtoolAddTests(DevtoolBase):
263
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500264 def test_devtool_add(self):
265 # Fetch source
266 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
267 self.track_for_cleanup(tempdir)
268 pn = 'pv'
269 pv = '1.5.3'
270 url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2'
271 result = runCmd('wget %s' % url, cwd=tempdir)
272 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
273 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
274 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
275 # Test devtool add
276 self.track_for_cleanup(self.workspacedir)
277 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
278 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
279 result = runCmd('devtool add %s %s' % (pn, srcdir))
280 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
281 # Test devtool status
282 result = runCmd('devtool status')
283 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
284 self.assertIn(recipepath, result.output)
285 self.assertIn(srcdir, result.output)
286 # Test devtool find-recipe
287 result = runCmd('devtool -q find-recipe %s' % pn)
288 self.assertEqual(recipepath, result.output.strip())
289 # Test devtool edit-recipe
290 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
291 self.assertEqual('123 %s' % recipepath, result.output.strip())
292 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
293 bitbake('%s -c cleansstate' % pn)
294 # Test devtool build
295 result = runCmd('devtool build %s' % pn)
296 bb_vars = get_bb_vars(['D', 'bindir'], pn)
297 installdir = bb_vars['D']
298 self.assertTrue(installdir, 'Could not query installdir variable')
299 bindir = bb_vars['bindir']
300 self.assertTrue(bindir, 'Could not query bindir variable')
301 if bindir[0] == '/':
302 bindir = bindir[1:]
303 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
304
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500305 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800306 # We need dbus built so that DEPENDS recognition works
307 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500308 # Fetch source from a remote URL, but do it outside of devtool
309 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
310 self.track_for_cleanup(tempdir)
311 pn = 'dbus-wait'
312 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
313 # We choose an https:// git URL here to check rewriting the URL works
314 url = 'https://git.yoctoproject.org/git/dbus-wait'
315 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
316 # instead of the directory name
317 result = runCmd('git clone %s noname' % url, cwd=tempdir)
318 srcdir = os.path.join(tempdir, 'noname')
319 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
320 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
321 # Test devtool add
322 self.track_for_cleanup(self.workspacedir)
323 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
324 # Don't specify a name since we should be able to auto-detect it
325 result = runCmd('devtool add %s' % srcdir)
326 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
327 # Check the recipe name is correct
328 recipefile = get_bb_var('FILE', pn)
329 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
330 self.assertIn(recipefile, result.output)
331 # Test devtool status
332 result = runCmd('devtool status')
333 self.assertIn(pn, result.output)
334 self.assertIn(srcdir, result.output)
335 self.assertIn(recipefile, result.output)
336 checkvars = {}
337 checkvars['LICENSE'] = 'GPLv2'
338 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
339 checkvars['S'] = '${WORKDIR}/git'
340 checkvars['PV'] = '0.1+git${SRCPV}'
341 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https'
342 checkvars['SRCREV'] = srcrev
343 checkvars['DEPENDS'] = set(['dbus'])
344 self._test_recipe_contents(recipefile, checkvars, [])
345
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500346 def test_devtool_add_library(self):
347 # Fetch source
348 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
349 self.track_for_cleanup(tempdir)
350 version = '1.1'
351 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
352 result = runCmd('wget %s' % url, cwd=tempdir)
353 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
354 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
355 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
356 # Test devtool add (and use -V so we test that too)
357 self.track_for_cleanup(self.workspacedir)
358 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
359 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
360 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
361 # Test devtool status
362 result = runCmd('devtool status')
363 self.assertIn('libftdi', result.output)
364 self.assertIn(srcdir, result.output)
365 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
366 bitbake('libftdi -c cleansstate')
367 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
368 # There's also the matter of it installing cmake files to a path we don't
369 # normally cover, which triggers the installed-vs-shipped QA test we have
370 # within do_package
371 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
372 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
373 with open(recipefile, 'a') as f:
374 f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n')
375 # We don't have the ability to pick up this dependency automatically yet...
376 f.write('\nDEPENDS += "libusb1"\n')
377 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
378 # Test devtool build
379 result = runCmd('devtool build libftdi')
380 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
381 staging_libdir = bb_vars['TESTLIBOUTPUT']
382 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
383 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)
384 # Test devtool reset
385 stampprefix = bb_vars['STAMP']
386 result = runCmd('devtool reset libftdi')
387 result = runCmd('devtool status')
388 self.assertNotIn('libftdi', result.output)
389 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
390 matches = glob.glob(stampprefix + '*')
391 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
392 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
393
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500394 def test_devtool_add_fetch(self):
395 # Fetch source
396 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
397 self.track_for_cleanup(tempdir)
398 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400399 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500400 testrecipe = 'python-markupsafe'
401 srcdir = os.path.join(tempdir, testrecipe)
402 # Test devtool add
403 self.track_for_cleanup(self.workspacedir)
404 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
405 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
406 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
407 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
408 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
409 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
410 # Test devtool status
411 result = runCmd('devtool status')
412 self.assertIn(testrecipe, result.output)
413 self.assertIn(srcdir, result.output)
414 # Check recipe
415 recipefile = get_bb_var('FILE', testrecipe)
416 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
417 checkvars = {}
418 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
419 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
420 self._test_recipe_contents(recipefile, checkvars, [])
421 # Try with version specified
422 result = runCmd('devtool reset -n %s' % testrecipe)
423 shutil.rmtree(srcdir)
424 fakever = '1.9'
425 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
426 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
427 # Test devtool status
428 result = runCmd('devtool status')
429 self.assertIn(testrecipe, result.output)
430 self.assertIn(srcdir, result.output)
431 # Check recipe
432 recipefile = get_bb_var('FILE', testrecipe)
433 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
434 checkvars = {}
435 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
436 checkvars['SRC_URI'] = url
437 self._test_recipe_contents(recipefile, checkvars, [])
438
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500439 def test_devtool_add_fetch_git(self):
440 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
441 self.track_for_cleanup(tempdir)
442 url = 'gitsm://git.yoctoproject.org/mraa'
443 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
444 testrecipe = 'mraa'
445 srcdir = os.path.join(tempdir, testrecipe)
446 # Test devtool add
447 self.track_for_cleanup(self.workspacedir)
448 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
449 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
450 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
451 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
452 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
453 # Test devtool status
454 result = runCmd('devtool status')
455 self.assertIn(testrecipe, result.output)
456 self.assertIn(srcdir, result.output)
457 # Check recipe
458 recipefile = get_bb_var('FILE', testrecipe)
459 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
460 checkvars = {}
461 checkvars['S'] = '${WORKDIR}/git'
462 checkvars['PV'] = '1.0+git${SRCPV}'
463 checkvars['SRC_URI'] = url
464 checkvars['SRCREV'] = '${AUTOREV}'
465 self._test_recipe_contents(recipefile, checkvars, [])
466 # Try with revision and version specified
467 result = runCmd('devtool reset -n %s' % testrecipe)
468 shutil.rmtree(srcdir)
469 url_rev = '%s;rev=%s' % (url, checkrev)
470 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
471 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
472 # Test devtool status
473 result = runCmd('devtool status')
474 self.assertIn(testrecipe, result.output)
475 self.assertIn(srcdir, result.output)
476 # Check recipe
477 recipefile = get_bb_var('FILE', testrecipe)
478 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
479 checkvars = {}
480 checkvars['S'] = '${WORKDIR}/git'
481 checkvars['PV'] = '1.5+git${SRCPV}'
482 checkvars['SRC_URI'] = url
483 checkvars['SRCREV'] = checkrev
484 self._test_recipe_contents(recipefile, checkvars, [])
485
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500486 def test_devtool_add_fetch_simple(self):
487 # Fetch source from a remote URL, auto-detecting name
488 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
489 self.track_for_cleanup(tempdir)
490 testver = '1.6.0'
491 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
492 testrecipe = 'pv'
493 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
494 # Test devtool add
495 self.track_for_cleanup(self.workspacedir)
496 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
497 result = runCmd('devtool add %s' % url)
498 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
499 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
500 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
501 # Test devtool status
502 result = runCmd('devtool status')
503 self.assertIn(testrecipe, result.output)
504 self.assertIn(srcdir, result.output)
505 # Check recipe
506 recipefile = get_bb_var('FILE', testrecipe)
507 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
508 checkvars = {}
509 checkvars['S'] = None
510 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
511 self._test_recipe_contents(recipefile, checkvars, [])
512
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800513class DevtoolModifyTests(DevtoolBase):
514
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 def test_devtool_modify(self):
516 import oe.path
517
518 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
519 self.track_for_cleanup(tempdir)
520 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500521 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400522 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500523 result = runCmd('devtool modify mdadm -x %s' % tempdir)
524 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
525 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
526 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
527 self.assertTrue(matches, 'bbappend not created %s' % result.output)
528
529 # Test devtool status
530 result = runCmd('devtool status')
531 self.assertIn('mdadm', result.output)
532 self.assertIn(tempdir, result.output)
533 self._check_src_repo(tempdir)
534
535 bitbake('mdadm -C unpack')
536
537 def check_line(checkfile, expected, message, present=True):
538 # Check for $expected, on a line on its own, in checkfile.
539 with open(checkfile, 'r') as f:
540 if present:
541 self.assertIn(expected + '\n', f, message)
542 else:
543 self.assertNotIn(expected + '\n', f, message)
544
545 modfile = os.path.join(tempdir, 'mdadm.8.in')
546 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
547 pkgd = bb_vars['PKGD']
548 self.assertTrue(pkgd, 'Could not query PKGD variable')
549 mandir = bb_vars['mandir']
550 self.assertTrue(mandir, 'Could not query mandir variable')
551 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
552
553 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
554 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
555
556 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
557 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
558
559 bitbake('mdadm -c package')
560 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
561
562 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
563 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
564
565 bitbake('mdadm -c package')
566 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
567
568 result = runCmd('devtool reset mdadm')
569 result = runCmd('devtool status')
570 self.assertNotIn('mdadm', result.output)
571
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500572 def test_devtool_buildclean(self):
573 def assertFile(path, *paths):
574 f = os.path.join(path, *paths)
575 self.assertExists(f)
576 def assertNoFile(path, *paths):
577 f = os.path.join(path, *paths)
578 self.assertNotExists(f)
579
580 # Clean up anything in the workdir/sysroot/sstate cache
581 bitbake('mdadm m4 -c cleansstate')
582 # Try modifying a recipe
583 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
584 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
585 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
586 self.track_for_cleanup(tempdir_mdadm)
587 self.track_for_cleanup(tempdir_m4)
588 self.track_for_cleanup(builddir_m4)
589 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500590 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400591 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500592 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
593 try:
594 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
595 runCmd('devtool modify m4 -x %s' % tempdir_m4)
596 assertNoFile(tempdir_mdadm, 'mdadm')
597 assertNoFile(builddir_m4, 'src/m4')
598 result = bitbake('m4 -e')
599 result = bitbake('mdadm m4 -c compile')
600 self.assertEqual(result.status, 0)
601 assertFile(tempdir_mdadm, 'mdadm')
602 assertFile(builddir_m4, 'src/m4')
603 # Check that buildclean task exists and does call make clean
604 bitbake('mdadm m4 -c buildclean')
605 assertNoFile(tempdir_mdadm, 'mdadm')
606 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400607 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500608 bitbake('mdadm m4 -c compile')
609 assertFile(tempdir_mdadm, 'mdadm')
610 assertFile(builddir_m4, 'src/m4')
611 bitbake('mdadm m4 -c clean')
612 # Check that buildclean task is run before clean for B == S
613 assertNoFile(tempdir_mdadm, 'mdadm')
614 # Check that buildclean task is not run before clean for B != S
615 assertFile(builddir_m4, 'src/m4')
616 finally:
617 self.delete_recipeinc('m4')
618
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500619 def test_devtool_modify_invalid(self):
620 # Try modifying some recipes
621 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
622 self.track_for_cleanup(tempdir)
623 self.track_for_cleanup(self.workspacedir)
624 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
625
626 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
627 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
628 result = runCmd('bitbake-layers show-recipes gcc-source*')
629 for line in result.output.splitlines():
630 # just match those lines that contain a real target
631 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
632 if m:
633 testrecipes.append(m.group('recipe'))
634 for testrecipe in testrecipes:
635 # Check it's a valid recipe
636 bitbake('%s -e' % testrecipe)
637 # devtool extract should fail
638 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
639 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
640 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
641 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
642 # devtool modify should fail
643 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
644 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
645 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
646
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500647 def test_devtool_modify_native(self):
648 # Check preconditions
649 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
650 # Try modifying some recipes
651 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
652 self.track_for_cleanup(tempdir)
653 self.track_for_cleanup(self.workspacedir)
654 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
655
656 bbclassextended = False
657 inheritnative = False
658 testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
659 for testrecipe in testrecipes:
660 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
661 if not bbclassextended:
662 bbclassextended = checkextend
663 if not inheritnative:
664 inheritnative = not checkextend
665 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
666 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
667 result = runCmd('devtool build %s' % testrecipe)
668 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
669 result = runCmd('devtool reset %s' % testrecipe)
670 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
671
672 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
673 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
674
675
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500676 def test_devtool_modify_git(self):
677 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400678 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500679 src_uri = get_bb_var('SRC_URI', testrecipe)
680 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
681 # Clean up anything in the workdir/sysroot/sstate cache
682 bitbake('%s -c cleansstate' % testrecipe)
683 # Try modifying a recipe
684 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
685 self.track_for_cleanup(tempdir)
686 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500687 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400688 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500689 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400690 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500691 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 -0400692 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500693 self.assertTrue(matches, 'bbappend not created')
694 # Test devtool status
695 result = runCmd('devtool status')
696 self.assertIn(testrecipe, result.output)
697 self.assertIn(tempdir, result.output)
698 # Check git repo
699 self._check_src_repo(tempdir)
700 # Try building
701 bitbake(testrecipe)
702
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500703 def test_devtool_modify_localfiles(self):
704 # Check preconditions
705 testrecipe = 'lighttpd'
706 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
707 foundlocal = False
708 for item in src_uri:
709 if item.startswith('file://') and '.patch' not in item:
710 foundlocal = True
711 break
712 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
713 # Clean up anything in the workdir/sysroot/sstate cache
714 bitbake('%s -c cleansstate' % testrecipe)
715 # Try modifying a recipe
716 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
717 self.track_for_cleanup(tempdir)
718 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500719 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400720 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500721 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
722 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
723 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
724 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
725 self.assertTrue(matches, 'bbappend not created')
726 # Test devtool status
727 result = runCmd('devtool status')
728 self.assertIn(testrecipe, result.output)
729 self.assertIn(tempdir, result.output)
730 # Try building
731 bitbake(testrecipe)
732
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500733 def test_devtool_modify_virtual(self):
734 # Try modifying a virtual recipe
735 virtrecipe = 'virtual/make'
736 realrecipe = 'make'
737 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
738 self.track_for_cleanup(tempdir)
739 self.track_for_cleanup(self.workspacedir)
740 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
741 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
742 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
743 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
744 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
745 self.assertTrue(matches, 'bbappend not created %s' % result.output)
746 # Test devtool status
747 result = runCmd('devtool status')
748 self.assertNotIn(virtrecipe, result.output)
749 self.assertIn(realrecipe, result.output)
750 # Check git repo
751 self._check_src_repo(tempdir)
752 # This is probably sufficient
753
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800754class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500755
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500756 def test_devtool_update_recipe(self):
757 # Check preconditions
758 testrecipe = 'minicom'
759 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
760 recipefile = bb_vars['FILE']
761 src_uri = bb_vars['SRC_URI']
762 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
763 self._check_repo_status(os.path.dirname(recipefile), [])
764 # First, modify a recipe
765 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
766 self.track_for_cleanup(tempdir)
767 self.track_for_cleanup(self.workspacedir)
768 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
769 # (don't bother with cleaning the recipe on teardown, we won't be building it)
770 # We don't use -x here so that we test the behaviour of devtool modify without it
771 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
772 # Check git repo
773 self._check_src_repo(tempdir)
774 # Add a couple of commits
775 # FIXME: this only tests adding, need to also test update and remove
776 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
777 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
778 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
779 result = runCmd('git add devtool-new-file', cwd=tempdir)
780 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
781 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
782 result = runCmd('devtool update-recipe %s' % testrecipe)
783 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
784 ('??', '.*/0001-Change-the-README.patch$'),
785 ('??', '.*/0002-Add-a-new-file.patch$')]
786 self._check_repo_status(os.path.dirname(recipefile), expected_status)
787
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500788 def test_devtool_update_recipe_git(self):
789 # Check preconditions
790 testrecipe = 'mtd-utils'
791 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
792 recipefile = bb_vars['FILE']
793 src_uri = bb_vars['SRC_URI']
794 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
795 patches = []
796 for entry in src_uri.split():
797 if entry.startswith('file://') and entry.endswith('.patch'):
798 patches.append(entry[7:].split(';')[0])
799 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
800 self._check_repo_status(os.path.dirname(recipefile), [])
801 # First, modify a recipe
802 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
803 self.track_for_cleanup(tempdir)
804 self.track_for_cleanup(self.workspacedir)
805 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
806 # (don't bother with cleaning the recipe on teardown, we won't be building it)
807 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
808 # Check git repo
809 self._check_src_repo(tempdir)
810 # Add a couple of commits
811 # FIXME: this only tests adding, need to also test update and remove
812 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
813 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
814 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
815 result = runCmd('git add devtool-new-file', cwd=tempdir)
816 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
817 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
818 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
819 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
820 [(' D', '.*/%s$' % patch) for patch in patches]
821 self._check_repo_status(os.path.dirname(recipefile), expected_status)
822
823 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
824 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
825 srcurilines = src_uri.split()
826 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
827 srcurilines.append('"')
828 removelines = ['SRCREV = ".*"'] + srcurilines
829 for line in result.output.splitlines():
830 if line.startswith('+++') or line.startswith('---'):
831 continue
832 elif line.startswith('+'):
833 matched = False
834 for item in addlines:
835 if re.match(item, line[1:].strip()):
836 matched = True
837 break
838 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
839 elif line.startswith('-'):
840 matched = False
841 for item in removelines:
842 if re.match(item, line[1:].strip()):
843 matched = True
844 break
845 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
846 # Now try with auto mode
847 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
848 result = runCmd('devtool update-recipe %s' % testrecipe)
849 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
850 topleveldir = result.output.strip()
851 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
852 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
853 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
854 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
855 self._check_repo_status(os.path.dirname(recipefile), expected_status)
856
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500857 def test_devtool_update_recipe_append(self):
858 # Check preconditions
859 testrecipe = 'mdadm'
860 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
861 recipefile = bb_vars['FILE']
862 src_uri = bb_vars['SRC_URI']
863 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
864 self._check_repo_status(os.path.dirname(recipefile), [])
865 # First, modify a recipe
866 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
867 tempsrcdir = os.path.join(tempdir, 'source')
868 templayerdir = os.path.join(tempdir, 'layer')
869 self.track_for_cleanup(tempdir)
870 self.track_for_cleanup(self.workspacedir)
871 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
872 # (don't bother with cleaning the recipe on teardown, we won't be building it)
873 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
874 # Check git repo
875 self._check_src_repo(tempsrcdir)
876 # Add a commit
877 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
878 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
879 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
880 # Create a temporary layer and add it to bblayers.conf
881 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
882 # Create the bbappend
883 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
884 self.assertNotIn('WARNING:', result.output)
885 # Check recipe is still clean
886 self._check_repo_status(os.path.dirname(recipefile), [])
887 # Check bbappend was created
888 splitpath = os.path.dirname(recipefile).split(os.sep)
889 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
890 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
891 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
892 self.assertExists(patchfile, 'Patch file not created')
893
894 # Check bbappend contents
895 expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
896 '\n',
897 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
898 '\n']
899 with open(bbappendfile, 'r') as f:
900 self.assertEqual(expectedlines, f.readlines())
901
902 # Check we can run it again and bbappend isn't modified
903 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
904 with open(bbappendfile, 'r') as f:
905 self.assertEqual(expectedlines, f.readlines())
906 # Drop new commit and check patch gets deleted
907 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
908 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
909 self.assertNotExists(patchfile, 'Patch file not deleted')
910 expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
911 '\n']
912 with open(bbappendfile, 'r') as f:
913 self.assertEqual(expectedlines2, f.readlines())
914 # Put commit back and check we can run it if layer isn't in bblayers.conf
915 os.remove(bbappendfile)
916 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
917 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
918 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
919 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
920 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
921 with open(bbappendfile, 'r') as f:
922 self.assertEqual(expectedlines, f.readlines())
923 # Deleting isn't expected to work under these circumstances
924
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500925 def test_devtool_update_recipe_append_git(self):
926 # Check preconditions
927 testrecipe = 'mtd-utils'
928 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
929 recipefile = bb_vars['FILE']
930 src_uri = bb_vars['SRC_URI']
931 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
932 for entry in src_uri.split():
933 if entry.startswith('git://'):
934 git_uri = entry
935 break
936 self._check_repo_status(os.path.dirname(recipefile), [])
937 # First, modify a recipe
938 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
939 tempsrcdir = os.path.join(tempdir, 'source')
940 templayerdir = os.path.join(tempdir, 'layer')
941 self.track_for_cleanup(tempdir)
942 self.track_for_cleanup(self.workspacedir)
943 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
944 # (don't bother with cleaning the recipe on teardown, we won't be building it)
945 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
946 # Check git repo
947 self._check_src_repo(tempsrcdir)
948 # Add a commit
949 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
950 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
951 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
952 # Create a temporary layer
953 os.makedirs(os.path.join(templayerdir, 'conf'))
954 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
955 f.write('BBPATH .= ":${LAYERDIR}"\n')
956 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
957 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
958 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
959 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
960 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400961 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500962 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
963 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
964 # Create the bbappend
965 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
966 self.assertNotIn('WARNING:', result.output)
967 # Check recipe is still clean
968 self._check_repo_status(os.path.dirname(recipefile), [])
969 # Check bbappend was created
970 splitpath = os.path.dirname(recipefile).split(os.sep)
971 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
972 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
973 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
974
975 # Check bbappend contents
976 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
977 expectedlines = set(['SRCREV = "%s"\n' % result.output,
978 '\n',
979 'SRC_URI = "%s"\n' % git_uri,
980 '\n'])
981 with open(bbappendfile, 'r') as f:
982 self.assertEqual(expectedlines, set(f.readlines()))
983
984 # Check we can run it again and bbappend isn't modified
985 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
986 with open(bbappendfile, 'r') as f:
987 self.assertEqual(expectedlines, set(f.readlines()))
988 # Drop new commit and check SRCREV changes
989 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
990 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
991 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
992 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
993 expectedlines = set(['SRCREV = "%s"\n' % result.output,
994 '\n',
995 'SRC_URI = "%s"\n' % git_uri,
996 '\n'])
997 with open(bbappendfile, 'r') as f:
998 self.assertEqual(expectedlines, set(f.readlines()))
999 # Put commit back and check we can run it if layer isn't in bblayers.conf
1000 os.remove(bbappendfile)
1001 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1002 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1003 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1004 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1005 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1006 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1007 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1008 '\n',
1009 'SRC_URI = "%s"\n' % git_uri,
1010 '\n'])
1011 with open(bbappendfile, 'r') as f:
1012 self.assertEqual(expectedlines, set(f.readlines()))
1013 # Deleting isn't expected to work under these circumstances
1014
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001015 def test_devtool_update_recipe_local_files(self):
1016 """Check that local source files are copied over instead of patched"""
1017 testrecipe = 'makedevs'
1018 recipefile = get_bb_var('FILE', testrecipe)
1019 # Setup srctree for modifying the recipe
1020 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1021 self.track_for_cleanup(tempdir)
1022 self.track_for_cleanup(self.workspacedir)
1023 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1024 # (don't bother with cleaning the recipe on teardown, we won't be
1025 # building it)
1026 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1027 # Check git repo
1028 self._check_src_repo(tempdir)
1029 # Try building just to ensure we haven't broken that
1030 bitbake("%s" % testrecipe)
1031 # Edit / commit local source
1032 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1033 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1034 runCmd('echo "Bar" > new-file', cwd=tempdir)
1035 runCmd('git add new-file', cwd=tempdir)
1036 runCmd('git commit -m "Add new file"', cwd=tempdir)
1037 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1038 os.path.dirname(recipefile))
1039 runCmd('devtool update-recipe %s' % testrecipe)
1040 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1041 (' M', '.*/makedevs/makedevs.c$'),
1042 ('??', '.*/makedevs/new-local$'),
1043 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1044 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1045
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001046 def test_devtool_update_recipe_local_files_2(self):
1047 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001048 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001049 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001050 recipedir = os.path.dirname(recipefile)
1051 result = runCmd('git status --porcelain .', cwd=recipedir)
1052 if result.output.strip():
1053 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001054 # Setup srctree for modifying the recipe
1055 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1056 self.track_for_cleanup(tempdir)
1057 self.track_for_cleanup(self.workspacedir)
1058 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1059 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1060 # Check git repo
1061 self._check_src_repo(tempdir)
1062 # Add oe-local-files to Git
1063 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1064 runCmd('git add oe-local-files', cwd=tempdir)
1065 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1066 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001067 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001068 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001069 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001070 runCmd('git commit -m"Remove file"', cwd=tempdir)
1071 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1072 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1073 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1074 runCmd('echo "Gar" > new-file', cwd=tempdir)
1075 runCmd('git add new-file', cwd=tempdir)
1076 runCmd('git commit -m "Add new file"', cwd=tempdir)
1077 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1078 os.path.dirname(recipefile))
1079 # Checkout unmodified file to working copy -> devtool should still pick
1080 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001081 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001082 runCmd('devtool update-recipe %s' % testrecipe)
1083 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001084 (' M', '.*/file1$'),
1085 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001086 ('??', '.*/new-local$'),
1087 ('??', '.*/0001-Add-new-file.patch$')]
1088 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1089
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001090 def test_devtool_update_recipe_local_files_3(self):
1091 # First, modify the recipe
1092 testrecipe = 'devtool-test-localonly'
1093 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1094 recipefile = bb_vars['FILE']
1095 src_uri = bb_vars['SRC_URI']
1096 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1097 self.track_for_cleanup(tempdir)
1098 self.track_for_cleanup(self.workspacedir)
1099 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1100 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1101 result = runCmd('devtool modify %s' % testrecipe)
1102 # Modify one file
1103 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1104 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1105 result = runCmd('devtool update-recipe %s' % testrecipe)
1106 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1107 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1108
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001109 def test_devtool_update_recipe_local_patch_gz(self):
1110 # First, modify the recipe
1111 testrecipe = 'devtool-test-patch-gz'
1112 if get_bb_var('DISTRO') == 'poky-tiny':
1113 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1114 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1115 recipefile = bb_vars['FILE']
1116 src_uri = bb_vars['SRC_URI']
1117 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1118 self.track_for_cleanup(tempdir)
1119 self.track_for_cleanup(self.workspacedir)
1120 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1121 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1122 result = runCmd('devtool modify %s' % testrecipe)
1123 # Modify one file
1124 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1125 runCmd('echo "Another line" >> README', cwd=srctree)
1126 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1127 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1128 result = runCmd('devtool update-recipe %s' % testrecipe)
1129 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1130 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1131 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1132 result = runCmd('file %s' % patch_gz)
1133 if 'gzip compressed data' not in result.output:
1134 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1135
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001136 def test_devtool_update_recipe_local_files_subdir(self):
1137 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1138 # SRC_URI such that it overwrites a file that was in an archive that
1139 # was also in SRC_URI
1140 # First, modify the recipe
1141 testrecipe = 'devtool-test-subdir'
1142 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1143 recipefile = bb_vars['FILE']
1144 src_uri = bb_vars['SRC_URI']
1145 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1146 self.track_for_cleanup(tempdir)
1147 self.track_for_cleanup(self.workspacedir)
1148 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1149 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1150 result = runCmd('devtool modify %s' % testrecipe)
1151 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1152 self.assertExists(testfile, 'Extracted source could not be found')
1153 with open(testfile, 'r') as f:
1154 contents = f.read().rstrip()
1155 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1156 # Test devtool update-recipe without modifying any files
1157 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1158 result = runCmd('devtool update-recipe %s' % testrecipe)
1159 expected_status = []
1160 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1161
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001162class DevtoolExtractTests(DevtoolBase):
1163
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001164 def test_devtool_extract(self):
1165 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1166 # Try devtool extract
1167 self.track_for_cleanup(tempdir)
1168 self.track_for_cleanup(self.workspacedir)
1169 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1170 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1171 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1172 self._check_src_repo(tempdir)
1173
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001174 def test_devtool_extract_virtual(self):
1175 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1176 # Try devtool extract
1177 self.track_for_cleanup(tempdir)
1178 self.track_for_cleanup(self.workspacedir)
1179 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1180 result = runCmd('devtool extract virtual/make %s' % tempdir)
1181 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1182 self._check_src_repo(tempdir)
1183
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001184 def test_devtool_reset_all(self):
1185 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1186 self.track_for_cleanup(tempdir)
1187 self.track_for_cleanup(self.workspacedir)
1188 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1189 testrecipe1 = 'mdadm'
1190 testrecipe2 = 'cronie'
1191 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1192 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1193 result = runCmd('devtool build %s' % testrecipe1)
1194 result = runCmd('devtool build %s' % testrecipe2)
1195 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1196 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1197 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1198 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1199 result = runCmd('devtool reset -a')
1200 self.assertIn(testrecipe1, result.output)
1201 self.assertIn(testrecipe2, result.output)
1202 result = runCmd('devtool status')
1203 self.assertNotIn(testrecipe1, result.output)
1204 self.assertNotIn(testrecipe2, result.output)
1205 matches1 = glob.glob(stampprefix1 + '*')
1206 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1207 matches2 = glob.glob(stampprefix2 + '*')
1208 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1209
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001210 def test_devtool_deploy_target(self):
1211 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1212 # unfortunately the runtime tests run under bitbake and you can't run
1213 # devtool within bitbake (since devtool needs to run bitbake itself).
1214 # Additionally we are testing build-time functionality as well, so
1215 # really this has to be done as an oe-selftest test.
1216 #
1217 # Check preconditions
1218 machine = get_bb_var('MACHINE')
1219 if not machine.startswith('qemu'):
1220 self.skipTest('This test only works with qemu machines')
1221 if not os.path.exists('/etc/runqemu-nosudo'):
1222 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1223 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1224 if result.status != 0:
1225 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1226 if result.status != 0:
1227 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1228 for line in result.output.splitlines():
1229 if line.startswith('tap'):
1230 break
1231 else:
1232 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1233 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1234 # Definitions
1235 testrecipe = 'mdadm'
1236 testfile = '/sbin/mdadm'
1237 testimage = 'oe-selftest-image'
1238 testcommand = '/sbin/mdadm --help'
1239 # Build an image to run
1240 bitbake("%s qemu-native qemu-helper-native" % testimage)
1241 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1242 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1243 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1244 # Clean recipe so the first deploy will fail
1245 bitbake("%s -c clean" % testrecipe)
1246 # Try devtool modify
1247 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1248 self.track_for_cleanup(tempdir)
1249 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001250 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001251 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001252 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1253 # Test that deploy-target at this point fails (properly)
1254 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1255 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1256 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1257 result = runCmd('devtool build %s' % testrecipe)
1258 # First try a dry-run of deploy-target
1259 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1260 self.assertIn(' %s' % testfile, result.output)
1261 # Boot the image
1262 with runqemu(testimage) as qemu:
1263 # Now really test deploy-target
1264 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1265 # Run a test command to see if it was installed properly
1266 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1267 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1268 # Check if it deployed all of the files with the right ownership/perms
1269 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1270 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1271 installdir = bb_vars['D']
1272 fakerootenv = bb_vars['FAKEROOTENV']
1273 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001274 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001275 filelist1 = self._process_ls_output(result.output)
1276
1277 # Now look on the target
1278 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1279 self.track_for_cleanup(tempdir2)
1280 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1281 with open(tmpfilelist, 'w') as f:
1282 for line in filelist1:
1283 splitline = line.split()
1284 f.write(splitline[-1] + '\n')
1285 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1286 filelist2 = self._process_ls_output(result.output)
1287 filelist1.sort(key=lambda item: item.split()[-1])
1288 filelist2.sort(key=lambda item: item.split()[-1])
1289 self.assertEqual(filelist1, filelist2)
1290 # Test undeploy-target
1291 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1292 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1293 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1294
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001295 def test_devtool_build_image(self):
1296 """Test devtool build-image plugin"""
1297 # Check preconditions
1298 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1299 image = 'core-image-minimal'
1300 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001301 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001302 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001303 bitbake('%s -c clean' % image)
1304 # Add target and native recipes to workspace
1305 recipes = ['mdadm', 'parted-native']
1306 for recipe in recipes:
1307 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1308 self.track_for_cleanup(tempdir)
1309 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1310 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1311 # Try to build image
1312 result = runCmd('devtool build-image %s' % image)
1313 self.assertNotEqual(result, 0, 'devtool build-image failed')
1314 # Check if image contains expected packages
1315 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1316 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1317 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1318 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1319 for line in f:
1320 splitval = line.split()
1321 if splitval:
1322 pkg = splitval[0]
1323 if pkg in reqpkgs:
1324 reqpkgs.remove(pkg)
1325 if reqpkgs:
1326 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1327
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001328class DevtoolUpgradeTests(DevtoolBase):
1329
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001330 def test_devtool_upgrade(self):
1331 # Check preconditions
1332 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1333 self.track_for_cleanup(self.workspacedir)
1334 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1335 # Check parameters
1336 result = runCmd('devtool upgrade -h')
1337 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1338 self.assertIn(param, result.output)
1339 # For the moment, we are using a real recipe.
1340 recipe = 'devtool-upgrade-test1'
1341 version = '1.6.0'
1342 oldrecipefile = get_bb_var('FILE', recipe)
1343 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1344 self.track_for_cleanup(tempdir)
1345 # Check that recipe is not already under devtool control
1346 result = runCmd('devtool status')
1347 self.assertNotIn(recipe, result.output)
1348 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1349 # we are downgrading instead of upgrading.
1350 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1351 # Check if srctree at least is populated
1352 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1353 # Check new recipe subdirectory is present
1354 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1355 # Check new recipe file is present
1356 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1357 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1358 # Check devtool status and make sure recipe is present
1359 result = runCmd('devtool status')
1360 self.assertIn(recipe, result.output)
1361 self.assertIn(tempdir, result.output)
1362 # Check recipe got changed as expected
1363 with open(oldrecipefile + '.upgraded', 'r') as f:
1364 desiredlines = f.readlines()
1365 with open(newrecipefile, 'r') as f:
1366 newlines = f.readlines()
1367 self.assertEqual(desiredlines, newlines)
1368 # Check devtool reset recipe
1369 result = runCmd('devtool reset %s -n' % recipe)
1370 result = runCmd('devtool status')
1371 self.assertNotIn(recipe, result.output)
1372 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1373
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001374 def test_devtool_upgrade_git(self):
1375 # Check preconditions
1376 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1377 self.track_for_cleanup(self.workspacedir)
1378 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1379 recipe = 'devtool-upgrade-test2'
1380 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1381 oldrecipefile = get_bb_var('FILE', recipe)
1382 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1383 self.track_for_cleanup(tempdir)
1384 # Check that recipe is not already under devtool control
1385 result = runCmd('devtool status')
1386 self.assertNotIn(recipe, result.output)
1387 # Check upgrade
1388 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1389 # Check if srctree at least is populated
1390 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1391 # Check new recipe file is present
1392 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1393 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1394 # Check devtool status and make sure recipe is present
1395 result = runCmd('devtool status')
1396 self.assertIn(recipe, result.output)
1397 self.assertIn(tempdir, result.output)
1398 # Check recipe got changed as expected
1399 with open(oldrecipefile + '.upgraded', 'r') as f:
1400 desiredlines = f.readlines()
1401 with open(newrecipefile, 'r') as f:
1402 newlines = f.readlines()
1403 self.assertEqual(desiredlines, newlines)
1404 # Check devtool reset recipe
1405 result = runCmd('devtool reset %s -n' % recipe)
1406 result = runCmd('devtool status')
1407 self.assertNotIn(recipe, result.output)
1408 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1409
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001410 def test_devtool_layer_plugins(self):
1411 """Test that devtool can use plugins from other layers.
1412
1413 This test executes the selftest-reverse command from meta-selftest."""
1414
1415 self.track_for_cleanup(self.workspacedir)
1416 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1417
1418 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1419 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1420 self.assertEqual(result.output, s[::-1])
1421
1422 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1423 dstdir = basedstdir
1424 self.assertExists(dstdir)
1425 for p in paths:
1426 dstdir = os.path.join(dstdir, p)
1427 if not os.path.exists(dstdir):
1428 os.makedirs(dstdir)
1429 self.track_for_cleanup(dstdir)
1430 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1431 if srcfile != dstfile:
1432 shutil.copy(srcfile, dstfile)
1433 self.track_for_cleanup(dstfile)
1434
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001435 def test_devtool_load_plugin(self):
1436 """Test that devtool loads only the first found plugin in BBPATH."""
1437
1438 self.track_for_cleanup(self.workspacedir)
1439 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1440
1441 devtool = runCmd("which devtool")
1442 fromname = runCmd("devtool --quiet pluginfile")
1443 srcfile = fromname.output
1444 bbpath = get_bb_var('BBPATH')
1445 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1446 plugincontent = []
1447 with open(srcfile) as fh:
1448 plugincontent = fh.readlines()
1449 try:
1450 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1451 for path in searchpath:
1452 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1453 result = runCmd("devtool --quiet count")
1454 self.assertEqual(result.output, '1')
1455 result = runCmd("devtool --quiet multiloaded")
1456 self.assertEqual(result.output, "no")
1457 for path in searchpath:
1458 result = runCmd("devtool --quiet bbdir")
1459 self.assertEqual(result.output, path)
1460 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1461 finally:
1462 with open(srcfile, 'w') as fh:
1463 fh.writelines(plugincontent)
1464
1465 def _setup_test_devtool_finish_upgrade(self):
1466 # Check preconditions
1467 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1468 self.track_for_cleanup(self.workspacedir)
1469 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1470 # Use a "real" recipe from meta-selftest
1471 recipe = 'devtool-upgrade-test1'
1472 oldversion = '1.5.3'
1473 newversion = '1.6.0'
1474 oldrecipefile = get_bb_var('FILE', recipe)
1475 recipedir = os.path.dirname(oldrecipefile)
1476 result = runCmd('git status --porcelain .', cwd=recipedir)
1477 if result.output.strip():
1478 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1479 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1480 self.track_for_cleanup(tempdir)
1481 # Check that recipe is not already under devtool control
1482 result = runCmd('devtool status')
1483 self.assertNotIn(recipe, result.output)
1484 # Do the upgrade
1485 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1486 # Check devtool status and make sure recipe is present
1487 result = runCmd('devtool status')
1488 self.assertIn(recipe, result.output)
1489 self.assertIn(tempdir, result.output)
1490 # Make a change to the source
1491 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1492 result = runCmd('git status --porcelain', cwd=tempdir)
1493 self.assertIn('M src/pv/number.c', result.output)
1494 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1495 # Check if patch is there
1496 recipedir = os.path.dirname(oldrecipefile)
1497 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1498 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
1499 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
1500 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn
1501
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001502 def test_devtool_finish_upgrade_origlayer(self):
1503 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1504 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1505 self.assertIn('/meta-selftest/', recipedir)
1506 # Try finish to the original layer
1507 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1508 result = runCmd('devtool finish %s meta-selftest' % recipe)
1509 result = runCmd('devtool status')
1510 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1511 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1512 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1513 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
1514 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1515 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1516 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1517 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
1518 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
1519
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001520 def test_devtool_finish_upgrade_otherlayer(self):
1521 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1522 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1523 self.assertIn('/meta-selftest/', recipedir)
1524 # Try finish to a different layer - should create a bbappend
1525 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1526 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1527 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1528 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1529 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1530 self.track_for_cleanup(newrecipedir)
1531 result = runCmd('devtool finish %s oe-core' % recipe)
1532 result = runCmd('devtool status')
1533 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1534 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1535 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1536 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
1537 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1538 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1539 self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
1540 self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
1541
1542 def _setup_test_devtool_finish_modify(self):
1543 # Check preconditions
1544 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1545 # Try modifying a recipe
1546 self.track_for_cleanup(self.workspacedir)
1547 recipe = 'mdadm'
1548 oldrecipefile = get_bb_var('FILE', recipe)
1549 recipedir = os.path.dirname(oldrecipefile)
1550 result = runCmd('git status --porcelain .', cwd=recipedir)
1551 if result.output.strip():
1552 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1553 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1554 self.track_for_cleanup(tempdir)
1555 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1556 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1557 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1558 # Test devtool status
1559 result = runCmd('devtool status')
1560 self.assertIn(recipe, result.output)
1561 self.assertIn(tempdir, result.output)
1562 # Make a change to the source
1563 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1564 result = runCmd('git status --porcelain', cwd=tempdir)
1565 self.assertIn('M maps.c', result.output)
1566 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1567 for entry in os.listdir(recipedir):
1568 filesdir = os.path.join(recipedir, entry)
1569 if os.path.isdir(filesdir):
1570 break
1571 else:
1572 self.fail('Unable to find recipe files directory for %s' % recipe)
1573 return recipe, oldrecipefile, recipedir, filesdir
1574
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001575 def test_devtool_finish_modify_origlayer(self):
1576 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1577 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1578 self.assertIn('/meta/', recipedir)
1579 # Try finish to the original layer
1580 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1581 result = runCmd('devtool finish %s meta' % recipe)
1582 result = runCmd('devtool status')
1583 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1584 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1585 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1586 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1587 self._check_repo_status(recipedir, expected_status)
1588
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001589 def test_devtool_finish_modify_otherlayer(self):
1590 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1591 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1592 self.assertIn('/meta/', recipedir)
1593 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1594 appenddir = os.path.join(get_test_layer(), relpth)
1595 self.track_for_cleanup(appenddir)
1596 # Try finish to the original layer
1597 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1598 result = runCmd('devtool finish %s meta-selftest' % recipe)
1599 result = runCmd('devtool status')
1600 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1601 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1602 result = runCmd('git status --porcelain .', cwd=recipedir)
1603 if result.output.strip():
1604 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1605 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1606 recipefn = recipefn.split('_')[0] + '_%'
1607 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1608 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1609 newdir = os.path.join(appenddir, recipe)
1610 files = os.listdir(newdir)
1611 foundpatch = None
1612 for fn in files:
1613 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1614 foundpatch = fn
1615 if not foundpatch:
1616 self.fail('No patch file created next to bbappend')
1617 files.remove(foundpatch)
1618 if files:
1619 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1620
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001621 def test_devtool_rename(self):
1622 # Check preconditions
1623 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1624 self.track_for_cleanup(self.workspacedir)
1625 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1626
1627 # First run devtool add
1628 # We already have this recipe in OE-Core, but that doesn't matter
1629 recipename = 'i2c-tools'
1630 recipever = '3.1.2'
1631 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1632 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1633 def add_recipe():
1634 result = runCmd('devtool add %s' % url)
1635 self.assertExists(recipefile, 'Expected recipe file not created')
1636 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1637 checkvars = {}
1638 checkvars['S'] = None
1639 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1640 self._test_recipe_contents(recipefile, checkvars, [])
1641 add_recipe()
1642 # Now rename it - change both name and version
1643 newrecipename = 'mynewrecipe'
1644 newrecipever = '456'
1645 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1646 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1647 self.assertExists(newrecipefile, 'Recipe file not renamed')
1648 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1649 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1650 self.assertExists(newsrctree, 'Source directory not renamed')
1651 checkvars = {}
1652 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1653 checkvars['SRC_URI'] = url
1654 self._test_recipe_contents(newrecipefile, checkvars, [])
1655 # Try again - change just name this time
1656 result = runCmd('devtool reset -n %s' % newrecipename)
1657 shutil.rmtree(newsrctree)
1658 add_recipe()
1659 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1660 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1661 self.assertExists(newrecipefile, 'Recipe file not renamed')
1662 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1663 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1664 checkvars = {}
1665 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1666 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1667 self._test_recipe_contents(newrecipefile, checkvars, [])
1668 # Try again - change just version this time
1669 result = runCmd('devtool reset -n %s' % newrecipename)
1670 shutil.rmtree(newsrctree)
1671 add_recipe()
1672 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1673 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1674 self.assertExists(newrecipefile, 'Recipe file not renamed')
1675 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1676 checkvars = {}
1677 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1678 checkvars['SRC_URI'] = url
1679 self._test_recipe_contents(newrecipefile, checkvars, [])
1680
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001681 def test_devtool_virtual_kernel_modify(self):
1682 """
1683 Summary: The purpose of this test case is to verify that
1684 devtool modify works correctly when building
1685 the kernel.
1686 Dependencies: NA
1687 Steps: 1. Build kernel with bitbake.
1688 2. Save the config file generated.
1689 3. Clean the environment.
1690 4. Use `devtool modify virtual/kernel` to validate following:
1691 4.1 The source is checked out correctly.
1692 4.2 The resulting configuration is the same as
1693 what was get on step 2.
1694 4.3 The Kernel can be build correctly.
1695 4.4 Changes made on the source are reflected on the
1696 subsequent builds.
1697 4.5 Changes on the configuration are reflected on the
1698 subsequent builds
1699 Expected: devtool modify is able to checkout the source of the kernel
1700 and modification to the source and configurations are reflected
1701 when building the kernel.
1702 """
1703 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
1704 # Clean up the enviroment
1705 bitbake('%s -c clean' % kernel_provider)
1706 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1707 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1708 self.track_for_cleanup(tempdir)
1709 self.track_for_cleanup(tempdir_cfg)
1710 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001711 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001712 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001713 #Step 1
1714 #Here is just generated the config file instead of all the kernel to optimize the
1715 #time of executing this test case.
1716 bitbake('%s -c configure' % kernel_provider)
1717 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1718 #Step 2
1719 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1720 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1721
1722 tmpconfig = os.path.join(tempdir_cfg, '.config')
1723 #Step 3
1724 bitbake('%s -c clean' % kernel_provider)
1725 #Step 4.1
1726 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1727 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1728 #Step 4.2
1729 configfile = os.path.join(tempdir,'.config')
1730 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1731 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1732 #Step 4.3
1733 #NOTE: virtual/kernel is mapped to kernel_provider
1734 result = runCmd('devtool build %s' % kernel_provider)
1735 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1736 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1737 self.assertExists(kernelfile, 'Kernel was not build correctly')
1738
1739 #Modify the kernel source
1740 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1741 modstring = "Use a boot loader. Devtool testing."
1742 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1743 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1744 #Modify the configuration
1745 codeconfigfile = os.path.join(tempdir,'.config.new')
1746 modconfopt = "CONFIG_SG_POOL=n"
1747 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1748 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1749 #Build again kernel with devtool
1750 rebuild = runCmd('devtool build %s' % kernel_provider)
1751 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1752 #Step 4.4
1753 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1754 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1755 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1756 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1757 #Step 4.5
1758 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1759 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')