blob: b383ed9c50b154a208f9c6dc0a667c3414bba096 [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
Andrew Geissler82c905d2020-04-13 13:39:40 -0500514 def test_devtool_add_npm(self):
515 pn = 'savoirfairelinux-node-server-example'
516 pv = '1.0.0'
517 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
518 # Test devtool add
519 self.track_for_cleanup(self.workspacedir)
520 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
521 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
522 result = runCmd('devtool add \'%s\'' % url)
523 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
524 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
525 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
526 # Test devtool status
527 result = runCmd('devtool status')
528 self.assertIn(pn, result.output)
529 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
530 bitbake('%s -c cleansstate' % pn)
531 # Test devtool build
532 result = runCmd('devtool build %s' % pn)
533
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800534class DevtoolModifyTests(DevtoolBase):
535
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500536 def test_devtool_modify(self):
537 import oe.path
538
539 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
540 self.track_for_cleanup(tempdir)
541 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500542 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400543 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500544 result = runCmd('devtool modify mdadm -x %s' % tempdir)
545 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
546 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
547 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
548 self.assertTrue(matches, 'bbappend not created %s' % result.output)
549
550 # Test devtool status
551 result = runCmd('devtool status')
552 self.assertIn('mdadm', result.output)
553 self.assertIn(tempdir, result.output)
554 self._check_src_repo(tempdir)
555
556 bitbake('mdadm -C unpack')
557
558 def check_line(checkfile, expected, message, present=True):
559 # Check for $expected, on a line on its own, in checkfile.
560 with open(checkfile, 'r') as f:
561 if present:
562 self.assertIn(expected + '\n', f, message)
563 else:
564 self.assertNotIn(expected + '\n', f, message)
565
566 modfile = os.path.join(tempdir, 'mdadm.8.in')
567 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
568 pkgd = bb_vars['PKGD']
569 self.assertTrue(pkgd, 'Could not query PKGD variable')
570 mandir = bb_vars['mandir']
571 self.assertTrue(mandir, 'Could not query mandir variable')
572 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
573
574 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
575 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
576
577 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
578 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
579
580 bitbake('mdadm -c package')
581 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
582
583 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
584 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
585
586 bitbake('mdadm -c package')
587 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
588
589 result = runCmd('devtool reset mdadm')
590 result = runCmd('devtool status')
591 self.assertNotIn('mdadm', result.output)
592
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500593 def test_devtool_buildclean(self):
594 def assertFile(path, *paths):
595 f = os.path.join(path, *paths)
596 self.assertExists(f)
597 def assertNoFile(path, *paths):
598 f = os.path.join(path, *paths)
599 self.assertNotExists(f)
600
601 # Clean up anything in the workdir/sysroot/sstate cache
602 bitbake('mdadm m4 -c cleansstate')
603 # Try modifying a recipe
604 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
605 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
606 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
607 self.track_for_cleanup(tempdir_mdadm)
608 self.track_for_cleanup(tempdir_m4)
609 self.track_for_cleanup(builddir_m4)
610 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500611 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400612 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500613 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
614 try:
615 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
616 runCmd('devtool modify m4 -x %s' % tempdir_m4)
617 assertNoFile(tempdir_mdadm, 'mdadm')
618 assertNoFile(builddir_m4, 'src/m4')
619 result = bitbake('m4 -e')
620 result = bitbake('mdadm m4 -c compile')
621 self.assertEqual(result.status, 0)
622 assertFile(tempdir_mdadm, 'mdadm')
623 assertFile(builddir_m4, 'src/m4')
624 # Check that buildclean task exists and does call make clean
625 bitbake('mdadm m4 -c buildclean')
626 assertNoFile(tempdir_mdadm, 'mdadm')
627 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400628 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500629 bitbake('mdadm m4 -c compile')
630 assertFile(tempdir_mdadm, 'mdadm')
631 assertFile(builddir_m4, 'src/m4')
632 bitbake('mdadm m4 -c clean')
633 # Check that buildclean task is run before clean for B == S
634 assertNoFile(tempdir_mdadm, 'mdadm')
635 # Check that buildclean task is not run before clean for B != S
636 assertFile(builddir_m4, 'src/m4')
637 finally:
638 self.delete_recipeinc('m4')
639
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500640 def test_devtool_modify_invalid(self):
641 # Try modifying some recipes
642 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
643 self.track_for_cleanup(tempdir)
644 self.track_for_cleanup(self.workspacedir)
645 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
646
647 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
648 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
649 result = runCmd('bitbake-layers show-recipes gcc-source*')
650 for line in result.output.splitlines():
651 # just match those lines that contain a real target
652 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
653 if m:
654 testrecipes.append(m.group('recipe'))
655 for testrecipe in testrecipes:
656 # Check it's a valid recipe
657 bitbake('%s -e' % testrecipe)
658 # devtool extract should fail
659 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
660 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
661 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
662 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
663 # devtool modify should fail
664 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
665 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
666 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
667
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500668 def test_devtool_modify_native(self):
669 # Check preconditions
670 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
671 # Try modifying some recipes
672 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
673 self.track_for_cleanup(tempdir)
674 self.track_for_cleanup(self.workspacedir)
675 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
676
677 bbclassextended = False
678 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500679 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500680 for testrecipe in testrecipes:
681 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
682 if not bbclassextended:
683 bbclassextended = checkextend
684 if not inheritnative:
685 inheritnative = not checkextend
686 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
687 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
688 result = runCmd('devtool build %s' % testrecipe)
689 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
690 result = runCmd('devtool reset %s' % testrecipe)
691 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
692
693 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
694 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
695
696
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500697 def test_devtool_modify_git(self):
698 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400699 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500700 src_uri = get_bb_var('SRC_URI', testrecipe)
701 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
702 # Clean up anything in the workdir/sysroot/sstate cache
703 bitbake('%s -c cleansstate' % testrecipe)
704 # Try modifying a recipe
705 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
706 self.track_for_cleanup(tempdir)
707 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500708 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400709 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500710 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400711 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500712 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 -0400713 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500714 self.assertTrue(matches, 'bbappend not created')
715 # Test devtool status
716 result = runCmd('devtool status')
717 self.assertIn(testrecipe, result.output)
718 self.assertIn(tempdir, result.output)
719 # Check git repo
720 self._check_src_repo(tempdir)
721 # Try building
722 bitbake(testrecipe)
723
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500724 def test_devtool_modify_localfiles(self):
725 # Check preconditions
726 testrecipe = 'lighttpd'
727 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
728 foundlocal = False
729 for item in src_uri:
730 if item.startswith('file://') and '.patch' not in item:
731 foundlocal = True
732 break
733 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
734 # Clean up anything in the workdir/sysroot/sstate cache
735 bitbake('%s -c cleansstate' % testrecipe)
736 # Try modifying a recipe
737 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
738 self.track_for_cleanup(tempdir)
739 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500740 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400741 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500742 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
743 self.assertExists(os.path.join(tempdir, 'configure.ac'), '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' % testrecipe))
746 self.assertTrue(matches, 'bbappend not created')
747 # Test devtool status
748 result = runCmd('devtool status')
749 self.assertIn(testrecipe, result.output)
750 self.assertIn(tempdir, result.output)
751 # Try building
752 bitbake(testrecipe)
753
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500754 def test_devtool_modify_virtual(self):
755 # Try modifying a virtual recipe
756 virtrecipe = 'virtual/make'
757 realrecipe = 'make'
758 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
759 self.track_for_cleanup(tempdir)
760 self.track_for_cleanup(self.workspacedir)
761 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
762 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
763 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
764 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
765 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
766 self.assertTrue(matches, 'bbappend not created %s' % result.output)
767 # Test devtool status
768 result = runCmd('devtool status')
769 self.assertNotIn(virtrecipe, result.output)
770 self.assertIn(realrecipe, result.output)
771 # Check git repo
772 self._check_src_repo(tempdir)
773 # This is probably sufficient
774
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800775class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500776
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500777 def test_devtool_update_recipe(self):
778 # Check preconditions
779 testrecipe = 'minicom'
780 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
781 recipefile = bb_vars['FILE']
782 src_uri = bb_vars['SRC_URI']
783 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
784 self._check_repo_status(os.path.dirname(recipefile), [])
785 # First, modify a recipe
786 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
787 self.track_for_cleanup(tempdir)
788 self.track_for_cleanup(self.workspacedir)
789 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
790 # (don't bother with cleaning the recipe on teardown, we won't be building it)
791 # We don't use -x here so that we test the behaviour of devtool modify without it
792 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
793 # Check git repo
794 self._check_src_repo(tempdir)
795 # Add a couple of commits
796 # FIXME: this only tests adding, need to also test update and remove
797 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
798 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
799 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
800 result = runCmd('git add devtool-new-file', cwd=tempdir)
801 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
802 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
803 result = runCmd('devtool update-recipe %s' % testrecipe)
804 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
805 ('??', '.*/0001-Change-the-README.patch$'),
806 ('??', '.*/0002-Add-a-new-file.patch$')]
807 self._check_repo_status(os.path.dirname(recipefile), expected_status)
808
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500809 def test_devtool_update_recipe_git(self):
810 # Check preconditions
811 testrecipe = 'mtd-utils'
812 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
813 recipefile = bb_vars['FILE']
814 src_uri = bb_vars['SRC_URI']
815 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
816 patches = []
817 for entry in src_uri.split():
818 if entry.startswith('file://') and entry.endswith('.patch'):
819 patches.append(entry[7:].split(';')[0])
820 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
821 self._check_repo_status(os.path.dirname(recipefile), [])
822 # First, modify a recipe
823 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
824 self.track_for_cleanup(tempdir)
825 self.track_for_cleanup(self.workspacedir)
826 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
827 # (don't bother with cleaning the recipe on teardown, we won't be building it)
828 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
829 # Check git repo
830 self._check_src_repo(tempdir)
831 # Add a couple of commits
832 # FIXME: this only tests adding, need to also test update and remove
833 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
834 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
835 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
836 result = runCmd('git add devtool-new-file', cwd=tempdir)
837 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
838 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
839 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
840 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
841 [(' D', '.*/%s$' % patch) for patch in patches]
842 self._check_repo_status(os.path.dirname(recipefile), expected_status)
843
844 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
845 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
846 srcurilines = src_uri.split()
847 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
848 srcurilines.append('"')
849 removelines = ['SRCREV = ".*"'] + srcurilines
850 for line in result.output.splitlines():
851 if line.startswith('+++') or line.startswith('---'):
852 continue
853 elif line.startswith('+'):
854 matched = False
855 for item in addlines:
856 if re.match(item, line[1:].strip()):
857 matched = True
858 break
859 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
860 elif line.startswith('-'):
861 matched = False
862 for item in removelines:
863 if re.match(item, line[1:].strip()):
864 matched = True
865 break
866 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
867 # Now try with auto mode
868 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
869 result = runCmd('devtool update-recipe %s' % testrecipe)
870 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
871 topleveldir = result.output.strip()
872 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
873 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
874 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
875 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
876 self._check_repo_status(os.path.dirname(recipefile), expected_status)
877
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500878 def test_devtool_update_recipe_append(self):
879 # Check preconditions
880 testrecipe = 'mdadm'
881 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
882 recipefile = bb_vars['FILE']
883 src_uri = bb_vars['SRC_URI']
884 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
885 self._check_repo_status(os.path.dirname(recipefile), [])
886 # First, modify a recipe
887 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
888 tempsrcdir = os.path.join(tempdir, 'source')
889 templayerdir = os.path.join(tempdir, 'layer')
890 self.track_for_cleanup(tempdir)
891 self.track_for_cleanup(self.workspacedir)
892 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
893 # (don't bother with cleaning the recipe on teardown, we won't be building it)
894 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
895 # Check git repo
896 self._check_src_repo(tempsrcdir)
897 # Add a commit
898 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
899 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
900 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
901 # Create a temporary layer and add it to bblayers.conf
902 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
903 # Create the bbappend
904 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
905 self.assertNotIn('WARNING:', result.output)
906 # Check recipe is still clean
907 self._check_repo_status(os.path.dirname(recipefile), [])
908 # Check bbappend was created
909 splitpath = os.path.dirname(recipefile).split(os.sep)
910 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
911 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
912 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
913 self.assertExists(patchfile, 'Patch file not created')
914
915 # Check bbappend contents
916 expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
917 '\n',
918 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
919 '\n']
920 with open(bbappendfile, 'r') as f:
921 self.assertEqual(expectedlines, f.readlines())
922
923 # Check we can run it again and bbappend isn't modified
924 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
925 with open(bbappendfile, 'r') as f:
926 self.assertEqual(expectedlines, f.readlines())
927 # Drop new commit and check patch gets deleted
928 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
929 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
930 self.assertNotExists(patchfile, 'Patch file not deleted')
931 expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
932 '\n']
933 with open(bbappendfile, 'r') as f:
934 self.assertEqual(expectedlines2, f.readlines())
935 # Put commit back and check we can run it if layer isn't in bblayers.conf
936 os.remove(bbappendfile)
937 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
938 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
939 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
940 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
941 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
942 with open(bbappendfile, 'r') as f:
943 self.assertEqual(expectedlines, f.readlines())
944 # Deleting isn't expected to work under these circumstances
945
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500946 def test_devtool_update_recipe_append_git(self):
947 # Check preconditions
948 testrecipe = 'mtd-utils'
949 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
950 recipefile = bb_vars['FILE']
951 src_uri = bb_vars['SRC_URI']
952 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
953 for entry in src_uri.split():
954 if entry.startswith('git://'):
955 git_uri = entry
956 break
957 self._check_repo_status(os.path.dirname(recipefile), [])
958 # First, modify a recipe
959 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
960 tempsrcdir = os.path.join(tempdir, 'source')
961 templayerdir = os.path.join(tempdir, 'layer')
962 self.track_for_cleanup(tempdir)
963 self.track_for_cleanup(self.workspacedir)
964 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
965 # (don't bother with cleaning the recipe on teardown, we won't be building it)
966 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
967 # Check git repo
968 self._check_src_repo(tempsrcdir)
969 # Add a commit
970 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
971 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
972 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
973 # Create a temporary layer
974 os.makedirs(os.path.join(templayerdir, 'conf'))
975 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
976 f.write('BBPATH .= ":${LAYERDIR}"\n')
977 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
978 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
979 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
980 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
981 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400982 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500983 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
984 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
985 # Create the bbappend
986 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
987 self.assertNotIn('WARNING:', result.output)
988 # Check recipe is still clean
989 self._check_repo_status(os.path.dirname(recipefile), [])
990 # Check bbappend was created
991 splitpath = os.path.dirname(recipefile).split(os.sep)
992 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
993 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
994 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
995
996 # Check bbappend contents
997 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
998 expectedlines = set(['SRCREV = "%s"\n' % result.output,
999 '\n',
1000 'SRC_URI = "%s"\n' % git_uri,
1001 '\n'])
1002 with open(bbappendfile, 'r') as f:
1003 self.assertEqual(expectedlines, set(f.readlines()))
1004
1005 # Check we can run it again and bbappend isn't modified
1006 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1007 with open(bbappendfile, 'r') as f:
1008 self.assertEqual(expectedlines, set(f.readlines()))
1009 # Drop new commit and check SRCREV changes
1010 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1011 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1012 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1013 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1014 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1015 '\n',
1016 'SRC_URI = "%s"\n' % git_uri,
1017 '\n'])
1018 with open(bbappendfile, 'r') as f:
1019 self.assertEqual(expectedlines, set(f.readlines()))
1020 # Put commit back and check we can run it if layer isn't in bblayers.conf
1021 os.remove(bbappendfile)
1022 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1023 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1024 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1025 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1026 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1027 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1028 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1029 '\n',
1030 'SRC_URI = "%s"\n' % git_uri,
1031 '\n'])
1032 with open(bbappendfile, 'r') as f:
1033 self.assertEqual(expectedlines, set(f.readlines()))
1034 # Deleting isn't expected to work under these circumstances
1035
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001036 def test_devtool_update_recipe_local_files(self):
1037 """Check that local source files are copied over instead of patched"""
1038 testrecipe = 'makedevs'
1039 recipefile = get_bb_var('FILE', testrecipe)
1040 # Setup srctree for modifying the recipe
1041 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1042 self.track_for_cleanup(tempdir)
1043 self.track_for_cleanup(self.workspacedir)
1044 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1045 # (don't bother with cleaning the recipe on teardown, we won't be
1046 # building it)
1047 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1048 # Check git repo
1049 self._check_src_repo(tempdir)
1050 # Try building just to ensure we haven't broken that
1051 bitbake("%s" % testrecipe)
1052 # Edit / commit local source
1053 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1054 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1055 runCmd('echo "Bar" > new-file', cwd=tempdir)
1056 runCmd('git add new-file', cwd=tempdir)
1057 runCmd('git commit -m "Add new file"', cwd=tempdir)
1058 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1059 os.path.dirname(recipefile))
1060 runCmd('devtool update-recipe %s' % testrecipe)
1061 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1062 (' M', '.*/makedevs/makedevs.c$'),
1063 ('??', '.*/makedevs/new-local$'),
1064 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1065 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1066
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001067 def test_devtool_update_recipe_local_files_2(self):
1068 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001069 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001070 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001071 recipedir = os.path.dirname(recipefile)
1072 result = runCmd('git status --porcelain .', cwd=recipedir)
1073 if result.output.strip():
1074 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001075 # Setup srctree for modifying the recipe
1076 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1077 self.track_for_cleanup(tempdir)
1078 self.track_for_cleanup(self.workspacedir)
1079 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1080 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1081 # Check git repo
1082 self._check_src_repo(tempdir)
1083 # Add oe-local-files to Git
1084 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1085 runCmd('git add oe-local-files', cwd=tempdir)
1086 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1087 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001088 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001089 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001090 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001091 runCmd('git commit -m"Remove file"', cwd=tempdir)
1092 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1093 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1094 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1095 runCmd('echo "Gar" > new-file', cwd=tempdir)
1096 runCmd('git add new-file', cwd=tempdir)
1097 runCmd('git commit -m "Add new file"', cwd=tempdir)
1098 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1099 os.path.dirname(recipefile))
1100 # Checkout unmodified file to working copy -> devtool should still pick
1101 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001102 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001103 runCmd('devtool update-recipe %s' % testrecipe)
1104 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001105 (' M', '.*/file1$'),
1106 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001107 ('??', '.*/new-local$'),
1108 ('??', '.*/0001-Add-new-file.patch$')]
1109 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1110
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001111 def test_devtool_update_recipe_with_gitignore(self):
1112 # First, modify the recipe
1113 testrecipe = 'devtool-test-ignored'
1114 bb_vars = get_bb_vars(['FILE'], testrecipe)
1115 recipefile = bb_vars['FILE']
1116 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1117 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
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 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1125 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1126 # Check recipe got changed as expected
1127 with open(newpatchfile, 'r') as f:
1128 desiredlines = f.readlines()
1129 with open(patchfile, 'r') as f:
1130 newlines = f.readlines()
1131 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1132 # which changes the metadata subject which is added into the patch, but keep
1133 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1134 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1135 self.assertEqual(desiredlines[5:], newlines[5:])
1136
1137 def test_devtool_update_recipe_long_filename(self):
1138 # First, modify the recipe
1139 testrecipe = 'devtool-test-long-filename'
1140 bb_vars = get_bb_vars(['FILE'], testrecipe)
1141 recipefile = bb_vars['FILE']
1142 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1143 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1144 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1145 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1146 self.track_for_cleanup(tempdir)
1147 self.track_for_cleanup(self.workspacedir)
1148 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1149 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1150 result = runCmd('devtool modify %s' % testrecipe)
1151 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1152 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1153 # Check recipe got changed as expected
1154 with open(newpatchfile, 'r') as f:
1155 desiredlines = f.readlines()
1156 with open(patchfile, 'r') as f:
1157 newlines = f.readlines()
1158 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1159 # which changes the metadata subject which is added into the patch, but keep
1160 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1161 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1162 self.assertEqual(desiredlines[5:], newlines[5:])
1163
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001164 def test_devtool_update_recipe_local_files_3(self):
1165 # First, modify the recipe
1166 testrecipe = 'devtool-test-localonly'
1167 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1168 recipefile = bb_vars['FILE']
1169 src_uri = bb_vars['SRC_URI']
1170 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1171 self.track_for_cleanup(tempdir)
1172 self.track_for_cleanup(self.workspacedir)
1173 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1174 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1175 result = runCmd('devtool modify %s' % testrecipe)
1176 # Modify one file
1177 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1178 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1179 result = runCmd('devtool update-recipe %s' % testrecipe)
1180 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1181 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1182
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001183 def test_devtool_update_recipe_local_patch_gz(self):
1184 # First, modify the recipe
1185 testrecipe = 'devtool-test-patch-gz'
1186 if get_bb_var('DISTRO') == 'poky-tiny':
1187 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1188 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1189 recipefile = bb_vars['FILE']
1190 src_uri = bb_vars['SRC_URI']
1191 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1192 self.track_for_cleanup(tempdir)
1193 self.track_for_cleanup(self.workspacedir)
1194 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1195 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1196 result = runCmd('devtool modify %s' % testrecipe)
1197 # Modify one file
1198 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1199 runCmd('echo "Another line" >> README', cwd=srctree)
1200 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1201 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1202 result = runCmd('devtool update-recipe %s' % testrecipe)
1203 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1204 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1205 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1206 result = runCmd('file %s' % patch_gz)
1207 if 'gzip compressed data' not in result.output:
1208 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1209
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001210 def test_devtool_update_recipe_local_files_subdir(self):
1211 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1212 # SRC_URI such that it overwrites a file that was in an archive that
1213 # was also in SRC_URI
1214 # First, modify the recipe
1215 testrecipe = 'devtool-test-subdir'
1216 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1217 recipefile = bb_vars['FILE']
1218 src_uri = bb_vars['SRC_URI']
1219 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1220 self.track_for_cleanup(tempdir)
1221 self.track_for_cleanup(self.workspacedir)
1222 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1223 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1224 result = runCmd('devtool modify %s' % testrecipe)
1225 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1226 self.assertExists(testfile, 'Extracted source could not be found')
1227 with open(testfile, 'r') as f:
1228 contents = f.read().rstrip()
1229 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1230 # Test devtool update-recipe without modifying any files
1231 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1232 result = runCmd('devtool update-recipe %s' % testrecipe)
1233 expected_status = []
1234 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1235
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001236class DevtoolExtractTests(DevtoolBase):
1237
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001238 def test_devtool_extract(self):
1239 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1240 # Try devtool extract
1241 self.track_for_cleanup(tempdir)
1242 self.track_for_cleanup(self.workspacedir)
1243 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1244 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1245 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1246 self._check_src_repo(tempdir)
1247
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001248 def test_devtool_extract_virtual(self):
1249 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1250 # Try devtool extract
1251 self.track_for_cleanup(tempdir)
1252 self.track_for_cleanup(self.workspacedir)
1253 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1254 result = runCmd('devtool extract virtual/make %s' % tempdir)
1255 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1256 self._check_src_repo(tempdir)
1257
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001258 def test_devtool_reset_all(self):
1259 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1260 self.track_for_cleanup(tempdir)
1261 self.track_for_cleanup(self.workspacedir)
1262 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1263 testrecipe1 = 'mdadm'
1264 testrecipe2 = 'cronie'
1265 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1266 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1267 result = runCmd('devtool build %s' % testrecipe1)
1268 result = runCmd('devtool build %s' % testrecipe2)
1269 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1270 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1271 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1272 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1273 result = runCmd('devtool reset -a')
1274 self.assertIn(testrecipe1, result.output)
1275 self.assertIn(testrecipe2, result.output)
1276 result = runCmd('devtool status')
1277 self.assertNotIn(testrecipe1, result.output)
1278 self.assertNotIn(testrecipe2, result.output)
1279 matches1 = glob.glob(stampprefix1 + '*')
1280 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1281 matches2 = glob.glob(stampprefix2 + '*')
1282 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1283
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001284 def test_devtool_deploy_target(self):
1285 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1286 # unfortunately the runtime tests run under bitbake and you can't run
1287 # devtool within bitbake (since devtool needs to run bitbake itself).
1288 # Additionally we are testing build-time functionality as well, so
1289 # really this has to be done as an oe-selftest test.
1290 #
1291 # Check preconditions
1292 machine = get_bb_var('MACHINE')
1293 if not machine.startswith('qemu'):
1294 self.skipTest('This test only works with qemu machines')
1295 if not os.path.exists('/etc/runqemu-nosudo'):
1296 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1297 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1298 if result.status != 0:
1299 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1300 if result.status != 0:
1301 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1302 for line in result.output.splitlines():
1303 if line.startswith('tap'):
1304 break
1305 else:
1306 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1307 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1308 # Definitions
1309 testrecipe = 'mdadm'
1310 testfile = '/sbin/mdadm'
1311 testimage = 'oe-selftest-image'
1312 testcommand = '/sbin/mdadm --help'
1313 # Build an image to run
1314 bitbake("%s qemu-native qemu-helper-native" % testimage)
1315 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1316 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1317 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1318 # Clean recipe so the first deploy will fail
1319 bitbake("%s -c clean" % testrecipe)
1320 # Try devtool modify
1321 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1322 self.track_for_cleanup(tempdir)
1323 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001324 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001325 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001326 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1327 # Test that deploy-target at this point fails (properly)
1328 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1329 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1330 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1331 result = runCmd('devtool build %s' % testrecipe)
1332 # First try a dry-run of deploy-target
1333 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1334 self.assertIn(' %s' % testfile, result.output)
1335 # Boot the image
1336 with runqemu(testimage) as qemu:
1337 # Now really test deploy-target
1338 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1339 # Run a test command to see if it was installed properly
1340 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1341 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1342 # Check if it deployed all of the files with the right ownership/perms
1343 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1344 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1345 installdir = bb_vars['D']
1346 fakerootenv = bb_vars['FAKEROOTENV']
1347 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001348 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001349 filelist1 = self._process_ls_output(result.output)
1350
1351 # Now look on the target
1352 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1353 self.track_for_cleanup(tempdir2)
1354 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1355 with open(tmpfilelist, 'w') as f:
1356 for line in filelist1:
1357 splitline = line.split()
1358 f.write(splitline[-1] + '\n')
1359 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1360 filelist2 = self._process_ls_output(result.output)
1361 filelist1.sort(key=lambda item: item.split()[-1])
1362 filelist2.sort(key=lambda item: item.split()[-1])
1363 self.assertEqual(filelist1, filelist2)
1364 # Test undeploy-target
1365 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1366 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1367 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1368
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001369 def test_devtool_build_image(self):
1370 """Test devtool build-image plugin"""
1371 # Check preconditions
1372 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1373 image = 'core-image-minimal'
1374 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001375 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001376 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001377 bitbake('%s -c clean' % image)
1378 # Add target and native recipes to workspace
1379 recipes = ['mdadm', 'parted-native']
1380 for recipe in recipes:
1381 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1382 self.track_for_cleanup(tempdir)
1383 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1384 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1385 # Try to build image
1386 result = runCmd('devtool build-image %s' % image)
1387 self.assertNotEqual(result, 0, 'devtool build-image failed')
1388 # Check if image contains expected packages
1389 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1390 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1391 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1392 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1393 for line in f:
1394 splitval = line.split()
1395 if splitval:
1396 pkg = splitval[0]
1397 if pkg in reqpkgs:
1398 reqpkgs.remove(pkg)
1399 if reqpkgs:
1400 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1401
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001402class DevtoolUpgradeTests(DevtoolBase):
1403
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001404 def test_devtool_upgrade(self):
1405 # Check preconditions
1406 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1407 self.track_for_cleanup(self.workspacedir)
1408 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1409 # Check parameters
1410 result = runCmd('devtool upgrade -h')
1411 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1412 self.assertIn(param, result.output)
1413 # For the moment, we are using a real recipe.
1414 recipe = 'devtool-upgrade-test1'
1415 version = '1.6.0'
1416 oldrecipefile = get_bb_var('FILE', recipe)
1417 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1418 self.track_for_cleanup(tempdir)
1419 # Check that recipe is not already under devtool control
1420 result = runCmd('devtool status')
1421 self.assertNotIn(recipe, result.output)
1422 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1423 # we are downgrading instead of upgrading.
1424 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1425 # Check if srctree at least is populated
1426 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1427 # Check new recipe subdirectory is present
1428 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1429 # Check new recipe file is present
1430 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1431 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1432 # Check devtool status and make sure recipe is present
1433 result = runCmd('devtool status')
1434 self.assertIn(recipe, result.output)
1435 self.assertIn(tempdir, result.output)
1436 # Check recipe got changed as expected
1437 with open(oldrecipefile + '.upgraded', 'r') as f:
1438 desiredlines = f.readlines()
1439 with open(newrecipefile, 'r') as f:
1440 newlines = f.readlines()
1441 self.assertEqual(desiredlines, newlines)
1442 # Check devtool reset recipe
1443 result = runCmd('devtool reset %s -n' % recipe)
1444 result = runCmd('devtool status')
1445 self.assertNotIn(recipe, result.output)
1446 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1447
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001448 def test_devtool_upgrade_git(self):
1449 # Check preconditions
1450 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1451 self.track_for_cleanup(self.workspacedir)
1452 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1453 recipe = 'devtool-upgrade-test2'
1454 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1455 oldrecipefile = get_bb_var('FILE', recipe)
1456 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1457 self.track_for_cleanup(tempdir)
1458 # Check that recipe is not already under devtool control
1459 result = runCmd('devtool status')
1460 self.assertNotIn(recipe, result.output)
1461 # Check upgrade
1462 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1463 # Check if srctree at least is populated
1464 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1465 # Check new recipe file is present
1466 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1467 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1468 # Check devtool status and make sure recipe is present
1469 result = runCmd('devtool status')
1470 self.assertIn(recipe, result.output)
1471 self.assertIn(tempdir, result.output)
1472 # Check recipe got changed as expected
1473 with open(oldrecipefile + '.upgraded', 'r') as f:
1474 desiredlines = f.readlines()
1475 with open(newrecipefile, 'r') as f:
1476 newlines = f.readlines()
1477 self.assertEqual(desiredlines, newlines)
1478 # Check devtool reset recipe
1479 result = runCmd('devtool reset %s -n' % recipe)
1480 result = runCmd('devtool status')
1481 self.assertNotIn(recipe, result.output)
1482 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1483
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001484 def test_devtool_layer_plugins(self):
1485 """Test that devtool can use plugins from other layers.
1486
1487 This test executes the selftest-reverse command from meta-selftest."""
1488
1489 self.track_for_cleanup(self.workspacedir)
1490 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1491
1492 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1493 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1494 self.assertEqual(result.output, s[::-1])
1495
1496 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1497 dstdir = basedstdir
1498 self.assertExists(dstdir)
1499 for p in paths:
1500 dstdir = os.path.join(dstdir, p)
1501 if not os.path.exists(dstdir):
1502 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001503 if p == "lib":
1504 # Can race with other tests
1505 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1506 else:
1507 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001508 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1509 if srcfile != dstfile:
1510 shutil.copy(srcfile, dstfile)
1511 self.track_for_cleanup(dstfile)
1512
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001513 def test_devtool_load_plugin(self):
1514 """Test that devtool loads only the first found plugin in BBPATH."""
1515
1516 self.track_for_cleanup(self.workspacedir)
1517 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1518
1519 devtool = runCmd("which devtool")
1520 fromname = runCmd("devtool --quiet pluginfile")
1521 srcfile = fromname.output
1522 bbpath = get_bb_var('BBPATH')
1523 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1524 plugincontent = []
1525 with open(srcfile) as fh:
1526 plugincontent = fh.readlines()
1527 try:
1528 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1529 for path in searchpath:
1530 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1531 result = runCmd("devtool --quiet count")
1532 self.assertEqual(result.output, '1')
1533 result = runCmd("devtool --quiet multiloaded")
1534 self.assertEqual(result.output, "no")
1535 for path in searchpath:
1536 result = runCmd("devtool --quiet bbdir")
1537 self.assertEqual(result.output, path)
1538 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1539 finally:
1540 with open(srcfile, 'w') as fh:
1541 fh.writelines(plugincontent)
1542
1543 def _setup_test_devtool_finish_upgrade(self):
1544 # Check preconditions
1545 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1546 self.track_for_cleanup(self.workspacedir)
1547 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1548 # Use a "real" recipe from meta-selftest
1549 recipe = 'devtool-upgrade-test1'
1550 oldversion = '1.5.3'
1551 newversion = '1.6.0'
1552 oldrecipefile = get_bb_var('FILE', recipe)
1553 recipedir = os.path.dirname(oldrecipefile)
1554 result = runCmd('git status --porcelain .', cwd=recipedir)
1555 if result.output.strip():
1556 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1557 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1558 self.track_for_cleanup(tempdir)
1559 # Check that recipe is not already under devtool control
1560 result = runCmd('devtool status')
1561 self.assertNotIn(recipe, result.output)
1562 # Do the upgrade
1563 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1564 # Check devtool status and make sure recipe is present
1565 result = runCmd('devtool status')
1566 self.assertIn(recipe, result.output)
1567 self.assertIn(tempdir, result.output)
1568 # Make a change to the source
1569 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1570 result = runCmd('git status --porcelain', cwd=tempdir)
1571 self.assertIn('M src/pv/number.c', result.output)
1572 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1573 # Check if patch is there
1574 recipedir = os.path.dirname(oldrecipefile)
1575 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1576 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001577 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001578 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001579 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1580 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001581
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001582 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001583 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001584 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1585 self.assertIn('/meta-selftest/', recipedir)
1586 # Try finish to the original layer
1587 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1588 result = runCmd('devtool finish %s meta-selftest' % recipe)
1589 result = runCmd('devtool status')
1590 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1591 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1592 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1593 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001594 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 -05001595 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1596 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1597 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1598 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 -05001599 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 -05001600 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 -05001601 with open(newrecipefile, 'r') as f:
1602 newcontent = f.read()
1603 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1604 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1605 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1606 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1607
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001608
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001609 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001610 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001611 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1612 self.assertIn('/meta-selftest/', recipedir)
1613 # Try finish to a different layer - should create a bbappend
1614 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1615 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1616 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1617 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1618 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1619 self.track_for_cleanup(newrecipedir)
1620 result = runCmd('devtool finish %s oe-core' % recipe)
1621 result = runCmd('devtool status')
1622 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1623 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1624 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1625 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001626 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001627 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1628 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1629 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 -05001630 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 -05001631 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 -05001632 with open(newrecipefile, 'r') as f:
1633 newcontent = f.read()
1634 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1635 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1636 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1637 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 -05001638
1639 def _setup_test_devtool_finish_modify(self):
1640 # Check preconditions
1641 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1642 # Try modifying a recipe
1643 self.track_for_cleanup(self.workspacedir)
1644 recipe = 'mdadm'
1645 oldrecipefile = get_bb_var('FILE', recipe)
1646 recipedir = os.path.dirname(oldrecipefile)
1647 result = runCmd('git status --porcelain .', cwd=recipedir)
1648 if result.output.strip():
1649 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1650 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1651 self.track_for_cleanup(tempdir)
1652 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1653 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1654 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1655 # Test devtool status
1656 result = runCmd('devtool status')
1657 self.assertIn(recipe, result.output)
1658 self.assertIn(tempdir, result.output)
1659 # Make a change to the source
1660 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1661 result = runCmd('git status --porcelain', cwd=tempdir)
1662 self.assertIn('M maps.c', result.output)
1663 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1664 for entry in os.listdir(recipedir):
1665 filesdir = os.path.join(recipedir, entry)
1666 if os.path.isdir(filesdir):
1667 break
1668 else:
1669 self.fail('Unable to find recipe files directory for %s' % recipe)
1670 return recipe, oldrecipefile, recipedir, filesdir
1671
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001672 def test_devtool_finish_modify_origlayer(self):
1673 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1674 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1675 self.assertIn('/meta/', recipedir)
1676 # Try finish to the original layer
1677 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1678 result = runCmd('devtool finish %s meta' % recipe)
1679 result = runCmd('devtool status')
1680 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1681 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1682 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1683 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1684 self._check_repo_status(recipedir, expected_status)
1685
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001686 def test_devtool_finish_modify_otherlayer(self):
1687 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1688 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1689 self.assertIn('/meta/', recipedir)
1690 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1691 appenddir = os.path.join(get_test_layer(), relpth)
1692 self.track_for_cleanup(appenddir)
1693 # Try finish to the original layer
1694 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1695 result = runCmd('devtool finish %s meta-selftest' % recipe)
1696 result = runCmd('devtool status')
1697 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1698 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1699 result = runCmd('git status --porcelain .', cwd=recipedir)
1700 if result.output.strip():
1701 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1702 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1703 recipefn = recipefn.split('_')[0] + '_%'
1704 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1705 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1706 newdir = os.path.join(appenddir, recipe)
1707 files = os.listdir(newdir)
1708 foundpatch = None
1709 for fn in files:
1710 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1711 foundpatch = fn
1712 if not foundpatch:
1713 self.fail('No patch file created next to bbappend')
1714 files.remove(foundpatch)
1715 if files:
1716 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1717
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001718 def test_devtool_rename(self):
1719 # Check preconditions
1720 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1721 self.track_for_cleanup(self.workspacedir)
1722 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1723
1724 # First run devtool add
1725 # We already have this recipe in OE-Core, but that doesn't matter
1726 recipename = 'i2c-tools'
1727 recipever = '3.1.2'
1728 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1729 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1730 def add_recipe():
1731 result = runCmd('devtool add %s' % url)
1732 self.assertExists(recipefile, 'Expected recipe file not created')
1733 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1734 checkvars = {}
1735 checkvars['S'] = None
1736 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1737 self._test_recipe_contents(recipefile, checkvars, [])
1738 add_recipe()
1739 # Now rename it - change both name and version
1740 newrecipename = 'mynewrecipe'
1741 newrecipever = '456'
1742 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1743 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1744 self.assertExists(newrecipefile, 'Recipe file not renamed')
1745 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1746 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1747 self.assertExists(newsrctree, 'Source directory not renamed')
1748 checkvars = {}
1749 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1750 checkvars['SRC_URI'] = url
1751 self._test_recipe_contents(newrecipefile, checkvars, [])
1752 # Try again - change just name this time
1753 result = runCmd('devtool reset -n %s' % newrecipename)
1754 shutil.rmtree(newsrctree)
1755 add_recipe()
1756 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1757 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1758 self.assertExists(newrecipefile, 'Recipe file not renamed')
1759 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1760 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1761 checkvars = {}
1762 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1763 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1764 self._test_recipe_contents(newrecipefile, checkvars, [])
1765 # Try again - change just version this time
1766 result = runCmd('devtool reset -n %s' % newrecipename)
1767 shutil.rmtree(newsrctree)
1768 add_recipe()
1769 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1770 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1771 self.assertExists(newrecipefile, 'Recipe file not renamed')
1772 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1773 checkvars = {}
1774 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1775 checkvars['SRC_URI'] = url
1776 self._test_recipe_contents(newrecipefile, checkvars, [])
1777
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001778 def test_devtool_virtual_kernel_modify(self):
1779 """
1780 Summary: The purpose of this test case is to verify that
1781 devtool modify works correctly when building
1782 the kernel.
1783 Dependencies: NA
1784 Steps: 1. Build kernel with bitbake.
1785 2. Save the config file generated.
1786 3. Clean the environment.
1787 4. Use `devtool modify virtual/kernel` to validate following:
1788 4.1 The source is checked out correctly.
1789 4.2 The resulting configuration is the same as
1790 what was get on step 2.
1791 4.3 The Kernel can be build correctly.
1792 4.4 Changes made on the source are reflected on the
1793 subsequent builds.
1794 4.5 Changes on the configuration are reflected on the
1795 subsequent builds
1796 Expected: devtool modify is able to checkout the source of the kernel
1797 and modification to the source and configurations are reflected
1798 when building the kernel.
1799 """
1800 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001801 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001802 bitbake('%s -c clean' % kernel_provider)
1803 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1804 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1805 self.track_for_cleanup(tempdir)
1806 self.track_for_cleanup(tempdir_cfg)
1807 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001808 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001809 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001810 #Step 1
1811 #Here is just generated the config file instead of all the kernel to optimize the
1812 #time of executing this test case.
1813 bitbake('%s -c configure' % kernel_provider)
1814 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1815 #Step 2
1816 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1817 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1818
1819 tmpconfig = os.path.join(tempdir_cfg, '.config')
1820 #Step 3
1821 bitbake('%s -c clean' % kernel_provider)
1822 #Step 4.1
1823 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1824 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1825 #Step 4.2
1826 configfile = os.path.join(tempdir,'.config')
1827 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1828 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1829 #Step 4.3
1830 #NOTE: virtual/kernel is mapped to kernel_provider
1831 result = runCmd('devtool build %s' % kernel_provider)
1832 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1833 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1834 self.assertExists(kernelfile, 'Kernel was not build correctly')
1835
1836 #Modify the kernel source
1837 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1838 modstring = "Use a boot loader. Devtool testing."
1839 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1840 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1841 #Modify the configuration
1842 codeconfigfile = os.path.join(tempdir,'.config.new')
1843 modconfopt = "CONFIG_SG_POOL=n"
1844 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1845 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1846 #Build again kernel with devtool
1847 rebuild = runCmd('devtool build %s' % kernel_provider)
1848 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1849 #Step 4.4
1850 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1851 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1852 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1853 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1854 #Step 4.5
1855 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1856 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')