blob: 5886862d6c45a31c4e9d358a9ff42d93199c615b [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
679 testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
680 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
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001111 def test_devtool_update_recipe_local_files_3(self):
1112 # First, modify the recipe
1113 testrecipe = 'devtool-test-localonly'
1114 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1115 recipefile = bb_vars['FILE']
1116 src_uri = bb_vars['SRC_URI']
1117 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1118 self.track_for_cleanup(tempdir)
1119 self.track_for_cleanup(self.workspacedir)
1120 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1121 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1122 result = runCmd('devtool modify %s' % testrecipe)
1123 # Modify one file
1124 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1125 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1126 result = runCmd('devtool update-recipe %s' % testrecipe)
1127 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1128 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1129
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001130 def test_devtool_update_recipe_local_patch_gz(self):
1131 # First, modify the recipe
1132 testrecipe = 'devtool-test-patch-gz'
1133 if get_bb_var('DISTRO') == 'poky-tiny':
1134 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1135 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1136 recipefile = bb_vars['FILE']
1137 src_uri = bb_vars['SRC_URI']
1138 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1139 self.track_for_cleanup(tempdir)
1140 self.track_for_cleanup(self.workspacedir)
1141 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1142 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1143 result = runCmd('devtool modify %s' % testrecipe)
1144 # Modify one file
1145 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1146 runCmd('echo "Another line" >> README', cwd=srctree)
1147 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1148 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1149 result = runCmd('devtool update-recipe %s' % testrecipe)
1150 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1151 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1152 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1153 result = runCmd('file %s' % patch_gz)
1154 if 'gzip compressed data' not in result.output:
1155 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1156
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001157 def test_devtool_update_recipe_local_files_subdir(self):
1158 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1159 # SRC_URI such that it overwrites a file that was in an archive that
1160 # was also in SRC_URI
1161 # First, modify the recipe
1162 testrecipe = 'devtool-test-subdir'
1163 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1164 recipefile = bb_vars['FILE']
1165 src_uri = bb_vars['SRC_URI']
1166 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1167 self.track_for_cleanup(tempdir)
1168 self.track_for_cleanup(self.workspacedir)
1169 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1170 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1171 result = runCmd('devtool modify %s' % testrecipe)
1172 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1173 self.assertExists(testfile, 'Extracted source could not be found')
1174 with open(testfile, 'r') as f:
1175 contents = f.read().rstrip()
1176 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1177 # Test devtool update-recipe without modifying any 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 = []
1181 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1182
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001183class DevtoolExtractTests(DevtoolBase):
1184
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001185 def test_devtool_extract(self):
1186 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1187 # Try devtool extract
1188 self.track_for_cleanup(tempdir)
1189 self.track_for_cleanup(self.workspacedir)
1190 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1191 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1192 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1193 self._check_src_repo(tempdir)
1194
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001195 def test_devtool_extract_virtual(self):
1196 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1197 # Try devtool extract
1198 self.track_for_cleanup(tempdir)
1199 self.track_for_cleanup(self.workspacedir)
1200 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1201 result = runCmd('devtool extract virtual/make %s' % tempdir)
1202 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1203 self._check_src_repo(tempdir)
1204
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001205 def test_devtool_reset_all(self):
1206 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1207 self.track_for_cleanup(tempdir)
1208 self.track_for_cleanup(self.workspacedir)
1209 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1210 testrecipe1 = 'mdadm'
1211 testrecipe2 = 'cronie'
1212 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1213 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1214 result = runCmd('devtool build %s' % testrecipe1)
1215 result = runCmd('devtool build %s' % testrecipe2)
1216 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1217 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1218 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1219 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1220 result = runCmd('devtool reset -a')
1221 self.assertIn(testrecipe1, result.output)
1222 self.assertIn(testrecipe2, result.output)
1223 result = runCmd('devtool status')
1224 self.assertNotIn(testrecipe1, result.output)
1225 self.assertNotIn(testrecipe2, result.output)
1226 matches1 = glob.glob(stampprefix1 + '*')
1227 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1228 matches2 = glob.glob(stampprefix2 + '*')
1229 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1230
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001231 def test_devtool_deploy_target(self):
1232 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1233 # unfortunately the runtime tests run under bitbake and you can't run
1234 # devtool within bitbake (since devtool needs to run bitbake itself).
1235 # Additionally we are testing build-time functionality as well, so
1236 # really this has to be done as an oe-selftest test.
1237 #
1238 # Check preconditions
1239 machine = get_bb_var('MACHINE')
1240 if not machine.startswith('qemu'):
1241 self.skipTest('This test only works with qemu machines')
1242 if not os.path.exists('/etc/runqemu-nosudo'):
1243 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1244 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1245 if result.status != 0:
1246 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1247 if result.status != 0:
1248 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1249 for line in result.output.splitlines():
1250 if line.startswith('tap'):
1251 break
1252 else:
1253 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1254 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1255 # Definitions
1256 testrecipe = 'mdadm'
1257 testfile = '/sbin/mdadm'
1258 testimage = 'oe-selftest-image'
1259 testcommand = '/sbin/mdadm --help'
1260 # Build an image to run
1261 bitbake("%s qemu-native qemu-helper-native" % testimage)
1262 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1263 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1264 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1265 # Clean recipe so the first deploy will fail
1266 bitbake("%s -c clean" % testrecipe)
1267 # Try devtool modify
1268 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1269 self.track_for_cleanup(tempdir)
1270 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001271 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001272 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001273 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1274 # Test that deploy-target at this point fails (properly)
1275 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1276 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1277 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1278 result = runCmd('devtool build %s' % testrecipe)
1279 # First try a dry-run of deploy-target
1280 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1281 self.assertIn(' %s' % testfile, result.output)
1282 # Boot the image
1283 with runqemu(testimage) as qemu:
1284 # Now really test deploy-target
1285 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1286 # Run a test command to see if it was installed properly
1287 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1288 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1289 # Check if it deployed all of the files with the right ownership/perms
1290 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1291 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1292 installdir = bb_vars['D']
1293 fakerootenv = bb_vars['FAKEROOTENV']
1294 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001295 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001296 filelist1 = self._process_ls_output(result.output)
1297
1298 # Now look on the target
1299 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1300 self.track_for_cleanup(tempdir2)
1301 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1302 with open(tmpfilelist, 'w') as f:
1303 for line in filelist1:
1304 splitline = line.split()
1305 f.write(splitline[-1] + '\n')
1306 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1307 filelist2 = self._process_ls_output(result.output)
1308 filelist1.sort(key=lambda item: item.split()[-1])
1309 filelist2.sort(key=lambda item: item.split()[-1])
1310 self.assertEqual(filelist1, filelist2)
1311 # Test undeploy-target
1312 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1313 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1314 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1315
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001316 def test_devtool_build_image(self):
1317 """Test devtool build-image plugin"""
1318 # Check preconditions
1319 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1320 image = 'core-image-minimal'
1321 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001322 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001323 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001324 bitbake('%s -c clean' % image)
1325 # Add target and native recipes to workspace
1326 recipes = ['mdadm', 'parted-native']
1327 for recipe in recipes:
1328 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1329 self.track_for_cleanup(tempdir)
1330 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1331 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1332 # Try to build image
1333 result = runCmd('devtool build-image %s' % image)
1334 self.assertNotEqual(result, 0, 'devtool build-image failed')
1335 # Check if image contains expected packages
1336 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1337 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1338 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1339 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1340 for line in f:
1341 splitval = line.split()
1342 if splitval:
1343 pkg = splitval[0]
1344 if pkg in reqpkgs:
1345 reqpkgs.remove(pkg)
1346 if reqpkgs:
1347 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1348
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001349class DevtoolUpgradeTests(DevtoolBase):
1350
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001351 def test_devtool_upgrade(self):
1352 # Check preconditions
1353 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1354 self.track_for_cleanup(self.workspacedir)
1355 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1356 # Check parameters
1357 result = runCmd('devtool upgrade -h')
1358 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1359 self.assertIn(param, result.output)
1360 # For the moment, we are using a real recipe.
1361 recipe = 'devtool-upgrade-test1'
1362 version = '1.6.0'
1363 oldrecipefile = get_bb_var('FILE', recipe)
1364 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1365 self.track_for_cleanup(tempdir)
1366 # Check that recipe is not already under devtool control
1367 result = runCmd('devtool status')
1368 self.assertNotIn(recipe, result.output)
1369 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1370 # we are downgrading instead of upgrading.
1371 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1372 # Check if srctree at least is populated
1373 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1374 # Check new recipe subdirectory is present
1375 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1376 # Check new recipe file is present
1377 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1378 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1379 # Check devtool status and make sure recipe is present
1380 result = runCmd('devtool status')
1381 self.assertIn(recipe, result.output)
1382 self.assertIn(tempdir, result.output)
1383 # Check recipe got changed as expected
1384 with open(oldrecipefile + '.upgraded', 'r') as f:
1385 desiredlines = f.readlines()
1386 with open(newrecipefile, 'r') as f:
1387 newlines = f.readlines()
1388 self.assertEqual(desiredlines, newlines)
1389 # Check devtool reset recipe
1390 result = runCmd('devtool reset %s -n' % recipe)
1391 result = runCmd('devtool status')
1392 self.assertNotIn(recipe, result.output)
1393 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1394
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001395 def test_devtool_upgrade_git(self):
1396 # Check preconditions
1397 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1398 self.track_for_cleanup(self.workspacedir)
1399 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1400 recipe = 'devtool-upgrade-test2'
1401 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1402 oldrecipefile = get_bb_var('FILE', recipe)
1403 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1404 self.track_for_cleanup(tempdir)
1405 # Check that recipe is not already under devtool control
1406 result = runCmd('devtool status')
1407 self.assertNotIn(recipe, result.output)
1408 # Check upgrade
1409 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1410 # Check if srctree at least is populated
1411 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1412 # Check new recipe file is present
1413 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1414 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1415 # Check devtool status and make sure recipe is present
1416 result = runCmd('devtool status')
1417 self.assertIn(recipe, result.output)
1418 self.assertIn(tempdir, result.output)
1419 # Check recipe got changed as expected
1420 with open(oldrecipefile + '.upgraded', 'r') as f:
1421 desiredlines = f.readlines()
1422 with open(newrecipefile, 'r') as f:
1423 newlines = f.readlines()
1424 self.assertEqual(desiredlines, newlines)
1425 # Check devtool reset recipe
1426 result = runCmd('devtool reset %s -n' % recipe)
1427 result = runCmd('devtool status')
1428 self.assertNotIn(recipe, result.output)
1429 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1430
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001431 def test_devtool_layer_plugins(self):
1432 """Test that devtool can use plugins from other layers.
1433
1434 This test executes the selftest-reverse command from meta-selftest."""
1435
1436 self.track_for_cleanup(self.workspacedir)
1437 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1438
1439 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1440 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1441 self.assertEqual(result.output, s[::-1])
1442
1443 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1444 dstdir = basedstdir
1445 self.assertExists(dstdir)
1446 for p in paths:
1447 dstdir = os.path.join(dstdir, p)
1448 if not os.path.exists(dstdir):
1449 os.makedirs(dstdir)
1450 self.track_for_cleanup(dstdir)
1451 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1452 if srcfile != dstfile:
1453 shutil.copy(srcfile, dstfile)
1454 self.track_for_cleanup(dstfile)
1455
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001456 def test_devtool_load_plugin(self):
1457 """Test that devtool loads only the first found plugin in BBPATH."""
1458
1459 self.track_for_cleanup(self.workspacedir)
1460 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1461
1462 devtool = runCmd("which devtool")
1463 fromname = runCmd("devtool --quiet pluginfile")
1464 srcfile = fromname.output
1465 bbpath = get_bb_var('BBPATH')
1466 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1467 plugincontent = []
1468 with open(srcfile) as fh:
1469 plugincontent = fh.readlines()
1470 try:
1471 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1472 for path in searchpath:
1473 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1474 result = runCmd("devtool --quiet count")
1475 self.assertEqual(result.output, '1')
1476 result = runCmd("devtool --quiet multiloaded")
1477 self.assertEqual(result.output, "no")
1478 for path in searchpath:
1479 result = runCmd("devtool --quiet bbdir")
1480 self.assertEqual(result.output, path)
1481 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1482 finally:
1483 with open(srcfile, 'w') as fh:
1484 fh.writelines(plugincontent)
1485
1486 def _setup_test_devtool_finish_upgrade(self):
1487 # Check preconditions
1488 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1489 self.track_for_cleanup(self.workspacedir)
1490 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1491 # Use a "real" recipe from meta-selftest
1492 recipe = 'devtool-upgrade-test1'
1493 oldversion = '1.5.3'
1494 newversion = '1.6.0'
1495 oldrecipefile = get_bb_var('FILE', recipe)
1496 recipedir = os.path.dirname(oldrecipefile)
1497 result = runCmd('git status --porcelain .', cwd=recipedir)
1498 if result.output.strip():
1499 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1500 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1501 self.track_for_cleanup(tempdir)
1502 # Check that recipe is not already under devtool control
1503 result = runCmd('devtool status')
1504 self.assertNotIn(recipe, result.output)
1505 # Do the upgrade
1506 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1507 # Check devtool status and make sure recipe is present
1508 result = runCmd('devtool status')
1509 self.assertIn(recipe, result.output)
1510 self.assertIn(tempdir, result.output)
1511 # Make a change to the source
1512 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1513 result = runCmd('git status --porcelain', cwd=tempdir)
1514 self.assertIn('M src/pv/number.c', result.output)
1515 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1516 # Check if patch is there
1517 recipedir = os.path.dirname(oldrecipefile)
1518 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1519 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001520 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001521 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001522 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1523 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001524
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001525 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001526 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001527 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1528 self.assertIn('/meta-selftest/', recipedir)
1529 # Try finish to the original layer
1530 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1531 result = runCmd('devtool finish %s meta-selftest' % recipe)
1532 result = runCmd('devtool status')
1533 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1534 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1535 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1536 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001537 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 -05001538 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1539 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1540 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1541 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 -05001542 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 -05001543 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 -05001544 with open(newrecipefile, 'r') as f:
1545 newcontent = f.read()
1546 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1547 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1548 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1549 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1550
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001551
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001552 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001553 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001554 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1555 self.assertIn('/meta-selftest/', recipedir)
1556 # Try finish to a different layer - should create a bbappend
1557 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1558 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1559 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1560 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1561 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1562 self.track_for_cleanup(newrecipedir)
1563 result = runCmd('devtool finish %s oe-core' % recipe)
1564 result = runCmd('devtool status')
1565 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1566 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1567 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1568 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001569 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001570 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1571 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1572 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 -05001573 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 -05001574 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 -05001575 with open(newrecipefile, 'r') as f:
1576 newcontent = f.read()
1577 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1578 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1579 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1580 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 -05001581
1582 def _setup_test_devtool_finish_modify(self):
1583 # Check preconditions
1584 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1585 # Try modifying a recipe
1586 self.track_for_cleanup(self.workspacedir)
1587 recipe = 'mdadm'
1588 oldrecipefile = get_bb_var('FILE', recipe)
1589 recipedir = os.path.dirname(oldrecipefile)
1590 result = runCmd('git status --porcelain .', cwd=recipedir)
1591 if result.output.strip():
1592 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1593 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1594 self.track_for_cleanup(tempdir)
1595 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1596 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1597 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1598 # Test devtool status
1599 result = runCmd('devtool status')
1600 self.assertIn(recipe, result.output)
1601 self.assertIn(tempdir, result.output)
1602 # Make a change to the source
1603 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1604 result = runCmd('git status --porcelain', cwd=tempdir)
1605 self.assertIn('M maps.c', result.output)
1606 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1607 for entry in os.listdir(recipedir):
1608 filesdir = os.path.join(recipedir, entry)
1609 if os.path.isdir(filesdir):
1610 break
1611 else:
1612 self.fail('Unable to find recipe files directory for %s' % recipe)
1613 return recipe, oldrecipefile, recipedir, filesdir
1614
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001615 def test_devtool_finish_modify_origlayer(self):
1616 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1617 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1618 self.assertIn('/meta/', recipedir)
1619 # Try finish to the original layer
1620 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1621 result = runCmd('devtool finish %s meta' % recipe)
1622 result = runCmd('devtool status')
1623 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1624 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1625 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1626 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1627 self._check_repo_status(recipedir, expected_status)
1628
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001629 def test_devtool_finish_modify_otherlayer(self):
1630 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1631 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1632 self.assertIn('/meta/', recipedir)
1633 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1634 appenddir = os.path.join(get_test_layer(), relpth)
1635 self.track_for_cleanup(appenddir)
1636 # Try finish to the original layer
1637 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1638 result = runCmd('devtool finish %s meta-selftest' % recipe)
1639 result = runCmd('devtool status')
1640 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1641 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1642 result = runCmd('git status --porcelain .', cwd=recipedir)
1643 if result.output.strip():
1644 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1645 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1646 recipefn = recipefn.split('_')[0] + '_%'
1647 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1648 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1649 newdir = os.path.join(appenddir, recipe)
1650 files = os.listdir(newdir)
1651 foundpatch = None
1652 for fn in files:
1653 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1654 foundpatch = fn
1655 if not foundpatch:
1656 self.fail('No patch file created next to bbappend')
1657 files.remove(foundpatch)
1658 if files:
1659 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1660
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001661 def test_devtool_rename(self):
1662 # Check preconditions
1663 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1664 self.track_for_cleanup(self.workspacedir)
1665 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1666
1667 # First run devtool add
1668 # We already have this recipe in OE-Core, but that doesn't matter
1669 recipename = 'i2c-tools'
1670 recipever = '3.1.2'
1671 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1672 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1673 def add_recipe():
1674 result = runCmd('devtool add %s' % url)
1675 self.assertExists(recipefile, 'Expected recipe file not created')
1676 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1677 checkvars = {}
1678 checkvars['S'] = None
1679 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1680 self._test_recipe_contents(recipefile, checkvars, [])
1681 add_recipe()
1682 # Now rename it - change both name and version
1683 newrecipename = 'mynewrecipe'
1684 newrecipever = '456'
1685 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1686 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1687 self.assertExists(newrecipefile, 'Recipe file not renamed')
1688 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1689 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1690 self.assertExists(newsrctree, 'Source directory not renamed')
1691 checkvars = {}
1692 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1693 checkvars['SRC_URI'] = url
1694 self._test_recipe_contents(newrecipefile, checkvars, [])
1695 # Try again - change just name this time
1696 result = runCmd('devtool reset -n %s' % newrecipename)
1697 shutil.rmtree(newsrctree)
1698 add_recipe()
1699 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1700 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1701 self.assertExists(newrecipefile, 'Recipe file not renamed')
1702 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1703 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1704 checkvars = {}
1705 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1706 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1707 self._test_recipe_contents(newrecipefile, checkvars, [])
1708 # Try again - change just version this time
1709 result = runCmd('devtool reset -n %s' % newrecipename)
1710 shutil.rmtree(newsrctree)
1711 add_recipe()
1712 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1713 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1714 self.assertExists(newrecipefile, 'Recipe file not renamed')
1715 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1716 checkvars = {}
1717 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1718 checkvars['SRC_URI'] = url
1719 self._test_recipe_contents(newrecipefile, checkvars, [])
1720
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001721 def test_devtool_virtual_kernel_modify(self):
1722 """
1723 Summary: The purpose of this test case is to verify that
1724 devtool modify works correctly when building
1725 the kernel.
1726 Dependencies: NA
1727 Steps: 1. Build kernel with bitbake.
1728 2. Save the config file generated.
1729 3. Clean the environment.
1730 4. Use `devtool modify virtual/kernel` to validate following:
1731 4.1 The source is checked out correctly.
1732 4.2 The resulting configuration is the same as
1733 what was get on step 2.
1734 4.3 The Kernel can be build correctly.
1735 4.4 Changes made on the source are reflected on the
1736 subsequent builds.
1737 4.5 Changes on the configuration are reflected on the
1738 subsequent builds
1739 Expected: devtool modify is able to checkout the source of the kernel
1740 and modification to the source and configurations are reflected
1741 when building the kernel.
1742 """
1743 kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001744 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001745 bitbake('%s -c clean' % kernel_provider)
1746 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1747 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1748 self.track_for_cleanup(tempdir)
1749 self.track_for_cleanup(tempdir_cfg)
1750 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001751 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001752 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001753 #Step 1
1754 #Here is just generated the config file instead of all the kernel to optimize the
1755 #time of executing this test case.
1756 bitbake('%s -c configure' % kernel_provider)
1757 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1758 #Step 2
1759 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1760 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1761
1762 tmpconfig = os.path.join(tempdir_cfg, '.config')
1763 #Step 3
1764 bitbake('%s -c clean' % kernel_provider)
1765 #Step 4.1
1766 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1767 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1768 #Step 4.2
1769 configfile = os.path.join(tempdir,'.config')
1770 diff = runCmd('diff %s %s' % (tmpconfig, configfile))
1771 self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
1772 #Step 4.3
1773 #NOTE: virtual/kernel is mapped to kernel_provider
1774 result = runCmd('devtool build %s' % kernel_provider)
1775 self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
1776 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
1777 self.assertExists(kernelfile, 'Kernel was not build correctly')
1778
1779 #Modify the kernel source
1780 modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
1781 modstring = "Use a boot loader. Devtool testing."
1782 modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
1783 self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
1784 #Modify the configuration
1785 codeconfigfile = os.path.join(tempdir,'.config.new')
1786 modconfopt = "CONFIG_SG_POOL=n"
1787 modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
1788 self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
1789 #Build again kernel with devtool
1790 rebuild = runCmd('devtool build %s' % kernel_provider)
1791 self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
1792 #Step 4.4
1793 bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
1794 bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
1795 checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
1796 self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
1797 #Step 4.5
1798 checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
1799 self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')