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